[BACK]Return to icacheviewer.C CVS log [TXT][DIR] Up to [Development] / performer / src / lib / libpfutil

File: [Development] / performer / src / lib / libpfutil / icacheviewer.C (download)

Revision 1.1, Tue Nov 21 21:39:36 2000 UTC (16 years, 10 months ago) by flynnt
Branch: MAIN
CVS Tags: HEAD

Initial check-in based on OpenGL Performer 2.4 tree.
-flynnt

/*
 * Copyright 2000, Silicon Graphics, Inc.
 * ALL RIGHTS RESERVED
 *
 * This source code ("Source Code") was originally derived from a
 * code base owned by Silicon Graphics, Inc. ("SGI")
 * 
 * LICENSE: SGI grants the user ("Licensee") permission to reproduce,
 * distribute, and create derivative works from this Source Code,
 * provided that: (1) the user reproduces this entire notice within
 * both source and binary format redistributions and any accompanying
 * materials such as documentation in printed or electronic format;
 * (2) the Source Code is not to be used, or ported or modified for
 * use, except in conjunction with OpenGL Performer; and (3) the
 * names of Silicon Graphics, Inc.  and SGI may not be used in any
 * advertising or publicity relating to the Source Code without the
 * prior written permission of SGI.  No further license or permission
 * may be inferred or deemed or construed to exist with regard to the
 * Source Code or the code base of which it forms a part. All rights
 * not expressly granted are reserved.
 * 
 * This Source Code is provided to Licensee AS IS, without any
 * warranty of any kind, either express, implied, or statutory,
 * including, but not limited to, any warranty that the Source Code
 * will conform to specifications, any implied warranties of
 * merchantability, fitness for a particular purpose, and freedom
 * from infringement, and any warranty that the documentation will
 * conform to the program, or any warranty that the Source Code will
 * be error free.
 * 
 * IN NO EVENT WILL SGI BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT
 * LIMITED TO DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES,
 * ARISING OUT OF, RESULTING FROM, OR IN ANY WAY CONNECTED WITH THE
 * SOURCE CODE, WHETHER OR NOT BASED UPON WARRANTY, CONTRACT, TORT OR
 * OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM,
 * OR AROSE OUT OF USE OR RESULTS FROM USE OF, OR LACK OF ABILITY TO
 * USE, THE SOURCE CODE.
 * 
 * Contact information:  Silicon Graphics, Inc., 
 * 1600 Amphitheatre Pkwy, Mountain View, CA  94043, 
 * or:  http://www.sgi.com
 */

#include <Performer/pr/pfImageCache.h>
#include <Performer/pr/pfClipTexture.h>
#include <Performer/pr/pfObject.h>
#include <Performer/pr/pfGeoSet.h>
#include <Performer/pfutil.h>
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include <stdlib.h>

#define FOR(i,n) for ((i) = 0; (i) < (n); ++(i))
#define INRANGE(foo,bar,baz) ((foo(bar))&&((bar)baz))
#define log2(x) (log(x)*M_LOG2E)
#define round(x) floor((x)+.5)

#define MAXLEVELS 32


static void
hsv_to_rgb(float h, float s, float v, float *R, float *G, float *B)
{
    int segment;
    float *rgb[3], major, minor, middle, frac;

    rgb[0] = R;
    rgb[1] = G;
    rgb[2] = B;

    while (h < 0)
        h++;
    while (h >= 1)
        h--;

    segment = (int)(h*6);

    frac = (6*h)-segment;
    if (segment % 2)
        frac = 1 - frac;

    major = v;
    minor = (1-s)*v;
    middle = frac * major + (1-frac) * minor;

    *rgb[(segment+1)/2 % 3] = major;
    *rgb[(segment+4)/2 % 3] = minor;
    *rgb[(7-segment) % 3] = middle;
}


class pfImageCacheViewer : public pfObject
{
public:
    pfImageCacheViewer()
    {
	tileShrink = .5;
	coordMap = NULL;
	coordMapArg = NULL;
	freeCoordMapArg = NULL;

	geostate = new(getArena()) pfGeoState;
	assert(geostate != NULL);
	geostate->setMode(PFSTATE_ENTEXTURE, PF_ON);

	int level;
	FOR (level, MAXLEVELS)
	{
	    geosets[level] = new(getArena()) pfGeoSet;
	    assert(geosets[level] != NULL);
	    pfRef(geosets[level]);
	    /* geosets[level]->setGState(geostate); */

	    nquads[level] = 0;
	    geosets[level]->setNumPrims(nquads[level]);
	    geosets[level]->setPrimType(PFGS_QUADS);
	    nquads_alloced[level] = 0;
	}
    }
    ~pfImageCacheViewer()
    {
	int level;
	setCoordMap(NULL,NULL,NULL);
	FOR (level, MAXLEVELS)
	{
	    set_nquads_alloced(level, 0);
	    assert(pfGetRef(geosets[level]) == 1);
	    pfMemory::unrefDelete(geosets[level]);
	}
    }
    void setTileShrink(float newTileShrink)
    {
	tileShrink = newTileShrink;
    }
    void setCoordMap(void (*newCoordMap)(double,double,double*,double*,void*),
		     void *newCoordMapArg,
		     void (*newFreeCoordMapArg)(void*))
    {
	if (freeCoordMapArg != NULL)
	    (*freeCoordMapArg)(coordMapArg);
	coordMap = newCoordMap;
	coordMapArg = newCoordMapArg;
	freeCoordMapArg = newFreeCoordMapArg;
    }

    void updateLevelFromImageCache(int level, pfImageCache *icache)
    {
	if (icache == NULL)
	{
	    nquads[level] = 0;
	    geosets[level]->setNumPrims(nquads[level]);
	    return;
	}

	int orgS, orgT, orgR; /* origin of icache, in tiles from ll of image */
	int nTilesS, nTilesT, nTilesR;
	int s, t, r; /* in tiles */
	int tileWidth, tileHeight, tileDepth;
	int imageWidth, imageHeight, imageDepth;
	icache->getMemRegionOrg(&orgS, &orgT, &orgR);
	icache->getMemRegionSize(&nTilesS, &nTilesT, &nTilesR);
	icache->getImageSize(&imageWidth, &imageHeight, &imageDepth);
	pfImageTile *itile = icache->getProtoTile();
	itile->getSize(&tileWidth, &tileHeight, &tileDepth);
	float logimageWidth = log2(imageWidth);

	if (nTilesS*nTilesT*nTilesR > nquads_alloced[level])
	    set_nquads_alloced(level, nTilesS*nTilesT*nTilesR);
	
	nquads[level] = 0;
	float z = level / 1000.;

	FOR (r, nTilesR)
	FOR (t, nTilesT)
	FOR (s, nTilesS)
	{
	    itile = icache->getTile(orgS+s, orgT+t, orgR+r);
	    int loading, valid, useDefault;
	    if (!(loading = itile->isLoading()))
		if (!(valid = itile->isValid()))
		    useDefault = itile->getDefaultTileMode();

	    double center[2];
	    int tileOriginS, tileOriginT, tileOriginR;
	    itile->getOrigin(&tileOriginS,&tileOriginT,&tileOriginR);
	    PFSET_VEC2(center, (tileOriginS+.5*tileWidth)/imageWidth,
			       (tileOriginT+.5*tileHeight)/imageHeight);
	    double vradiusS = tileShrink*(.5*tileWidth)/imageWidth;
	    double vradiusT = tileShrink*(.5*tileHeight)/imageHeight;
	    double tradiusS = (.5*tileWidth)/imageWidth;
	    double tradiusT = (.5*tileHeight)/imageHeight;
	    double double_vc[4][2];
	    double double_tc[4][2];
	    PFSET_VEC2(double_vc[0],center[PF_X]-vradiusS,center[PF_Y]-vradiusT);
	    PFSET_VEC2(double_vc[1],center[PF_X]+vradiusS,center[PF_Y]-vradiusT);
	    PFSET_VEC2(double_vc[2],center[PF_X]+vradiusS,center[PF_Y]+vradiusT);
	    PFSET_VEC2(double_vc[3],center[PF_X]-vradiusS,center[PF_Y]+vradiusT);
	    PFSET_VEC2(double_tc[0],center[PF_X]-tradiusS,center[PF_Y]-tradiusT);
	    PFSET_VEC2(double_tc[1],center[PF_X]+tradiusS,center[PF_Y]-tradiusT);
	    PFSET_VEC2(double_tc[2],center[PF_X]+tradiusS,center[PF_Y]+tradiusT);
	    PFSET_VEC2(double_tc[3],center[PF_X]-tradiusS,center[PF_Y]+tradiusT);
	    int i;

	    if (coordMap != NULL)
		FOR (i, 4)
		    coordMap(double_vc[i][0], double_vc[i][1], &double_vc[i][0], &double_vc[i][1], coordMapArg);

	    FOR (i, 4)
	    {
		PFSET_VEC3(vc[level][nquads[level]][i],
			   double_vc[i][PF_X],
			   -z,
			   double_vc[i][PF_Y]);
		PFCOPY_VEC2(tc[level][nquads[level]][i], double_tc[i]);
	    }
	    FOR (i, 4)
	    {
		assert(INRANGE(0 <=, double_vc[i][PF_X], <= 1));
		assert(INRANGE(0 <=, double_vc[i][PF_Y], <= 1));
	    }

	    float hue, sat, val;
	    if (loading)
	    {
		hue = (logimageWidth-3)/6.0f;
		sat = .5;
		val = 1.;
	    }
	    else if (valid)
	    {
		hue = (logimageWidth-3)/6.0f;
		sat = .9;
		val = 1.;
	    }
	    else if (useDefault)
	    {
		static float defaultSat = -1, defaultVal = -1;
		if (sat < 0)
		{
		    char *e = getenv("_GEOFLY_DEFAULT_SAT");
		    defaultSat = (e ? *e ? atof(e) : .5 : .5);
		    e = getenv("_GEOFLY_DEFAULT_VAL");
		    defaultVal = (e ? *e ? atof(e) : .3 : .3);
		    printf("default sat = %g, val = %g\n", sat, val);
		}
		hue = (logimageWidth-3)/6.0f;
		sat = defaultSat;
		val = defaultVal;
	    }
	    else
	    {
		/* waiting on this one! white */
		hue = 1;
		sat = 0;
		val = 1;
	    }

	    float red,green,blue;
	    hsv_to_rgb(hue,sat,val,&red,&green,&blue);
	    FOR (i, 4)
		PFSET_VEC4(colors[level][nquads[level]][i], red,green,blue,1.0f);

	    ++nquads[level];
	}
	geosets[level]->setNumPrims(nquads[level]);
    }

    void updateFromClipTexture(pfClipTexture *cliptex)
    {
	int w,h,d;
	int clipSize = cliptex->getClipSize();
	cliptex->getVirtualSize(&w,&h,&d);
	int nlevels = (int)round(log2(w));
	int level;
	FOR (level, nlevels)
	{
	    pfObject *obj = cliptex->getLevel(nlevels-1 - level);

	    if (obj != NULL
	     && obj->isOfType(pfImageCache::getClassType())
	     && (1<<level) >= clipSize) /* don't draw big hidden quads */
		    updateLevelFromImageCache(level, (pfImageCache *)obj);
	    else
		    updateLevelFromImageCache(level, NULL);
	}

	geosets[level]->getGState()->setAttr(PFSTATE_TEXTURE, cliptex);
    }

    /*
     * Draw all levels from coarsest to finest,
     * scaled so that the virtual image takes up the range 0..1 x 0..1.
     * The hue of a tile is chosen to match the gridification color
     * of its level (see gridify.C).
     * Tiles that are resident in memory are drawn fully saturated;
     * tiles that are scheduled to be read but not yet resident
     * are drawn with low saturation.
     */
    void draw()
    {
	int level;
	FOR (level, MAXLEVELS)
	{
	    if (nquads[level] != 0)
	    {
		/*
		if (pfGetNotifyLevel() >= PFNFY_DEBUG)
		{
		    fprintf(stderr, "Drawing geoset for level %d:\n", level);
		    pfPrint(geosets[level], 0, PFPRINT_VB_DEBUG, stderr);
		}
		*/
		int levels_to_enable_texture = 1<<11; /* make this a member */
		if (levels_to_enable_texture & (1<<level))
		{
		    geosets[level]->getGState()->setMode(PFSTATE_ENTEXTURE, PF_ON);
		    geosets[level]->getGState()->apply(); /* XXX ??? */
		}

		geosets[level]->draw();

		if (levels_to_enable_texture & (1<<level))
		{
		    geosets[level]->getGState()->setMode(PFSTATE_ENTEXTURE, PF_OFF);
		    geosets[level]->getGState()->apply(); /* XXX ??? */
		}
	    }
	}
    }



private:
    void set_nquads_alloced(int level, int new_nquads_alloced)
    {
	if (new_nquads_alloced != nquads_alloced[level])
	{
	    if (nquads_alloced[level] != 0)
	    {
		geosets[level]->setAttr(PFGS_COORD3, PFGS_PER_VERTEX,
			NULL, NULL);
		geosets[level]->setAttr(PFGS_TEXCOORD2, PFGS_PER_VERTEX,
			NULL, NULL);
		geosets[level]->setAttr(PFGS_COLOR4, PFGS_PER_VERTEX,
			NULL, NULL);
		assert(pfGetRef(geosets[level]) == 1);
		pfMemory::unrefDelete(geosets[level]);
		assert(pfGetRef(vc[level]) == 1);
		pfMemory::unrefDelete(vc[level]);
		assert(pfGetRef(tc[level]) == 1);
		pfMemory::unrefDelete(tc[level]);
		assert(pfGetRef(colors[level]) == 1);
		pfMemory::unrefDelete(colors[level]);
	    }

	    nquads_alloced[level] = new_nquads_alloced;

	    if (new_nquads_alloced > 0)
	    {
		vc[level] = (pfVec3 (*)[4])pfMalloc(nquads_alloced[level] * sizeof(*vc[level]), getArena());
		assert(vc[level] != NULL);
		pfRef(vc[level]);

		tc[level] = (pfVec2 (*)[4])pfMalloc(nquads_alloced[level] * sizeof(*tc[level]), getArena());
		assert(tc[level] != NULL);
		pfRef(tc[level]);

		colors[level] = (pfVec4 (*)[4])pfMalloc(nquads_alloced[level] * sizeof(*colors[level]), getArena());
		assert(colors[level] != NULL);
		pfRef(colors[level]);

	    }
	    geosets[level]->setAttr(PFGS_COORD3, PFGS_PER_VERTEX,
				    vc[level], NULL);
	    geosets[level]->setAttr(PFGS_TEXCOORD2, PFGS_PER_VERTEX,
				    tc[level], NULL);
	    geosets[level]->setAttr(PFGS_COLOR4, PFGS_PER_VERTEX,
				    colors[level], NULL);
	}
    }

private:
    float tileShrink;	/* 1 --> don't shrink, 0 --> shrink to nothing */
    void (*coordMap)(double, double, double*, double*, void*); /* warp from image 0..1 to displayed 0..1
			   so that the area of interest may be drawn bigger */
    void *coordMapArg; /* closure for coordMap function */
    void (*freeCoordMapArg)(void*); /* function to free coordMapArg */

    pfGeoSet *geosets[MAXLEVELS];
    pfGeoState *geostate;
    int nquads_alloced[MAXLEVELS];
    int nquads[MAXLEVELS];
    pfVec3 (*vc[MAXLEVELS])[4];
    pfVec2 (*tc[MAXLEVELS])[4];
    pfVec4 (*colors[MAXLEVELS])[4];
};

//
// External C api...
//
extern "C" {

pfImageCacheViewer *pfuNewImageCacheViewer(void)
{
    return new(pfGetSharedArena()) pfImageCacheViewer;
}
void pfuDrawImageCacheViewer(pfImageCacheViewer *viewer)
{
    viewer->draw();
}
void pfuUpdateImageCacheViewerFromClipTexture(pfImageCacheViewer *viewer,
					 pfClipTexture *cliptex)
{
    viewer->updateFromClipTexture(cliptex);
}
void pfuImageCacheViewerTileShrink(pfImageCacheViewer *viewer, float tileShrink)
{
    viewer->setTileShrink(tileShrink);
}
void pfuImageCacheViewerCoordMap(
	pfImageCacheViewer *viewer,
	void (*newCoordMap)(double,double,double*,double*,void*),
        void *newCoordMapArg,
        void (*newFreeCoordMapArg)(void*))
{
    viewer->setCoordMap(newCoordMap, newCoordMapArg, newFreeCoordMapArg);
}

} // end extern "C"