[BACK]Return to pfim.c CVS log [TXT][DIR] Up to [Development] / performer / src / lib / libpfdb / libpfim

File: [Development] / performer / src / lib / libpfdb / libpfim / pfim.c (download)

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

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

/*
 * Copyright 1993, 1995, 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
 */

/*
 * pfim.c - simple "Performer" loader.
 * 
 * $Revision: 1.1 $ 
 * $Date: 2000/11/21 21:39:33 $
 */

/*
 * This is sample loader that uses on-disk representations that correspond
 * closely to those in Performer itself.  It's useful for demonstrating 
 * pfFonts and similar objects not supported in any standard formats.
 * The .im format itself is likely to change substantially or disappear
 * in future releases.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#ifndef __linux__
#ifdef	_POSIX_SOURCE
extern char *strdup (const char *s1);
#endif
#endif

#include <Performer/pf.h>
#include <Performer/pfdu.h>
#include <Performer/pfutil.h>

static int breakup = 0;
static char GEODE_NODE[] = "geode";
static char BILLBOARD_NODE[] = "bboard";
static char SWITCH_NODE[] = "switch";
static char SEQUENCE_NODE[] = "sequence";
static char ROOT_NODE[] = "root";
static char GROUP_NODE[] = "group";
static char SCS_NODE[] = "scs";
static char DCS_NODE[] = "dcs";
static char FONT[] = "font";
static char TEXT[] = "str_text";
static char LOD_NODE[] = "lod";
static char LODSTATE[] = "lodstate";
static char LOD_LODSTATE[] = "lod_lodstate";
static char LOD_LODSTATE_INDEX[] = "lod_lodstate_index";
static char COLOR[] = "color";
static char COLORS[] = "colors";
static char NO_COLOR[] = "nocolor";
static char POLY[] = "poly";
static char LINE[] = "line";
static char POINT[] = "point";
static char VERTEX[] = "vc";
static char TEX_COORD[] = "tc";
static char NORMAL_COORD[] = "nc";
static char ATTACH[] = "attach";
static char CLIPTEXTURE[] = "cliptex";
static char CLIPCENTER[] = "clipcenter";
static char TEXGENCLIPCENTER[] = "texgenclipcenter";
static char SPHEREFRONT[] = "spherefront";
static char TEXTURE[] = "tex";
static char NO_TEXTURE[] = "notex";
static char BREAKUP[] = "breakup";
static char SHARE[] = "share";
static char NEW_NODE[] = "new";
static char TGEN_REFLECTIVE[] = "tgen_reflective";
static char TGEN_LINEAR[] = "tgen_linear";
static char TGEN_CONTOUR[] = "tgen_contour";
static char TGEN_OFF[] = "tgen_off";
static char TGEN_PARAMS[] = "tgen_params";
static char LIGHT_POINT_NODE[] = "lp";
static char LOAD_GEODE[] = "load_geode";
static char END_STRING[] = "end";
static char LOAD_STATE[] = "load_state";
static char STORE_STATE[] = "store_state";
static char PUSH_STATE[] = "push_state";
static char POP_STATE[] = "pop_state";
static char DEFINE_DEFAULT[] = "define_default_state";
static char RESET_STATE[] = "reset_state";
static char BOUNDING_SPHERE[] = "bounding_sphere";
static char LOAD_FILE[] = "load_file";
static char ASD_NODE[] = "asd";

pfFont *FindFontInList(pfList *list, char *name)
{
    int i,n;
    pfFont *fnt;

    n = pfGetNum(list);
    for(i=0;i<n;i++)
    {
	fnt = pfGet(list,i);
	if ((char *)pfGetFontAttr(fnt,PFFONT_NAME) && 
		(strcmp(name,(char *)pfGetFontAttr(fnt,PFFONT_NAME)) == 0))
	{
	    return fnt;
	}
    }
    return NULL;
}

pfNode *FindInList(pfList *list, char *name)
{
    int i,n;
    pfNode *nd;

    n = pfGetNum(list);
    for(i=0;i<n;i++)
    {
	nd = pfGet(list,i);
	if (pfGetNodeName(nd) && (strcmp(name,pfGetNodeName(nd)) == 0))
	    return nd;
    }
    return NULL;	  
}

extern pfNode *
pfdLoadFile_im (char *fileName)
{
char GEODE_NODE[] = "geode";
char BILLBOARD_NODE[] = "bboard";
char SEQUENCE_NODE[] = "sequence";
char SWITCH_NODE[] = "switch";
char ROOT_NODE[] = "root";
char GROUP_NODE[] = "group";
char SCS_NODE[] = "scs";
 char DCS_NODE[] = "dcs";
 char FONT[] = "font";
 char TEXT[] = "str_text";
 char LOD_NODE[] = "lod";
 char LODSTATE[] = "lodstate";
 char LOD_LODSTATE[] = "lod_lodstate";
 char LOD_LODSTATE_INDEX[] = "lod_lodstate_index";
 char COLOR[] = "color";
 char COLORS[] = "colors";
 char NO_COLOR[] = "nocolor";
 char POLY[] = "poly";
 char LINE[] = "line";
 char POINT[] = "point";
 char VERTEX[] = "vc";
 char TEX_COORD[] = "tc";
 char NORMAL_COORD[] = "nc";
 char ATTACH[] = "attach";
 char TEXTURE[] = "tex";
 char NO_TEXTURE[] = "notex";
 char BREAKUP[] = "breakup";
 char SHARE[] = "share";
 char NEW_NODE[] = "new";
 char TGEN_REFLECTIVE[] = "tgen_reflective";
 char TGEN_LINEAR[] = "tgen_linear";
 char TGEN_CONTOUR[] = "tgen_contour";
 char TGEN_OFF[] = "tgen_off";
 char TGEN_PARAMS[] = "tgen_params";
 char NEW_TEXGEN[] = "new_tgen";
 char NEW_TEXGEN_OFF[] = "new_tgen_off";
 char LIGHT_POINT_NODE[] = "lp";
 char LOAD_GEODE[] = "load_geode";
 char END_STRING[] = "end";
 char LOAD_STATE[] = "load_state";
 char STORE_STATE[] = "store_state";
 char PUSH_STATE[] = "push_state";
 char POP_STATE[] = "pop_state";
 char DEFINE_DEFAULT[] = "define_default_state";
 char RESET_STATE[] = "reset_state";

    FILE		*imFile;
    pfdGeom		*polygon;
    pfList		*nodeList;
    pfList		*fontList;
    pfList		*clipList;
    pfList		*clipNameList;
    pfGroup		*root = NULL;
    int			count;
    int			primType = PFGS_POLYS;
    char		buf[256];
    char 		endBuf[256];
    char		name[256];
    char		fname[1024];
    char		nodeType[256];
    char		nodeName[256];
    char		childName[256];
    char		parentName[256];
    long txgn;
    pfMaterial  *m      	= NULL;
    pfTexGen 	*tgen		= NULL;
    float *params = NULL;
    int			t	= 0;

    /* restore builder to initial state */
    pfdResetBldrGeometry();
    pfdResetBldrState();

    if ((imFile = pfdOpenFile(fileName)) == NULL)
	return NULL;

    pfdBldrAttr(PFDBLDR_NODE_NAME_COMPARE,(void *)strcmp);
    pfdBldrAttr(PFDBLDR_STATE_NAME_COMPARE,(void *)strcmp);

    /* establish material definition for model */
    m = (pfMaterial*)pfdGetTemplateObject(pfGetMtlClassType());
    pfMtlColor(m, PFMTL_AMBIENT,  0.2f, 0.2f, 0.2f);
    pfMtlColor(m, PFMTL_DIFFUSE,  0.8f, 0.8f, 0.8f);
    pfMtlColor(m, PFMTL_SPECULAR, 1.0f, 1.0f, 1.0f);
    pfMtlShininess(m, 30.0f);
    pfMtlColorMode(m, PFMTL_FRONT, PFMTL_CMODE_OFF);
    pfdBldrStateAttr(PFSTATE_FRONTMTL, m);
    pfdBldrStateMode(PFSTATE_ENLIGHTING, PF_ON);
    pfdBldrStateMode(PFSTATE_CULLFACE, PFCF_BACK);

    txgn = pfdAddState(strdup("texgen"),
			8*sizeof(float),NULL,NULL,NULL,NULL,NULL);
    pfdStateCallback(txgn, PFDEXT_DRAW_PREFUNC,pfdPreDrawTexgenExt);
    pfdStateCallback(txgn, PFDEXT_DRAW_POSTFUNC,pfdPostDrawTexgenExt);

    nodeList = pfNewList(sizeof(pfNode *),1,pfGetSharedArena());
    fontList = pfNewList(sizeof(pfNode *),1,pfGetSharedArena());
    clipList = pfNewList(sizeof(pfMPClipTexture*),1,pfGetSharedArena());
    clipNameList = pfNewList(sizeof(pfMPClipTexture*),1,pfGetSharedArena());
    count = 0;
    polygon = pfdNewGeom(300);
    for (t = 0 ; t < PF_MAX_TEXTURES ; t ++)
	polygon->tbind[t] = PFGS_OFF;    
    polygon->nbind = PFGS_OFF;
    polygon->cbind = PFGS_OFF;
    strcpy(name,"default");

    while(fscanf(imFile,"%s",buf) > 0)
    {
	if (strcmp(buf, LOAD_GEODE) == 0)
	{
	    fscanf(imFile, "%s", name);
	    pfdSelectBldrName(strdup(name));
	}
	else if (strcmp(buf, PUSH_STATE) == 0)
	{
	    pfdPushBldrState();
	    pfNotify(PFNFY_DEBUG,PFNFY_PRINT,"Pushed State");
	}
	else if (strcmp(buf, POP_STATE) == 0)
	{
	    pfdPopBldrState();
	    pfNotify(PFNFY_DEBUG,PFNFY_PRINT,"Popped State");
	}
	else if (strcmp(buf, STORE_STATE) == 0)
	{
	    char *stateNameBuf[512];
	    char *sName;
	    fscanf(imFile,"%s",stateNameBuf);
	    sName = strdup((const char *)stateNameBuf);
	    pfdSaveBldrState(sName);
	    pfNotify(PFNFY_DEBUG,PFNFY_PRINT,
		     "Saved State Under Name: %s",sName);
	}
	else if (strcmp(buf, LOAD_STATE) == 0)
	{
	    char *stateNameBuf[512];
	    char *sName;
	    fscanf(imFile,"%s",stateNameBuf);
	    sName = strdup((const char *)stateNameBuf);
	    pfdLoadBldrState(sName);
	    free(sName);
	    pfNotify(PFNFY_DEBUG,PFNFY_PRINT,
		     "Loaded State Named: %s",sName);
	}
	else if (strcmp(buf, DEFINE_DEFAULT) == 0)
	{
	    pfdCaptureDefaultBldrState();
	}
	else if (strcmp(buf, RESET_STATE) == 0)
	{
	    pfdResetBldrState();
	}
	else if (strcmp(buf, NEW_NODE) == 0)
	{
	    fscanf(imFile, "%s", nodeType);
	    if (strcmp(nodeType, LOD_NODE) == 0)
	    {
		float range,transition;
		int nLODs,i;
		pfLOD *LOD = pfNewLOD();

		fscanf(imFile,"%s",nodeName);
		pfNodeName(LOD,nodeName);

		fscanf(imFile,"%d",&nLODs);
		for(i=0;i<=nLODs;i++)
		{
		    fscanf(imFile,"%f",&range);
		    pfLODRange(LOD,i,range);
		}
		for(i=0;i<=nLODs;i++)
		{
		    fscanf(imFile,"%f",&transition);
		    pfLODTransition(LOD,i,transition);
		}
		pfAdd(nodeList, LOD);
		fscanf(imFile,"%s",endBuf);
	    }
	    else if (strcmp(nodeType, FONT) == 0)
	    {
		int fontType;
		pfFont *fnt = NULL;
		fscanf(imFile,"%s",nodeName);
		fscanf(imFile,"%s %d",childName,&fontType);
		fnt = pfdLoadFont_type1(childName,fontType);
		if (fnt != NULL)
		{
		    pfFontAttr(fnt,PFFONT_NAME,nodeName);
		    pfAdd(fontList, fnt);
		}
		fscanf(imFile,"%s",endBuf);
	    }
	    else if (strcmp(nodeType, TEXT) == 0)
	    {
		int nStrings,i;
		char tmpBuf[8192];
		pfFont *fnt = NULL;
		pfText *txt = pfNewText();
		fscanf(imFile,"%s",nodeName);
		pfNodeName(txt, nodeName);
		fscanf(imFile,"%s", tmpBuf);
		fnt = (pfFont*)FindFontInList(fontList, tmpBuf);
		fscanf(imFile,"%d",&nStrings);
		
		for(i=0;i<nStrings;i++)
		{
		    char c;
		    int j = 0;
		    int done = 0;

		    pfString *curStr = NULL;
/*		    fscanf(imFile,"%s",tmpBuf);*/
		    while(done < 2)
		    {
			c = fgetc(imFile);
			if (c == '|')
			    done++;
			else 
			    done = 0;
			tmpBuf[j++] = c;
		    }
		    tmpBuf[PF_MAX2(j-2,0)] = '\0';
		    curStr = pfNewString(pfGetSharedArena());
		    pfStringString(curStr, tmpBuf);
		    pfStringFont(curStr, fnt);
		    pfAddString(txt,curStr);
		}
		pfAdd(nodeList, txt);
		fscanf(imFile,"%s",endBuf);
	    }
	    else if (strcmp(nodeType, LODSTATE) == 0)
	    {
		pfVec2 rR,rS,tR,tS;
		pfLODState *ls = pfNewLODState();
		fscanf(imFile,"%s",nodeName);
		pfLODStateName(ls,nodeName);
		fscanf(imFile,"%f %f",&rR[0],&rR[1]);
		fscanf(imFile,"%f %f",&rS[0],&rS[1]);
		fscanf(imFile,"%f %f",&tR[0],&tR[1]);
		fscanf(imFile,"%f %f",&tS[0],&tS[1]);
		pfLODStateAttr(ls, PFLODSTATE_RANGE_RANGESCALE, rR[0]);
		pfLODStateAttr(ls, PFLODSTATE_RANGE_RANGEOFFSET, rR[1]);
		pfLODStateAttr(ls, PFLODSTATE_TRANSITION_RANGESCALE, rR[0]);
		pfLODStateAttr(ls, PFLODSTATE_TRANSITION_RANGEOFFSET, tR[1]);
		pfLODStateAttr(ls, PFLODSTATE_RANGE_STRESSSCALE, rS[0]);
		pfLODStateAttr(ls, PFLODSTATE_RANGE_STRESSOFFSET, rS[1]);
		pfLODStateAttr(ls, PFLODSTATE_TRANSITION_STRESSSCALE, rS[0]);
		pfLODStateAttr(ls, PFLODSTATE_TRANSITION_STRESSOFFSET, tS[1]);
		fscanf(imFile,"%s",endBuf);
	    }
	    else if (strcmp(nodeType, LIGHT_POINT_NODE) == 0)
	    {
		int lnum,i;
		float lsize;
		float lh,lp,lr;
		pfVec3 lpos;
		pfVec4 lclr;
		pfLightPoint *lpoint;

		pfNotify(PFNFY_INFO, PFNFY_PRINT, "Defining LP");
		fscanf(imFile,"%s",nodeName);
		fscanf(imFile,"%f",&lsize);
		fscanf(imFile,"%f %f %f", &lh, &lp, &lr);
		fscanf(imFile,"%d",&lnum);
		lpoint = pfNewLPoint(lnum);
		pfNodeName(lpoint, nodeName);
		pfLPointRot(lpoint,lh,lp,lr);
		pfLPointSize(lpoint,lsize);
		for(i=0;i<lnum;i++)
		{
		    fscanf(imFile,"%f %f %f", &lpos[0], &lpos[1], &lpos[2]);
		    fscanf(imFile,"%f %f %f %f", &lclr[0], &lclr[1], &lclr[2], &lclr[3]);
		    pfLPointPos(lpoint,i,lpos);
		    pfLPointColor(lpoint,i,lclr);
		}
		fscanf(imFile,"%s",endBuf);
		pfAdd(nodeList, lpoint);
	    }
	    else if (strcmp(nodeType, ROOT_NODE) == 0)
	    {
		root = pfNewGroup();

		fscanf(imFile,"%s",nodeName);
		pfNodeName(root, nodeName);

		pfAdd(nodeList, root);
		fscanf(imFile,"%s",endBuf);
	    }
	    else if (strcmp(nodeType, GROUP_NODE) == 0)
	    {
		pfGroup *grp = pfNewGroup();

		fscanf(imFile,"%s",nodeName);
		pfNodeName(grp, nodeName);

		pfAdd(nodeList, grp);
		fscanf(imFile,"%s",endBuf);
	    }
	    else if (strcmp(nodeType, SWITCH_NODE) == 0)
	    {
		pfSwitch *sw = pfNewSwitch();

		fscanf(imFile,"%s",nodeName);
		pfNodeName(sw, nodeName);

		pfAdd(nodeList, sw);
		fscanf(imFile,"%s",endBuf);
	    }
	    else if (strcmp(nodeType, GEODE_NODE) == 0)
	    {
		pfGeode *gd = pfNewGeode();

		fscanf(imFile,"%s",nodeName);
		pfNodeName(gd, nodeName);

		pfAdd(nodeList, gd);
		fscanf(imFile,"%s",endBuf);
	    }
	    else if (strcmp(nodeType, ASD_NODE) == 0)
	    {
		pfASD *asd;
		pfGeoState **gsList;
		int i,nGStates;

		fscanf(imFile,"%s",nodeName);
		fscanf(imFile,"%s",fname);
		asd = (pfASD*)pfdLoadFile(fname);
		pfNodeName(asd, nodeName);
		fscanf(imFile,"%d",&nGStates);
		gsList = (pfGeoState**)pfMalloc(nGStates*sizeof(pfGeoState*),
						pfGetSharedArena());
		for(i=0;i<nGStates;i++)
		{
		    pfGeoState *gs = pfNewGState(pfGetSharedArena());
		    sprintf(fname, "%s.%d", nodeName,i);
		    pfdLoadBldrState(fname);
		    pfCopy(gs, (void*)pfdGetBldrGState());
		    gsList[i] = gs;
   		}
		if(nGStates > 0)
		    pfASDGStates(asd,gsList,nGStates);
		pfAdd(nodeList, asd);
		fscanf(imFile,"%s",endBuf);
	    }		
	    else if (strcmp(nodeType, BILLBOARD_NODE) == 0)
	    {
		int rotmode, i;
		float axis[3], pos[3];

		pfBillboard *bb = pfNewBboard();

		fscanf(imFile,"%s",nodeName);
		pfNodeName(bb, nodeName);

		fscanf(imFile, "mode %d", &rotmode);
		pfBboardMode(bb, PFBB_ROT, rotmode);
		fscanf(imFile, "axis %f %f %f", &axis[0], &axis[1], &axis[2]);
		pfBboardAxis(bb, axis);
		while (fscanf(imFile, "pos %d %f %f %f",
			&i, &pos[0], &pos[1], &pos[2]) == 4)
		    pfBboardPos(bb, i, pos);

		pfAdd(nodeList, bb);
		fscanf(imFile,"%s",endBuf);
	    }
	    else if (strcmp(nodeType, SEQUENCE_NODE) == 0)
	    {
		int nFrames,i;
		float time;
		pfSequence *seq = pfNewSeq();

		fscanf(imFile,"%s",nodeName);
		pfNodeName(seq, nodeName);

		fscanf(imFile,"%d",&nFrames);
		for(i=0;i<nFrames;i++)
		{
		    fscanf(imFile,"%f",&time);
		    pfSeqTime(seq, i, time);
		}
		pfSeqDuration(seq,1.0f, -1.0f);
		pfSeqMode(seq,PFSEQ_START);
		pfAdd(nodeList, seq);
		fscanf(imFile,"%s",endBuf);
	    }
	    else if (strcmp(nodeType, DCS_NODE) == 0)
	    {
		pfMatrix mat;
		float tx,ty,tz,rx,ry,rz,sx,sy,sz;
		int i,j;
		pfDCS *DCS = pfNewDCS();

		pfMakeIdentMat(mat);
		fscanf(imFile,"%s",nodeName);
		pfNodeName(DCS, nodeName);
		fscanf(imFile,"%s",endBuf);
		while(strncmp(endBuf,"end",3) != 0)
		{
		    if (strncmp(endBuf,"translate",8)==0)
		    {
			fscanf(imFile,"%f %f %f",&tx,&ty,&tz);
			pfPostTransMat(mat,mat,tx,ty,tz);
		    }
		    else if (strncmp(endBuf,"rotate",6)==0)
		    {
			pfMatrix tmp;
			fscanf(imFile,"%f %f %f",&rx,&ry,&rz);
			pfMakeEulerMat(tmp,rx,ry,rz);
			pfPostMultMat(mat,tmp);
		    }
		    else if (strncmp(endBuf,"scale",5)==0)
		    {		   
			fscanf(imFile,"%f %f %f",&sx,&sy,&sz);
			pfPostScaleMat(mat,mat,sx,sy,sz);
		    }
		    else if (strncmp(endBuf,"matrix",5)==0)
		    {		   
			for(j=0;j<4;j++)
			  for(i=0;i<4;i++)
			    fscanf(imFile,"%f",mat[i][j]);
		    }
		    fscanf(imFile,"%s",endBuf);
		}
		pfDCSMat(DCS,mat);
		pfAdd(nodeList,DCS);
	    }
	    else if (strcmp(nodeType, SCS_NODE) == 0)
	    {
		pfMatrix mat;
		float tx,ty,tz,rx,ry,rz,sx,sy,sz;
		int i,j;
		pfSCS *SCS;

		pfMakeIdentMat(mat);
		fscanf(imFile,"%s",nodeName);
		fscanf(imFile,"%s",endBuf);
		while(strncmp(endBuf,"end",3) != 0)
		{
		    if (strncmp(endBuf,"translate",8)==0)
		    {
			fscanf(imFile,"%f %f %f",&tx,&ty,&tz);
			pfPostTransMat(mat,mat,tx,ty,tz);
		    }
		    else if (strncmp(endBuf,"rotate",6)==0)
		    {
			pfMatrix tmp;
			fscanf(imFile,"%f %f %f",&rx,&ry,&rz);
			pfMakeEulerMat(tmp,rx,ry,rz);
			pfPostMultMat(mat,tmp);
		    }
		    else if (strncmp(endBuf,"scale",5)==0)
		    {		   
			fscanf(imFile,"%f %f %f",&sx,&sy,&sz);
			pfPostScaleMat(mat,mat,sx,sy,sz);
		    }
		    else if (strncmp(endBuf,"matrix",5)==0)
		    {		   
			for(j=0;j<4;j++)
			  for(i=0;i<4;i++)
			    fscanf(imFile,"%f",&mat[i][j]);
		    }
		    fscanf(imFile,"%s",endBuf);
		}
		SCS = pfNewSCS(mat);
		pfNodeName(SCS, nodeName);
		pfAdd(nodeList,SCS);
	    }
	}
	else if (strcmp(buf, LOAD_FILE) == 0)
	{
	    /*
	     * Note that if the file is not .im format,
	     * the file name should contain the appropriate
	     * extension, e.g. call it "myscene.obj.im"
	     * to ensure that the proper converter gets loaded
	     * beforehand.
	     */
	    pfNode *node;
	    pfGroup *protector;
	    pfdBuilder *oldbuilder, *newbuilder;
		/* otherwise if it's a geode, we would kill it at the end */
	    fscanf(imFile, "%s %s", fname, nodeName);

	    /* push builder... */
	    newbuilder = pfdNewBldr();
	    oldbuilder = pfdGetCurBldr();
	    pfdSelectBldr(newbuilder);

	    node = pfdLoadFile(fname);

	    /* pop builder... */
	    pfdSelectBldr(oldbuilder);
	    pfdDelBldr(newbuilder);

	    protector = pfNewGroup();
	    pfAddChild(protector, node);
	    pfNodeName(protector, nodeName);
	    pfAdd(nodeList, protector);
	}
	else if (strcmp(buf, LOD_LODSTATE) == 0)
	{
	    pfLODState *ls;
	    pfLOD *lod;
	    fscanf(imFile,"%s %s",parentName,childName);
	    lod = (pfLOD *)FindInList(nodeList, parentName);
	    ls = pfFindLODState(childName);
	    if (lod && ls)
		pfLODLODState(lod,ls);
	    else if (!lod)
		pfNotify(PFNFY_WARN,PFNFY_PRINT,"No LOD Named: %s",parentName);
	    else 
		pfNotify(PFNFY_WARN,PFNFY_PRINT,"No LODState Named: %s",
			childName);
	}
	else if (strcmp(buf, LOD_LODSTATE_INDEX) == 0)
	{
	    pfLOD *lod;
	    long index;

	    fscanf(imFile,"%s %d",parentName,&index);
	    lod = (pfLOD *)FindInList(nodeList, parentName);
	    pfLODLODStateIndex(lod,index);
	}
	else if (strcmp(buf, BOUNDING_SPHERE) == 0)
	{
	    pfNode *node;
	    pfSphere bsph;
	    fscanf(imFile, "%s %f %f %f  %f",
		   nodeName,
		   &bsph.center[0],
		   &bsph.center[1],
		   &bsph.center[2],
		   &bsph.radius);
	    node = FindInList(nodeList, nodeName);
	    if (node != NULL)
	    {
		pfNodeBSphere(node, &bsph, PFBOUND_STATIC);
		pfNotify(PFNFY_DEBUG, PFNFY_PRINT,
		   "pfNodeBSphere(%s,center=(%.9g,%.9g,%.9g),radius=%.9g)",
		   nodeName,
		   bsph.center[0], bsph.center[1], bsph.center[2], bsph.radius);
	    }
	    else
		pfNotify(PFNFY_WARN, PFNFY_PRINT,
			 "Cannot set bounding sphere: No Node Named \"%s\"",
			 nodeName);
	}
	else if (strcmp(buf, ATTACH) == 0)
	{
	    pfGroup *parent;
	    pfNode *child;

	    fscanf(imFile,"%s %s",parentName,childName);
	    parent = (pfGroup *)FindInList(nodeList, parentName);
	    child = FindInList(nodeList, childName);
	    if (parent && child)
	    {
		pfAddChild(parent,child);
		pfNotify(PFNFY_DEBUG, PFNFY_PRINT,
			 "pfAddChild(%s,%s)",parentName,childName);
	    }
	    else if (!parent)
		pfNotify(PFNFY_WARN, PFNFY_PRINT, 
		    "Cannot Attach: No Node Named: %s", parentName);
	    else if (!child)
		pfNotify(PFNFY_WARN, PFNFY_PRINT, 
		    "Cannot Attach: No Node Named: %s", childName);
	}
	else if (strcmp(buf, SPHEREFRONT) == 0)
	{
	    pfNode *spherefront_node;
	    int size;
	    pfTexture *tex = (pfTexture*)pfdGetBldrStateAttr(PFSTATE_TEXTURE);
	    pfVec2 lonlat[2], st[2];
	    fscanf(imFile, "%s %f,%f,%f,%f %f,%f,%f,%f %d",
	        nodeName,
		&lonlat[0][PF_S], &lonlat[0][PF_T], &st[0][PF_S], &st[0][PF_T],
	        &lonlat[1][PF_S], &lonlat[1][PF_T], &st[1][PF_S], &st[1][PF_T],
	        &size);
	    spherefront_node = pfuNewSphereFrontOld(size, tex, lonlat, st, 1);
	    pfNodeName(spherefront_node, nodeName);
	    pfAdd(nodeList, spherefront_node);
	}
	else if (strncmp(buf, CLIPCENTER, 7) == 0)
	{
	    /*
	     * clipcenter clipcenter_nodeName childName refnodeName
	     * 	   creates the following:
	     *
	     *	       clipcenter_node 	--(user data)--> refnode
	     *		     |
	     *	           child
	     *
	     * clipcenter_node is a pfGroup with one child and:
	     *   -- a precull callback that calculates the point in refnode
	     *	    closest to the eye
	     *	 -- a predraw callback that sets the center of the clipmap
	     *	    to the point calculated in the precull callback.
	     * refnode should be a representation (possibly simplified,
	     * perhaps to a single quad or triangle) of child;
	     * it can be a reference to child itself.
	     */
	    pfNode *child, *refnode;
	    pfTexture *tex;
	    char clipcenter_nodeName[256];
	    char refnodeName[256];

	    fscanf(imFile,"%s %s %s",clipcenter_nodeName,childName,refnodeName);

	    refnode = FindInList(nodeList, refnodeName);
	    child = FindInList(nodeList, childName);

	    if (!refnode || !child)
	    {
		pfNotify(PFNFY_WARN, PFNFY_PRINT, 
		    "Cannot attach for clipmap centering: No Node Named: %s",
		    !refnode ? refnodeName : childName);
	    }
	    else if (!pfIsOfType(
		    tex = (pfTexture*)pfdGetBldrStateAttr(PFSTATE_TEXTURE),
		    pfGetClipTextureClassType()))
	    {
		/* do something reasonable to preserve the structure... */
		pfGroup *clipcenter_node = pfNewGroup();
		pfNodeName(clipcenter_node, clipcenter_nodeName);
		pfAdd(nodeList, clipcenter_node);
		pfAddChild(clipcenter_node, child);

		pfNotify(PFNFY_WARN, PFNFY_PRINT,
		    "Cannot attach for clipmap centering--");
		pfNotify(PFNFY_WARN, PFNFY_MORE,
		    "    texture %s is not a clip texture!",
		    pfGetTexName((pfTexture*)tex));
	    }
	    else
	    {
		pfuClipCenterNode *ccn;
		ccn = pfuNewClipCenterNode();
		pfuClipCenterNodeClipTexture(ccn, (pfClipTexture *)tex);
		pfNodeName(ccn, clipcenter_nodeName);
		pfuClipCenterNodeRefNode(ccn, refnode);
		pfAddChild(ccn, child);
		pfAdd(nodeList, ccn);

		pfNotify(PFNFY_DEBUG, PFNFY_PRINT,
		    "Created clipcenter node %s(%s,%s)",
		    clipcenter_nodeName, childName, refnodeName);
	    }
	}
	else if (strcmp(buf, TEXGENCLIPCENTER) == 0)
	{
            /*
             * clipcenter clipcenter_nodeName childName refnodeName
             *     creates the following:
             *
             *         clipcenter_node  --(user data)--> refnode
             *               |
             *             child
             *
             * clipcenter_node is a pfGroup with one child and:
             *   -- a precull callback that calculates the point in refnode
             *      closest to the eye
             *   -- a predraw callback that sets the center of the clipmap
             *      to the point calculated in the precull callback.
             * refnode should be a representation (possibly simplified,
             * perhaps to a single quad or triangle) of child;
             * it can be a reference to child itself.
             */

	    pfNode *child;
            pfTexture *tex;
            char clipcenter_nodeName[256];
	    pfuTexGenClipCenterNode *ccn;
	    pfTexGen *tgen;

            fscanf(imFile,"%s %s",clipcenter_nodeName,childName);
            child = FindInList(nodeList, childName);
            if (!child)
            {
                pfNotify(PFNFY_WARN, PFNFY_PRINT,
                    "Cannot attach for clipmap centering: No childNode Named: %s",
                    childName);
            }
            else if (!pfIsOfType(
                    tex = (pfTexture*)pfdGetBldrStateAttr(PFSTATE_TEXTURE),
                    pfGetClipTextureClassType()))
            {
                /* do something reasonable to preserve the structure... */
                pfGroup *clipcenter_node = pfNewGroup();
                pfNodeName(clipcenter_node, clipcenter_nodeName);
                pfAdd(nodeList, clipcenter_node);
                pfAddChild(clipcenter_node, child);

                pfNotify(PFNFY_WARN, PFNFY_PRINT,
                    "Cannot attach for clipmap centering--");
                pfNotify(PFNFY_WARN, PFNFY_MORE,
                    "    texture %s is not a clip texture!",
                    pfGetTexName((pfTexture*)tex));
            }
	    else /* using immediate mode */
	    {
	     	ccn = pfuNewTexGenClipCenterNode();
	     	pfuClipCenterNodeClipTexture((pfuClipCenterNode *)ccn, (pfClipTexture *)tex);
	     	pfNodeName(ccn, clipcenter_nodeName);
		tgen = (pfTexGen *)pfdGetBldrStateAttr(PFSTATE_TEXGEN);
		pfuTexGenClipCenterNodeTexGen(ccn, tgen);
                pfAddChild(ccn, child);
                pfAdd(nodeList, ccn);
	    }
	}
	else if (strcmp(buf, BREAKUP) == 0)
	{
	    int		breakup, breakupSize, breakupStrips,breakupBranch;

	    fscanf(imFile, "%d %f %d %d", 
			&breakup, &breakupSize, &breakupStrips,&breakupBranch);
	    pfdBldrMode(PFDBLDR_BREAKUP, breakup);
	    pfdBldrMode(PFDBLDR_BREAKUP_SIZE, breakupSize);
	    pfdBldrMode(PFDBLDR_BREAKUP_BRANCH, breakupBranch);
	    pfdBldrMode(PFDBLDR_BREAKUP_STRIP_LENGTH, breakupStrips);
	}
	else if (strcmp(buf, SHARE) == 0)
	{
	    int share_mask;
	    fscanf(imFile, "%d ", &share_mask);
	    pfdBldrMode(PFDBLDR_SHARE_MASK,share_mask);
	}
	else if (strncmp(buf, TGEN_PARAMS, 8) == 0)
	{ /* add params to a pre-existing texgen */

	    int p;

	    if (params)
		pfDelete(params);
	    params = pfMalloc(8*sizeof(float),pfGetSharedArena());
	    for(p=0;p<8;p++)
		fscanf(imFile,"%f ",&(params[p]));
	    pfNotify(PFNFY_DEBUG,PFNFY_PRINT,"Set PX: %.2f %.2f %.2f %.2f",
		     params[0],params[1],params[2],params[3]);
	    pfNotify(PFNFY_DEBUG,PFNFY_PRINT,"Set PX: %.2f %.2f %.2f %.2f",
		     params[4],params[5],params[6],params[7]);
	    if (tgen)
	    {
		pfTGenPlane(tgen, PF_S, params[0], params[1], params[2], params[3]);
		pfTGenPlane(tgen, PF_T, params[4], params[5], params[6], params[7]);
	    }
	    /*pfdBldrStateAttr(txgn,params);*/
	}
	else if (strncmp(buf, TGEN_REFLECTIVE, 8) == 0)
	{
	    tgen = (pfTexGen *)pfdGetTemplateObject(pfGetTGenClassType());
	    pfTGenMode(tgen, PF_S, PFTG_SPHERE_MAP);
	    pfTGenMode(tgen, PF_T, PFTG_SPHERE_MAP);
	    pfdBldrStateAttr(PFSTATE_TEXGEN,tgen);
	    pfdBldrStateMode(PFSTATE_ENTEXGEN, PFTR_ON);
	}
	else if (strncmp(buf, TGEN_CONTOUR, 8) == 0)
	{
	    /*pfdBldrStateMode(txgn,PFD_TEXGEN_CONTOUR);*/
	    tgen = (pfTexGen *)pfdGetTemplateObject(pfGetTGenClassType());
	    pfTGenMode(tgen, PF_S, PFTG_EYE_LINEAR);
	    pfTGenMode(tgen, PF_T, PFTG_EYE_LINEAR);
	    if (params)
	    {
		pfTGenPlane(tgen, PF_S, params[0], params[1], params[2], params[3]);
		pfTGenPlane(tgen, PF_T, params[4], params[5], params[6], params[7]);
	    }
	    pfdBldrStateAttr(PFSTATE_TEXGEN,tgen);
	    pfdBldrStateMode(PFSTATE_ENTEXGEN, PFTR_ON);
	}
	else if (strncmp(buf, TGEN_LINEAR, 8) == 0)
	{
	    /*pfdBldrStateMode(txgn,PFD_TEXGEN_LINEAR);*/
	    tgen = (pfTexGen *)pfdGetTemplateObject(pfGetTGenClassType());
	    pfTGenMode(tgen, PF_S, PFTG_OBJECT_LINEAR);
	    pfTGenMode(tgen, PF_T, PFTG_OBJECT_LINEAR);
	    if (params)
	    {
		pfTGenPlane(tgen, PF_S, params[0], params[1], params[2], params[3]);
		pfTGenPlane(tgen, PF_T, params[4], params[5], params[6], params[7]);
	    }
	    pfdBldrStateAttr(PFSTATE_TEXGEN,tgen);
	}
	else if (strncmp(buf, TGEN_OFF, 6) == 0)
	{
	    pfdBldrStateMode(PFSTATE_ENTEXGEN, PFTR_OFF);
	    pfdBldrStateMode(txgn,PFD_TEXGEN_OFF);
	}
	else if (strcmp(buf, NEW_TEXGEN) == 0)
	{
	    int i;
	    pfMatrix mat;
	    pfTexGen *tg = (pfTexGen *)pfdGetTemplateObject(pfGetTGenClassType());
	    for(i=0;i<16;i++)
	    	fscanf(imFile,"%f", &mat[(int)i/4][i%4]);
	    pfTGenPlane(tg, PF_S, mat[0][0], mat[1][0], mat[2][0], mat[3][0]);
	    pfTGenPlane(tg, PF_T, mat[0][1], mat[1][1], mat[2][1], mat[3][1]);
	    pfTGenPlane(tg, PF_R, mat[0][2], mat[1][2], mat[2][2], mat[3][2]);
	    pfTGenPlane(tg, PF_Q, mat[0][3], mat[1][3], mat[2][3], mat[3][3]);
	    pfTGenMode(tg, PF_S, PFTG_OBJECT_LINEAR);
	    pfTGenMode(tg, PF_T, PFTG_OBJECT_LINEAR);
	    pfTGenMode(tg, PF_R, PFTG_OBJECT_LINEAR);
	    pfTGenMode(tg, PF_Q, PFTG_OBJECT_LINEAR);
	    pfdBldrStateAttr(PFSTATE_TEXGEN,tg);
	    pfdBldrStateMode(PFSTATE_ENTEXGEN, PFTR_ON);
	    for(i=0;i<16;i++)
	    {
		if (i%4 == 0)
			printf("\n");
	    	printf("%f ", mat[(int)(i/4)][i%4]);
	    }
		printf("\n");
	}
	else if (strcmp(buf, NEW_TEXGEN_OFF)==0)
	{
	    pfdBldrStateMode(PFSTATE_ENTEXGEN, PFTR_OFF);
	}
	else if (strncmp(buf, TEXTURE, 3) == 0)
	{
	    pfTexture *tex = (pfTexture *)
		pfdGetTemplateObject(pfGetTexClassType());
	    fscanf(imFile, "%s", fname);
	    pfTexName(tex,fname);
	    pfdBldrStateAttr(PFSTATE_TEXTURE,tex);
	    pfdBldrStateMode(PFSTATE_ENTEXTURE, PFTR_ON);
	}
	else if (strncmp(buf, CLIPTEXTURE, 7) == 0)
	{
	    pfClipTexture *cliptex;
	    fscanf(imFile, "%s", fname);
	    cliptex = pfdLoadClipTexture(fname);
	    if (cliptex != NULL)
	    {
		pfTexName((pfTexture *)cliptex,fname); /* XXX is it already? */
		pfdBldrMode(PFDBLDR_PASS_REFERENCES, 1);
		pfdBldrStateAttr(PFSTATE_TEXTURE,cliptex);
		pfdBldrMode(PFDBLDR_PASS_REFERENCES, 0);
		pfdBldrStateMode(PFSTATE_ENTEXTURE, PFTR_ON);
		pfNotify(PFNFY_DEBUG, PFNFY_PRINT,
			 "im: successfully loaded clip texture from %s:",
			 fname);
		if (pfGetNotifyLevel() >= PFNFY_DEBUG)
		{
		    pfPrint(cliptex, PFTRAV_SELF | PFTRAV_DESCEND,
			    PFPRINT_VB_DEBUG, stderr); /* XXX */
		}
	    }
	    else
		pfNotify(PFNFY_WARN, PFNFY_PRINT,
			 "Can't load clip texture file %s\n", fname);
	}
	else if (strncmp(buf, NO_TEXTURE, 5) == 0)
	{
	    pfTexture *tex = NULL;
	    pfdBldrStateAttr(PFSTATE_TEXTURE,tex);
	    pfdBldrStateMode(PFSTATE_ENTEXTURE, PFTR_OFF);
	}
	else if (strncmp(buf, COLORS, 6) == 0)
	{
	    int i;
	    polygon->cbind = PFGS_PER_VERTEX;
	    for (i=0;i<polygon->numVerts;i++)
		fscanf(imFile, "%f %f %f %f", 
			&polygon->colors[i][0],
			&polygon->colors[i][1],
			&polygon->colors[i][2],
			&polygon->colors[i][3]);
	}
	else if (strncmp(buf, COLOR, 5) == 0)
	{
	    polygon->cbind = PFGS_OVERALL;
	    fscanf(imFile, "%f %f %f %f", 
			&polygon->colors[0][0],
			&polygon->colors[0][1],
			&polygon->colors[0][2],
			&polygon->colors[0][3]);
	}
	else if (strncmp(buf,NO_COLOR,5) == 0)
	{
	    polygon->cbind = PFGS_OFF;
	}
	else if (strncmp(buf, POLY, 4) == 0)
	{
	    fscanf(imFile, "%d", &polygon->numVerts);
	    primType = PFGS_POLYS;
	}
	else if (strncmp(buf, LINE, 4) == 0)
	{
	    fscanf(imFile, "%d", &polygon->numVerts);
	    primType = PFGS_LINES;
	}
	else if (strncmp(buf, POINT, 5) == 0)
	{
	    fscanf(imFile, "%d", &polygon->numVerts);
	    primType = PFGS_POINTS;
	}
	else if (strcmp(buf, VERTEX) == 0)
	{
	    int i;
	    for (i=0;i<polygon->numVerts;i++)
		fscanf(imFile, "%f %f %f", 
			&polygon->coords[i][0],
 			&polygon->coords[i][1], 
 			&polygon->coords[i][2]);
	}
	else if (strcmp(buf, TEX_COORD) == 0)
	{
	    int i;
	    
	    for (i=0;i<polygon->numVerts;i++)
		fscanf(imFile, "%f %f", 
		    &polygon->texCoords[0][i][0], 
		    &polygon->texCoords[0][i][1]); 
	    polygon->tbind[0] = PFGS_PER_VERTEX;
	    for (t = 1 ; t < PF_MAX_TEXTURES ; t ++)
		polygon->tbind[t] = PFGS_OFF;
	}
	else if (strcmp(buf, NORMAL_COORD) == 0)
	{
	    int i;
	    for (i=0;i<polygon->numVerts;i++)
		fscanf(imFile, "%f %f %f", 
			&polygon->norms[i][0],
 			&polygon->norms[i][1], 
 			&polygon->norms[i][2]);
	    polygon->nbind = PFGS_PER_VERTEX;
	}
	else if (strcmp(buf, "end") == 0)
	{
	    polygon->primtype = primType;
	    pfdAddBldrGeom(polygon,1);
	    for (t = 0 ; t < PF_MAX_TEXTURES ; t ++)
		polygon->tbind[t] = PFGS_OFF;
	    count += polygon->numVerts - 2;
	}
	else if (buf[0] == '#')
	{
	    /*
	     * discard rest of line as comment
	     * (note this only works in the global scope)
	     */
	    int c;
	    while ((c = getc(imFile)) != EOF && c != '\n')
		;
	}
	else
	{
	    pfNotify(PFNFY_WARN, PFNFY_PRINT, "Bogus Token: %s in file %s", 
			buf, fileName);
	}
    }
    {
	int i,j,n;
	n = pfGetNum(nodeList);
	for(i=0;i<n;i++)
	{
	    pfNode *node = pfGet(nodeList,i);
	    if (pfIsOfType(node, pfGetGeodeClassType()))
	    {
		char buf[512];
		pfNode *newNode;
		int nParents = pfGetNumParents(node);

		strncpy(buf,pfGetNodeName(node),512);
		newNode = pfdBuildNode(buf);

		for(j=0;j<nParents;j++)
		{
		    pfGroup *parent = pfGetParent(node,0); /* sic */
		    pfReplaceChild(parent,node,newNode);
		}
		pfDelete(node);
	    }
	}
    }
    fclose(imFile);
    pfdDelGeom(polygon);

    pfDelete(nodeList);
    pfDelete(fontList);
    pfDelete(clipList);
    pfDelete(clipNameList);

    /* print statistics */
    pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "pfdLoadFile_im: %s", fileName);
    pfNotify(PFNFY_INFO,   PFNFY_MORE,  "  Input Data:");
    pfNotify(PFNFY_INFO,   PFNFY_MORE,  "    Input polygons:     %8ld", count);

    return (pfNode *)root;
}