[BACK]Return to pfcsb.C CVS log [TXT][DIR] Up to [Development] / performer / src / lib / libpfdb / libpfcsb

File: [Development] / performer / src / lib / libpfdb / libpfcsb / pfcsb.C (download)

Revision 1.2, Fri Jan 12 03:55:14 2001 UTC (16 years, 9 months ago) by flynnt
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +2 -2 lines

linux csb loader byte-swapping fix

We were doing a swapped fread, when we shoulda been doing a regular fread
(for reading in a string).
-tom

/*
 * Copyright 1996, 1997 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
 */

/*
 *  pfCsb.c $Revision: 1.2 $
 */

#ifdef __linux__
int __cmpdi2;
#endif

#include <Performer/pr/pfGeoSet.h>
#include <Performer/pr/pfGeoState.h>
#include <Performer/pr/pfTexture.h>
#include <Performer/pr/pfMaterial.h>

#include <Performer/pf/pfNode.h>
#include <Performer/pf/pfBillboard.h>
#include <Performer/pf/pfGroup.h>
#include <Performer/pf/pfLOD.h>
#include <Performer/pf/pfDCS.h>
#include <Performer/pf/pfSwitch.h>
#include <Performer/pf/pfGeode.h>

#include <Performer/pfdu.h>

#include "pfcsb.h"

#if defined(__linux_has_ifl__) || !defined(__linux__)
#include <ifl/iflFile.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#ifndef __linux__
#include <bstring.h>
#else
#include <string.h>
#endif
#include <inttypes.h>
#include <malloc.h>
#include <dlfcn.h>

// Magic numbers used in csb files.
#define CSB_MAGIC_NUMBER	0xdb0c3d00
#define CSB_MAGIC_NUMBER_E      0x003d0cdb	// opposite endian
#define CSB_MAGIC_ENCODED       0xdb0c3d01
#define CSB_MAGIC_ENCODED_E     0x013d0cdb	// opposite endian

// current version number
#define CURRENT_OPTIMIZER_VERSION "1.0"

// DEBUG DEFINES
//#define DEBUG_NODE
//#define PRINT_SCENE

// typedefs for sized integers and floats.
// It is important that the fields in a csb file are of a well known size.

typedef int8_t		int8;
typedef uint8_t		uint8;
typedef int16_t		int16;
typedef uint16_t	uint16;
typedef int32_t		int32;
typedef uint32_t	uint32;
typedef int64_t		int64;
typedef uint64_t	uint64;
typedef intptr_t	intp;
typedef uintptr_t	uintp;
typedef float		float32;
typedef double		float64;

#ifdef __linux__
typedef unsigned char uchar_t;
#endif

// typedef for ClearCoat facility
typedef void (*ClearCoatGenFunc)(uchar_t*, int, int, int, int, uchar_t*, float, float, float);


//--------------------------------------------------------------------------

// Structures, tables, and defines matching cosmo3d classes.

/*
 *  ---------- for csObject ----------
 */

#define OBJECT_DATA


/*
 *  ---------- for csContainer ----------
 */

#define CONTAINER_DATA	\
    OBJECT_DATA		\
    int32 name_size;	\
    int32 udata;

typedef struct {
    CONTAINER_DATA
} container_t;


/*
 *  ---------- for csNode ----------
 */

#define NODE_DATA	\
    CONTAINER_DATA	\
    int32 bound_mode;	\
    int32 sphere_bound;

static const int nbm_table[] =		/* node bound mode */
{2,
    PFBOUND_STATIC,
    PFBOUND_DYNAMIC,
};

typedef struct {
    NODE_DATA
} node_t;


/*
 *  ---------- for csGroup ----------
 */

#define GROUP_DATA	\
    NODE_DATA		\
    int32 num_children;

typedef struct {
    GROUP_DATA
} group_t;


/*
 *  ---------- for csTransform ----------
 */

#define TRANSFORM_DATA_894      \
    GROUP_DATA                  \
    csFloat mat[4][4];

typedef struct {
    TRANSFORM_DATA_894
} transform_894_t;

#define TRANSFORM_DATA          \
    GROUP_DATA                  \
    csFloat translation[3];     \
    csFloat rotation[4];        \
    csFloat scale[3];           \
    csFloat scaleOrientation[4];\
    csFloat center[3];          \

typedef struct {
    TRANSFORM_DATA
} transform_t;


/*
 *  ---------- for csSwitch ----------
 */

#define SWITCH_DATA	\
    GROUP_DATA		\
    int32 which_child;

#define CSB_SWITCH_NO_CHILDREN	-1
#define CSB_SWITCH_ALL_CHILDREN	-2

typedef struct {
    SWITCH_DATA
} switch_t;

/*
 *  ---------- for csLOD ----------
 */
#define CS_MAX_LOD_RANGES       (10)   // from csLOD.h

#define CSLOD_DATA	\
    SWITCH_DATA		\
    float32 center[3]; \
    float32 ranges[CS_MAX_LOD_RANGES+1]; \
    int32 numRanges; \
    int32 offset;

typedef struct {
    CSLOD_DATA
} cslod_t;

/*
 *  ---------- for csShape ----------
 */

#define SHAPE_DATA	\
    NODE_DATA		\
    int32 appearance;	\
    int32 num_geometry;

typedef struct {
    SHAPE_DATA
} shape_t;

/*
 *  ---------- for csBillboard ----------
 */

#define BILLBOARD_DATA_893      \
    GROUP_DATA                  \
    int num_position;           \
    int mode;                   \
    float32 axis[3];

#define BILLBOARD_DATA          \
    BILLBOARD_DATA_893          \
    int forward;                \
    int up;

static const int bbm_table[] =          /* billboard mode */
{3,
/*
    (int)csBillboard::AXIAL,
    (int)csBillboard::POINT_SCREEN,
    (int)csBillboard::POINT_OBJECT,
*/
};
static const int bbv_table[] =          /* billboard vector (forward & up) */
{6,
/*
    (int)csBillboard::POS_X_AXIS,
    (int)csBillboard::POS_Y_AXIS,
    (int)csBillboard::POS_Z_AXIS,
    (int)csBillboard::NEG_X_AXIS,
    (int)csBillboard::NEG_Y_AXIS,
    (int)csBillboard::NEG_Z_AXIS,
*/
};

typedef struct {
    BILLBOARD_DATA_893
} billboard_t_893;

typedef struct {
    BILLBOARD_DATA
} billboard_t;

/*
 *  ---------- for csEnvironment ----------
 */

#define ENVIRONMENT_DATA        \
    GROUP_DATA                  \
    int num_light;              \
    int fog;

typedef struct {
    ENVIRONMENT_DATA
} environment_t;


/*
 *  ---------- for csLight ----------
 */
#define LIGHT_DATA              \
    NODE_DATA                   \
    int on;                     \
    float32 intensity;          \
    float32 ambientIntensity;   \
    float32 color[3];

typedef struct {
    LIGHT_DATA
} light_t;

/*
 *  ---------- for csDirectionalLight ----------
 */

#define DIRECTIONAL_LIGHT_DATA  \
    LIGHT_DATA                  \
    float32 direction[3];

typedef struct {
    DIRECTIONAL_LIGHT_DATA
} directional_light_t;


/*
 *  ---------- for csPointLight ----------
 */

#define POINT_LIGHT_DATA        \
    LIGHT_DATA                  \
    float32 location[3];        \
    float32 radius;             \
    float32 attenuation[3];

typedef struct {
    POINT_LIGHT_DATA
} point_light_t;


/*
 *  ---------- for csSpotLight ----------
 */

#define SPOT_LIGHT_DATA         \
    POINT_LIGHT_DATA            \
    float32 direction[3];       \
    float32 exponent;           \
    float32 cutOffAngle;

typedef struct {
    SPOT_LIGHT_DATA
} spot_light_t;


/*
 *  ---------- for csFog ------------
 */

#define FOG_DATA                \
    NODE_DATA                   \
    int on;                     \
    int mode;                   \
    float32 density;            \
    float32 start;              \
    float32 end;                \
    float32 index;              \
    float32 color[4];

typedef struct {
    FOG_DATA
} fog_t;

static const int fgm_table[] =          /* fog mode */
{3,
/*
    (int)csFog::LINEAR_FOG,
    (int)csFog::EXP_FOG,
    (int)csFog::EXP2_FOG,
*/
};



/*
 *  ---------- for all csNode types ----------
 */
#define N_GROUP			0
#define N_SHAPE			1
#define N_SWITCH		2
#define N_TRANSFORM		3
#define N_LOD			4
#define N_BILLBOARD		5
#define N_ENVIRONMENT           6
#define N_DIRECTIONAL_LIGHT     7
#define N_POINT_LIGHT           8
#define N_SPOT_LIGHT            9
#define N_FOG                   10
#define N_NUMNODE_TYPE  	11

typedef union {
    node_t node;
    group_t group;
    transform_t transform;
    transform_894_t transform_894;
    switch_t swtch;
    shape_t shape;
    cslod_t cslod;
    billboard_t billboard;
    environment_t environment;
    light_t light;
    directional_light_t directional_light;
    point_light_t point_light;
    spot_light_t spot_light;
    fog_t fog;
} all_nodes_t;


/*
 *  ---------- for csGeometry ----------
 */

#define GEOMETRY_DATA	\
    CONTAINER_DATA	\
    int32 bound_mode;	\
    int32 box_bound;

static const int gbm_table[] =		/* geometry bound mode */
{2,
    PFBOUND_STATIC,
    PFBOUND_DYNAMIC,
};

typedef struct {
    int32 list_id;
    int32 list_item;
} geometry_ref_t;

typedef struct {
    GEOMETRY_DATA
} geometry_t;


/*
 *  ---------- for csBox ----------
 */

#define BOX_DATA	\
    GEOMETRY_DATA	\
    float32 size[3];	\
    float32 center[3];

typedef struct {
    BOX_DATA
} box_t;


/*
 *  ---------- for csCone ----------
 */

#define CONE_DATA		\
    GEOMETRY_DATA		\
    float32 bottom_radius;	\
    float32 height;		\
    int32 side;			\
    int32 bottom;		\
    float32 center[3];

typedef struct {
    CONE_DATA
} cone_t;


/*
 *  ---------- for csCylinder ----------
 */

#define CYLINDER_DATA	\
    GEOMETRY_DATA	\
    float32 radius;	\
    float32 height;	\
    int32 side;		\
    int32 top;		\
    int32 bottom;	\
    float32 center[3];

typedef struct {
    CYLINDER_DATA
} cylinder_t;


/*
 *  ---------- for csSphere ----------
 */

#define SPHERE_DATA	\
    GEOMETRY_DATA	\
    float32 radius;	\
    float32 center[3];

typedef struct {
    SPHERE_DATA
} sphere_t;


/*
 *  ---------- for csSprite ----------
 */

#define SPRITE_DATA		\
    GEOMETRY_DATA		\
    float32 bottom_left[3];	\
    float32 top_right[3];	\
    float32 position[3];	\
    float32 normal[3];		\
    float32 axis[3];		\
    int32 mode;

static const int32 spm_table[] =		/* sprite mode */
{3,
    PFBB_AXIAL_ROT,
    PFBB_POINT_ROT_EYE,
    PFBB_POINT_ROT_WORLD,
};

typedef struct {
    SPRITE_DATA
} sprite_t;


/*
 *  ---------- for csGeoSet ----------
 */

#define GEOSET_DATA		\
    GEOMETRY_DATA		\
    int32 prim_count;		\
    int32 normal_bind;		\
    int32 color_bind;		\
    int32 tex_coord_bind;	\
    int32 coords;		\
    int32 normals;		\
    int32 colors;		\
    int32 tex_coords;		\
    int32 coord_index;		\
    int32 normal_index;		\
    int32 color_index;		\
    int32 tex_coord_index;	\
    int32 cull_face;

static const int gnb_table[] =		/* geoset normal bind */
{4,
    PFGS_OFF,
    PFGS_OVERALL,
    PFGS_PER_PRIM,
    PFGS_PER_VERTEX, 
};

static const int gcb_table[] =		/* geoset color bind */
{4,
    PFGS_OFF,
    PFGS_OVERALL,
    PFGS_PER_PRIM,
    PFGS_PER_VERTEX,
};

static const int gtb_table[] =		/* geoset tex coord bind */
{2,
    PFGS_OFF,
    PFGS_PER_VERTEX,
};

static const int ccf_table[] =		/* context cull face */
{2,
    //(int)csContext::NO_CULL,
    //(int)csContext::FRONT_CULL,
    //(int)csContext::BACK_CULL,
    //(int)csContext::BOTH_CULL,
};

typedef struct {
    GEOSET_DATA
} geoset_t;


/*
 *  ---------- for csLineSet ----------
 */

#define LINESET_DATA		\
    GEOSET_DATA			\
    float32 width;

typedef struct {
    LINESET_DATA
} lineset_t;


/*
 *  ---------- for csLineStripSet ----------
 */

#define LINESTRIPSET_DATA	\
    GEOSET_DATA			\
    float32 width;		\
    int32 num_lengths;

typedef struct {
    LINESTRIPSET_DATA
} linestripset_t;


/*
 *  ---------- for csPointSet ----------
 */

#define POINTSET_DATA		\
    GEOSET_DATA			\
    float32 size;

typedef struct {
    POINTSET_DATA
} pointset_t;


/*
 *  ---------- for csPolySet ----------
 */

#define POLYSET_DATA		\
    GEOSET_DATA			\
    int32 num_lengths;

typedef struct {
    POLYSET_DATA
} polyset_t;


/*
 *  ---------- for csQuadSet ----------
 */

#define QUADSET_DATA		\
    GEOSET_DATA

typedef struct {
    QUADSET_DATA
} quadset_t;


/*
 *  ---------- for csTriSet ----------
 */

#define TRISET_DATA		\
    GEOSET_DATA

typedef struct {
    TRISET_DATA
} triset_t;


/*
 *  ---------- for csTriStripSet ----------
 */

#define TRISTRIPSET_DATA	\
    GEOSET_DATA			\
    int32 num_lengths;

typedef struct {
    TRISTRIPSET_DATA
} tristripset_t;


/*
 *  ---------- for csTriFanSet ----------
 */

#define TRIFANSET_DATA	\
    GEOSET_DATA			\
    int32 num_lengths;

typedef struct {
    TRIFANSET_DATA
} trifanset_t;


/*
 *  -- for csCoordSet, csColorSet, csNormalSet, csTexCoordSet, and csIndexSet -
 */

#define ARRAYSET_DATA		\
    CONTAINER_DATA		\
    int32 array_type;		\
    int32 size;			\
    int32 count;

#define ARRAY_TYPE_UNKNOWN	-1
#define ARRAY_TYPE_1F		 0
#define ARRAY_TYPE_2F		 1
#define ARRAY_TYPE_3F		 2
#define ARRAY_TYPE_4F		 3
#define ARRAY_TYPE_1I		 4
#define ARRAY_TYPE_2I		 5
#define ARRAY_TYPE_3I		 6
#define ARRAY_TYPE_4I		 7
#define ARRAY_TYPE_1S		 9
#define ARRAY_TYPE_2S		10
#define ARRAY_TYPE_3S		11
#define ARRAY_TYPE_4S		12

typedef struct {
    ARRAYSET_DATA
} arrayset_t;


/*
 *  ---------- for csAppearance ----------
 */

// csAppearance data stored in CSB prior to version -995
#define APPEARANCE_DATA_A_32    \
    CONTAINER_DATA              \
    unsigned int inherit;

#define APPEARANCE_DATA_A_64    \
    CONTAINER_DATA              \
    int64 inherit;

#define APPEARANCE_DATA_B       \
    int tex;                    \
    int tex_enable;             \
    int tex_mode;               \
    float32 tex_bcolor[4];      \
    int tenv;                   \
    int tgen;                   \
    int tgen_enable;            \
    int mtl;                    \
    int light_enable;           \
    int shade_model;            \
    int transp_enable;          \
    int transp_mode;            \
    int alpha_func;             \
    float32 alpha_ref;          \
    float32 bcolor[4];          \
    int src_bfunc;              \
    int dst_bfunc;              \

#define APPEARANCE_DATA_C_1     \
    uint8 color_mask[4];        

#define APPEARANCE_DATA_C_2     \
    unsigned int color_mask[4]; 

#define APPEARANCE_DATA_D       \
    int depth_func;             \
    unsigned int depth_mask;    \
    int fog_enable;             \
    int poly_mode;

#define APPEARANCE_DATA_E       \
    int line_stipple_pattern;   \
    int line_stipple_factor;    \
    float32 tex_transform[16];  \
    int back_mtl;

#define APPEARANCE_DATA_F	\
    int     depth_enable;       \

// csAppearance data added with versions -895 and -894
#define APPEARANCE_DATA_G	\
    int     fog_mode;           \
    float32 fog_density;        \
    float32 fog_start;          \
    float32 fog_end;            \
    float32 fog_index;          \
    float32 fog_color[4];

// csAppearance data added with version -893
#define APPEARANCE_DATA_H       \
    int     material_mode_enable;

// csAppearance data stored in CSB prior to version -995
#define APPEARANCE_DATA_996     \
    APPEARANCE_DATA_A_32        \
    APPEARANCE_DATA_B           \
    APPEARANCE_DATA_C_1         \
    APPEARANCE_DATA_D

// csAppearance data stored in CSB prior to version -990
#define APPEARANCE_DATA_991     \
    APPEARANCE_DATA_A_32        \
    APPEARANCE_DATA_B           \
    APPEARANCE_DATA_C_2         \
    APPEARANCE_DATA_D

// csAppearance data stored in CSB prior to version -895
#define APPEARANCE_DATA_896     \
    APPEARANCE_DATA_991         \
    APPEARANCE_DATA_E

// csAppearance data stored in CSB prior to version -894
#define APPEARANCE_DATA_895     \
    APPEARANCE_DATA_896         \
    APPEARANCE_DATA_F

// csAppearance data stored in CSB prior to version -893
#define APPEARANCE_DATA_894     \
    APPEARANCE_DATA_A_64        \
    APPEARANCE_DATA_B           \
    APPEARANCE_DATA_C_2         \
    APPEARANCE_DATA_D           \
    APPEARANCE_DATA_E           \
    APPEARANCE_DATA_F		\
    APPEARANCE_DATA_G

// csAppearance data stored in CSB prior to version -890
#define APPEARANCE_DATA_893     \
    APPEARANCE_DATA_894         \
    APPEARANCE_DATA_H

// current csAppearance data stored in CSB
// note fog data is removed (appearance_data_g)
#define APPEARANCE_DATA         \
    APPEARANCE_DATA_A_64        \
    APPEARANCE_DATA_B           \
    APPEARANCE_DATA_C_2         \
    APPEARANCE_DATA_D           \
    APPEARANCE_DATA_E           \
    APPEARANCE_DATA_F		\
    APPEARANCE_DATA_H


static const int ctxm_table[] =		/* context.tex_mode */
{4,
    //(int)csContext::FAST_TEX,
    //(int)csContext::NICE_TEX,
    //(int)csContext::NON_PERSP_TEX,
    //(int)csContext::PERSP_TEX,
};

static const int cte_table[] =		/* context.tenv */
{5,
    PFTE_MODULATE,
    PFTE_BLEND,
    PFTE_REPLACE,
    PFTE_ADD,
    PFTE_DECAL,
};

static const int csm_table[] =		/* context.shade_model */
{2,
    PFSM_FLAT,
    PFSM_GOURAUD,
};

static const int ctrm_table[] =		/* context.transp_mode */
{4,
    PFTR_FAST,                  // csContext::FAST_TRANSP
    PFTR_HIGH_QUALITY,          // csContext::NICE_TRANSP
    PFTR_BLEND_ALPHA,           // csContext::BLEND_TRANSP
    PFTR_FAST,                  // csContext::SCREEN_DOOR_TRANSP
};

static const int caf_table[] =		/* context.alpha_func */
{8,
    PFAF_NEVER,
    PFAF_LESS,
    PFAF_EQUAL,
    PFAF_LEQUAL,
    PFAF_GREATER,
    PFAF_NOTEQUAL,
    PFAF_GEQUAL,
    PFAF_ALWAYS,
};


static const int csbf_table[] =		/* context.src_bfunc */
{9,
    //(int)csContext::ZERO_SBLEND,
    //(int)csContext::ONE_SBLEND,
    //(int)csContext::DST_COLOR_SBLEND,
    //(int)csContext::ONE_MINUS_DST_COLOR_SBLEND,
    //(int)csContext::SRC_ALPHA_SATURATE_SBLEND,
    //(int)csContext::SRC_ALPHA_SBLEND,
    //(int)csContext::ONE_MINUS_SRC_ALPHA_SBLEND,
    //(int)csContext::DST_ALPHA_SBLEND,
    //(int)csContext::ONE_MINUS_DST_ALPHA_SBLEND,
};

static const int cdbf_table[] =		/* context.dst_bfunc */
{8,
    //(int)csContext::ZERO_DBLEND,
    //(int)csContext::ONE_DBLEND,
    //(int)csContext::SRC_COLOR_DBLEND,
    //(int)csContext::ONE_MINUS_SRC_COLOR_DBLEND,
    //(int)csContext::SRC_ALPHA_DBLEND,
    //(int)csContext::ONE_MINUS_SRC_ALPHA_DBLEND,
    //(int)csContext::DST_ALPHA_DBLEND,
    //(int)csContext::ONE_MINUS_DST_ALPHA_DBLEND,
};

static const int cdf_table[] =		/* context.depth_func */
{8,
    //(int)csContext::NEVER_DFUNC,
    //(int)csContext::LESS_DFUNC,
    //(int)csContext::EQUAL_DFUNC,
    //(int)csContext::LEQUAL_DFUNC,
    //(int)csContext::GREATER_DFUNC,
    //(int)csContext::NOTEQUAL_DFUNC,
    //(int)csContext::GEQUAL_DFUNC,
    //(int)csContext::ALWAYS_DFUNC,
};

static const int cpm_table[] =		/* context.poly_mode */
{3,
    PFGS_POINTS,                   //POINT_PMODE,
    PFSTATE_ENWIREFRAME,           // Line mode
    PF_OFF,                              //(int)csContext::FILL_PMODE,
};

static const int cmm_table[] =          /* context.material_mode */
{2,
    //(int)csContext::NO_COLOR_MATERIAL,
    //(int)csContext::COLOR_MATERIAL,
};

#define NO_COLOR_MATERIAL 	1
#define COLOR_MATERIAL 		2


typedef struct {
    APPEARANCE_DATA
} appearance_t;

typedef struct {
    APPEARANCE_DATA_893
} appearance893_t;

typedef struct {
    APPEARANCE_DATA_894
} appearance894_t;

typedef struct {
    APPEARANCE_DATA_895
} appearance895_t;

typedef struct {
    APPEARANCE_DATA_896
} appearance896_t;

typedef struct {
    APPEARANCE_DATA_991
} appearance991_t;

typedef struct {
    APPEARANCE_DATA_996
} appearance996_t;


/*
 *  ---------- for csMaterial ----------
 */
#define MATERIAL_DATA		\
    CONTAINER_DATA		\
    float32 ambient[3];		\
    float32 diffuse[3];		\
    float32 specular[3];	\
    float32 emissive[3];	\
    float32 shininess;		\
    float32 transparency;	\
    int32 ambient_index;	\
    int32 diffuse_index;	\
    int32 specular_index;

typedef struct {
    MATERIAL_DATA
} material_t;


/*
 *  ---------- for csTexture ----------
 */
#define TEXTURE_DATA		\
    CONTAINER_DATA		\
    int32 file_name_size;	\
    int32 format;		\
    int32 repeat_s;		\
    int32 repeat_t;		\
    int32 min_filter;		\
    int32 mag_filter;

static const int32 txmnf_table[] =		/* texture.min_filter */
{3,
    PFTEX_POINT,
    PFTEX_LINEAR,
    PFTEX_MIPMAP,
};

static const int32 txmgf_table[] =		/* texture.mag_filter */
{2,
    PFTEX_POINT,
    PFTEX_LINEAR,
};

static const int32 txr_table[] =		/* texture.repeat */
{2,
    PFTEX_CLAMP,
    PFTEX_REPEAT,
};


static const int32 txf_table[] =		/* texture.format */
{45,
    PFTEX_LUMINANCE,         //  1(int32)csTexture::LUMINANCE,
    PFTEX_LUMINANCE_ALPHA,   //  2(int32)csTexture::LUMINANCE_ALPHA,
    PFTEX_RGB_5,             //  3(int32)csTexture::RGB,
    PFTEX_RGBA_4,            //  4(int32)csTexture::RGBA
    PFTEX_PACK_8,             // 5(int32)csTexture::TEXEL8,         /* PFTEX_PACK8 */
    PFTEX_PACK_16,            // 6(int32)csTexture::TEXEL16,
    PFTEX_UNSIGNED_INT,      // 7(int32)csTexture::TEXEL32,
    PFTEX_LUMINANCE,         // 8(int32)csTexture::LUMINANCE,	// PFTEX/* COLOR_INDEX, */
    PFTEX_LUMINANCE,         // 9(int32)csTexture::LUMINANCE,	/* COLOR_INDEX4, */
    PFTEX_LUMINANCE,         // 10(int32)csTexture::LUMINANCE,	/* COLOR_INDEX8, */
    PFTEX_LUMINANCE,         // 11(int32)csTexture::LUMINANCE,	/* COLOR_INDEX12, */
    PFTEX_LUMINANCE,         // 12(int32)csTexture::LUMINANCE,	/* COLOR_INDEX16, */
#ifdef OPENGL_EXTENSIONS
    GL_ALPHA4_EXT,            // 13(int32)csTexture::ALPHA4,
    GL_ALPHA8_EXT,            // 14(int32)csTexture::ALPHA8,
    GL_ALPHA12_EXT,           // 15(int32)csTexture::ALPHA12,
    GL_ALPHA16_EXT,           // 16(int32)csTexture::ALPHA16,
    GL_LUMINANCE4_EXT,               // 17 (int32)csTexture::LUMINANCE4,
    PFTEX_I_8,               // 18(int32)csTexture::LUMINANCE8,             /* PFTEX_I_8 */
    GL_LUMINANCE12_EXT,              //19(int32)csTexture::LUMINANCE12,
    PFTEX_I_16,              //20(int32)csTexture::LUMINANCE16,            /* PFTEX_I_16 */
    GL_LUMINANCE4_ALPHA4_EXT,    //21(int32)csTexture::LUMINANCE4_ALPHA4,
    GL_LUMINANCE6_ALPHA2_EXT,    //22(int32)csTexture::LUMINANCE6_ALPHA2,
    PFTEX_IA_8,              //23(int32)csTexture::LUMINANCE8_ALPHA8,      /* PFTEX_IA_8 */
    PFTEX_I_12A_4,           //24(int32)csTexture::LUMINANCE12_ALPHA4,     /* PFTEX_I_12A_4 */
    PFTEX_IA_12,             //25(int32)csTexture::LUMINANCE12_ALPHA12,    /* PFTEX_IA_12 */
    GL_LUMINANCE16_ALPHA16_EXT,   //26(int32)csTexture::LUMINANCE16_ALPHA16,
    PFTEX_I_8,               //27(int32)csTexture::INTENSITY,
    GL_INTENSITY4_EXT,               //28(int32)csTexture::INTENSITY4,
    PFTEX_I_8,               //29(int32)csTexture::INTENSITY8,
    GL_INTENSITY12_EXT,              //30(int32)csTexture::INTENSITY12,
    PFTEX_I_16,              //31(int32)csTexture::INTENSITY16,
    GL_RGB2_EXT,               //32(int32)csTexture::RGB2,
    PFTEX_RGB_4,               //33(int32)csTexture::RGB4,             /* PFTEX_RGB_4 */
    PFTEX_RGB_5,               //34(int32)csTexture::RGB5,             /* PFTEX_RGB_5 */
    PFTEX_RGB_8,               //35(int32)csTexture::RGB8,
    GL_RGB10_EXT,              //36(int32)csTexture::RGB10,
    PFTEX_RGB_12,              //37(int32)csTexture::RGB12,            /* PFTEX_RGB_12 */
    GL_RGB16_EXT,              //38(int32)csTexture::RGB16,
    GL_RGBA2_EXT,              //39(int32)csTexture::RGBA2,
    PFTEX_RGBA_4,              //40(int32)csTexture::RGBA4,           /* PFTEX_RGBA_4 */
    PFTEX_RGB5_A1,             //41(int32)csTexture::RGB5_A1,         /* PFTEX_RGB5_A1 */
    PFTEX_RGBA_8,              //42(int32)csTexture::RGBA8,           /* PFTEX_RGBA_8 */
    GL_RGB10_A2_EXT,           //43(int32)csTexture::RGB10_A2,
    PFTEX_RGBA_12,             //44(int32)csTexture::RGBA12,
    GL_RGBA16_EXT,             //45(int32)csTexture::RGBA16,
#else
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,    /* ALPHA4, */
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,	/* ALPHA8, */
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,	/* ALPHA12, */
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,	/* ALPHA16, */
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,	/* LUMINANCE4, */
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,	/* LUMINANCE8, */
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,	/* LUMINANCE12, */
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,	/* LUMINANCE16, */
    PFTEX_LUMINANCE_ALPHA,    //(int32)csTexture::LUMINANCE_ALPHA,	/* LUMINANCE4_ALPHA4, */
    PFTEX_LUMINANCE_ALPHA,    //(int32)csTexture::LUMINANCE_ALPHA,	/* LUMINANCE6_ALPHA2, */
    PFTEX_LUMINANCE_ALPHA,    //(int32)csTexture::LUMINANCE_ALPHA,	/* LUMINANCE8_ALPHA8, */
    PFTEX_LUMINANCE_ALPHA,    //(int32)csTexture::LUMINANCE_ALPHA,	/* LUMINANCE12_ALPHA4, */
    PFTEX_LUMINANCE_ALPHA,    //(int32)csTexture::LUMINANCE_ALPHA,	/* LUMINANCE12_ALPHA12, */
    PFTEX_LUMINANCE_ALPHA,    //(int32)csTexture::LUMINANCE_ALPHA,	/* LUMINANCE16_ALPHA16, */
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,	/* INTENSITY, */
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,	/* INTENSITY4, */
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,	/* INTENSITY8, */
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,	/* INTENSITY12, */
    PFTEX_LUMINANCE,          //(int32)csTexture::LUMINANCE,	/* INTENSITY16, */
    PFTEX_RGB,                //(int32)csTexture::RGB,		/* RGB2, */
    PFTEX_RGB,                //(int32)csTexture::RGB,		/* RGB4, */
    PFTEX_RGB,                //(int32)csTexture::RGB,		/* RGB5, */
    PFTEX_RGB,                //(int32)csTexture::RGB,		/* RGB8, */
    PFTEX_RGB,                //(int32)csTexture::RGB,		/* RGB10, */
    PFTEX_RGB,                //(int32)csTexture::RGB,		/* RGB12, */
    PFTEX_RGB,                //(int32)csTexture::RGB,		/* RGB16, */
    PFTEX_RGBA,               //(int32)csTexture::RGBA,		/* RGBA2, */
    PFTEX_RGBA,               //(int32)csTexture::RGBA,		/* RGBA4, */
    PFTEX_RGBA,               //(int32)csTexture::RGBA,		/* RGB5_A1, */
    PFTEX_RGBA,               //(int32)csTexture::RGBA,		/* RGBA8, */
    PFTEX_RGBA,               //(int32)csTexture::RGBA,		/* RGB10_A2, */
    PFTEX_RGBA,               //(int32)csTexture::RGBA,		/* RGBA12, */
    PFTEX_RGBA,               //(int32)csTexture::RGBA,		/* RGBA16, */
#endif
};

typedef struct {
    TEXTURE_DATA
} texture_t;


/*
 *  ---------- for csTexGen ----------
 */
#define TEXGEN_DATA		\
    CONTAINER_DATA		\
    int32 mode_s;		\
    int32 mode_t;		\
    int32 mode_r;		\
    int32 mode_q;		\
    float32 plane_s[4];		\
    float32 plane_t[4];		\
    float32 plane_r[4];		\
    float32 plane_q[4];

static const int32 tgm_table[] =		/* texgen.mode */
{5,
    PFTG_OFF,
    PFTG_EYE_LINEAR,
    PFTG_EYE_LINEAR_IDENT,
    PFTG_OBJECT_LINEAR,
    PFTG_SPHERE_MAP,
};

typedef struct {
    TEXGEN_DATA
} texgen_t;


/*
 *  ---------- for csEngine ----------
 */

typedef struct {
    int list_id;
    int list_item;
} engine_ref_t;


/*
 *  ------ for csInterpolator -------
 */

#define INTERPOLATOR_DATA       \
    CONTAINER_DATA              \
    float32 fraction;           \
    int num_keys;               \
    int num_keyValues;


typedef struct {
    INTERPOLATOR_DATA
} interpolator_t;


/*
 *  ---- for csMorphEng -----
 */

#define MORPHENG_DATA           \
    CONTAINER_DATA              \
    int num_counts;             \
    int num_indices;            \
    int num_weights;            \
    int num_inputs;

typedef struct {
    MORPHENG_DATA
} morpheng_t;

/*
 *  ---- for csSelectorEng -----
 */

#define SELECTENG_DATA          \
    CONTAINER_DATA              \
    int selector;               \
    int num_inputs;

typedef struct {
    SELECTENG_DATA
} selecteng_t;


/*
 *  ---- for csTransformEng -----
 */

#define TRANSENG_DATA           \
    CONTAINER_DATA              \
    int transform_type; \
    int num_counts;             \
    int num_indices;            \
    int num_matrices;           \
    int num_inputs;

typedef struct {
    TRANSENG_DATA
} transeng_t;

/*
static const int tet_table[] =         // transformeng.transform_type 
{2,
    (int)csTransformEng::POINT,
    (int)csTransformEng::VECTOR,
};
*/


/*
 *  -------- for csSpline ---------
 */

#define SPLINE_DATA             \
    CONTAINER_DATA              \
    float32 fraction;           \
    float32 basis[16];          \
    int num_keys;

typedef struct {
    SPLINE_DATA
} spline_t;


/*
 *  -------- for csTimeSensor ---------
 */

#define TIMESENSOR_DATA         \
    CONTAINER_DATA              \
    float64 cycle_interval;     \
    int enabled;                \
    int loop;                   \
    float64 start_time;         \
    float64 stop_time;

typedef struct {
    TIMESENSOR_DATA
} timesensor_t;


/*
 *  Maps Container to list/index
 */
typedef struct {
    int32	which_list;
    int32	index;
} ctr_ref_t;


/*
 * Field connection record
 */
typedef struct {
    ctr_ref_t	*from_ctr;
    int16	from_field;
    void	*to_ctr;   // csContainer	*to_ctr; to void AS
    int16	to_field;
} connection_t;


/*
 *  lists
 */
#define L_MTL		 0
#define L_TEX		 1
#define L_TEXGEN	 2
#define L_APP		 3
#define L_VSET		 4
#define L_CSET		 5
#define L_NSET		 6
#define L_TSET		 7
#define L_ISET		 8
#define L_LINESET	 9
#define L_LINESTRIPSET	10
#define L_POINTSET	11
#define L_POLYSET	12
#define L_QUADSET	13
#define L_TRISET	14
#define L_TRISTRIPSET	15
#define L_GEOM		16
#define L_NODE		17
#define L_BOX		18
#define L_CONE		19
#define L_CYLINDER	20
#define L_SPHERE	21
#define L_SPRITE	22
#define L_TRIFANSET	23
#define L_TRANSFORM	24
#define L_CUSTOM	25	// For custom classes derived from csNode
#define L_CONNECTIONS	26	// List of connections between fields
#define L_ENGINE        27
#define L_NORMINTERP    28
#define L_ORIENTINTERP  29
#define L_POSINTERP     30
#define L_SCALARINTERP  31
#define L_COLORINTERP   32
#define L_COORDINTERP   33
#define L_MORPHENG3F    34
#define L_MORPHENG4F    35
#define L_SELECTENG3F   36
#define L_SELECTENG4F   37
#define L_TRANSENG3F    38
#define L_SPLINE        39
#define L_TIMESENSOR    40
// L_COUNT == 41 in csCsb.h
#define L_EOF		-1


// class local to file

#define CSD_DUMMY_TYPE 	(csType *)-1
#define CSD_CUSTOMNAME	 32


class csdCustomObject
{
   public:
      csdCustomObject(pfType *_type, const char *_name,
                        csdDescendCustomObjFuncType_csb _descend_func,
                        csdStoreCustomObjFuncType_csb _store_func,
                        csdNewCustomObjFuncType_csb _new_func,
                        csdLoadCustomObjFuncType_csb _load_func);
      ~csdCustomObject(void) {};
      void addCustomObject(csdCustomObject *);
      csdCustomObject *findCustomObject(const char *name);
      csdCustomObject *findCustomObject(pfType *type);
      csdDescendCustomObjFuncType_csb descend_func;
      csdStoreCustomObjFuncType_csb store_func;
      csdNewCustomObjFuncType_csb new_func;
      csdLoadCustomObjFuncType_csb load_func;
      pfType *getType(void);

   private:
      pfType *type;
      char name[CSD_CUSTOMNAME];
      csdCustomObject *next;   // For linked list, later use binary tree
};

// GLOBALS

static csdCustomObject  *headCustomList = NULL;

// LOCAL FUNCTIONS

static int32 *set_buf_size(int size, csdFile_csb *csb);
void mask_to_bitmask(unsigned int mask, int64* bm);
void mask_to_bitmask64(int endian_flip, int64 mask, int64* bm);
void endian_flip(void *buf, size_t size);
size_t endian_fread(void *ptr, size_t size, size_t nitems, FILE *stream);
static void load_csb(csdFile_csb *csb);
static void free_load_csb(csdFile_csb *csb);
static void free_list( int list_id, csdFile_csb *csb );

   // Load functions
   
static pfMaterial *load_mtl(int id, csdFile_csb *csb);
static pfTexture *load_tex(int id, csdFile_csb *csb);
static pfTexGen *load_texgen(int id, csdFile_csb *csb);
static pfGeoState *load_appearance(int id, csdFile_csb *csb);
static pfVec3 *load_vset(int id, csdFile_csb *csb);
static pfVec4 *load_cset(int id, csdFile_csb *csb);
static pfVec3 *load_nset(int id, csdFile_csb *csb);
static void *load_tset(int id, csdFile_csb *csb);
static int32 *load_iset(int id, csdFile_csb *csb);
static void     load_bpc_data(pfGeoSet *gset, csdFile_csb *csb);
static pfGeoSet *load_lineset(int id, csdFile_csb *csb);
static pfGeoSet *load_linestripset(int id, csdFile_csb *csb);
static pfGeoSet *load_pointset(int id, csdFile_csb *csb);
static pfGeoSet *load_polyset(int id, csdFile_csb *csb);
static pfGeoSet *load_quadset(int id, csdFile_csb *csb);
static pfGeoSet *load_triset(int id, csdFile_csb *csb);
static pfGeoSet *load_tristripset(int id, csdFile_csb *csb);
static void *load_geometry(int id, csdFile_csb *csb);
static void *load_engine(int id, csdFile_csb *csb);
static void *load_norminterp(int id, csdFile_csb *csb);
static void *load_orientinterp(int id, csdFile_csb *csb);
static void *load_posinterp(int id, csdFile_csb *csb);
static void *load_scalarinterp(int id, csdFile_csb *csb);
static void *load_colorinterp(int id, csdFile_csb *csb);
static void *load_coordinterp(int id, csdFile_csb *csb);
static void *load_morpheng3f(int id, csdFile_csb *csb);
static void *load_morpheng4f(int id, csdFile_csb *csb);
static void *load_selecteng3f(int id, csdFile_csb *csb);
static void *load_selecteng4f(int id, csdFile_csb *csb);
static void *load_transeng3f(int id, csdFile_csb *csb);
static void *load_spline(int id, csdFile_csb *csb);
static void *load_timesensor(int id, csdFile_csb *csb);
static pfNode *load_node(int id, csdFile_csb *csb);
static pfGeoSet *load_box(int id, csdFile_csb *csb);
static pfGeoSet *load_cone(int id, csdFile_csb *csb);
static pfGeoSet *load_cylinder(int id, csdFile_csb *csb);
static pfGeoSet *load_sphere(int id, csdFile_csb *csb);
static pfBillboard *load_sprite(int id, csdFile_csb *csb);
static pfGeoSet *load_trifanset(int id, csdFile_csb *csb);
static void *load_connection(int id, csdFile_csb *csb);

   // Load helper functions
static void load_name(void *container, int name_size, csdFile_csb *csb);
static void load_node_name(pfNode *node, int name_size, csdFile_csb *csb);
static void set_geoset_data( pfGeoSet *gset,  geoset_t *g,  csdFile_csb *csb);
static void set_node_data(pfNode *node, node_t *g, csdFile_csb *csb);
static void fix_tristrip_normals( pfGeoSet *gset,  csdFile_csb *csb  );
static void convert_to_flat_shade( pfGeoSet *gset, csdFile_csb *csb  );
static void fix_linestrip_normals( pfGeoSet *gset,  csdFile_csb *csb  );
static void produceClearCoat(pfTexture* tex, float index, float contrastScale, float contrastBias);

// node loader stuff
static pfGroup *pfGroup_new(void);
static void csdLoadGroupInfo(void *obj, all_nodes_t *n, int structsize, csdFile_csb *csb);
static int pfGroup_load(void *obj, csdFile_csb *csb);
static pfDCS *pfDCS_new(void);
static void csdLoadTransformInfo(void *obj, all_nodes_t *n,int structsize,csdFile_csb *csb);
static int csTransform_load(void *obj, csdFile_csb *csb);
static pfSwitch *pfSwitch_new(void);
static void csdLoadSwitchInfo(void *node, all_nodes_t *n, int structsize,csdFile_csb *csb);
static int csSwitch_load(void *obj, csdFile_csb *csb);
static pfLOD *pfLOD_new(void);
static void csdLoadLODInfo(void *node, all_nodes_t *n, int structsize,csdFile_csb *csb);
static int csLOD_load(void *obj, csdFile_csb *csb);
static pfGeode *pfGeode_new(void);
int csShape_load(void *obj, csdFile_csb *csb);
static int csEnvironment_load(void *obj, csdFile_csb *csb);
static int csBillboard_load(void *obj, csdFile_csb *csb);
static int csPointLight_load(void *obj, csdFile_csb *csb);
static int csSpotLight_load(void *obj, csdFile_csb *csb);
static int csDirectionalLight_load(void *obj, csdFile_csb *csb);
static int csFog_load(void *obj, csdFile_csb *csb);
static void csRegisterTypes();

   // debug functions
static void print_gset_data( geoset_t *g );
static void print_appearance_data ( appearance_t *a );
static void print_material( material_t *m );
static void print_lod( cslod_t *l );

   // load function table
   
static void *(*load_func[L_COUNT])(int id, csdFile_csb *csb) =
{
    (void *(*)(int, csdFile_csb *))load_mtl,
    (void *(*)(int, csdFile_csb *))load_tex,
    (void *(*)(int, csdFile_csb *))load_texgen,
    (void *(*)(int, csdFile_csb *))load_appearance,
    (void *(*)(int, csdFile_csb *))load_vset,
    (void *(*)(int, csdFile_csb *))load_cset,
    (void *(*)(int, csdFile_csb *))load_nset,
    (void *(*)(int, csdFile_csb *))load_tset,
    (void *(*)(int, csdFile_csb *))load_iset,
    (void *(*)(int, csdFile_csb *))load_lineset,
    (void *(*)(int, csdFile_csb *))load_linestripset,
    (void *(*)(int, csdFile_csb *))load_pointset,
    (void *(*)(int, csdFile_csb *))load_polyset,
    (void *(*)(int, csdFile_csb *))load_quadset,
    (void *(*)(int, csdFile_csb *))load_triset,
    (void *(*)(int, csdFile_csb *))load_tristripset,
    (void *(*)(int, csdFile_csb *))load_geometry,
    (void *(*)(int, csdFile_csb *))load_node,
    (void *(*)(int, csdFile_csb *))load_box,
    (void *(*)(int, csdFile_csb *))load_cone,
    (void *(*)(int, csdFile_csb *))load_cylinder,
    (void *(*)(int, csdFile_csb *))load_sphere,
    (void *(*)(int, csdFile_csb *))load_sprite,
    (void *(*)(int, csdFile_csb *))load_trifanset,
    NULL,
    NULL,
    (void *(*)(int, csdFile_csb *))load_connection,
    (void *(*)(int, csdFile_csb *))load_engine,
    (void *(*)(int, csdFile_csb *))load_norminterp,
    (void *(*)(int, csdFile_csb *))load_orientinterp,
    (void *(*)(int, csdFile_csb *))load_posinterp,
    (void *(*)(int, csdFile_csb *))load_scalarinterp,
    (void *(*)(int, csdFile_csb *))load_colorinterp,
    (void *(*)(int, csdFile_csb *))load_coordinterp,
    (void *(*)(int, csdFile_csb *))load_morpheng3f,
    (void *(*)(int, csdFile_csb *))load_morpheng4f,
    (void *(*)(int, csdFile_csb *))load_selecteng3f,
    (void *(*)(int, csdFile_csb *))load_selecteng4f,
    (void *(*)(int, csdFile_csb *))load_transeng3f,
    (void *(*)(int, csdFile_csb *))load_spline,
    (void *(*)(int, csdFile_csb *))load_timesensor,
};


/*
 *  #define style psudo functions.
 */
#define GET_BUF(s) (((s) <= csb->buf_size)? csb->buf : set_buf_size((s), csb))

#define COPY3(dst, src)		\
(				\
    (dst)[0] = (src)[0],	\
    (dst)[1] = (src)[1],	\
    (dst)[2] = (src)[2]		\
)

// Load a csb file
pfNode *pfdLoadFile_csb(const char *fileName)
{
    static const char func_name[] = "pfdLoadFile_csb";
    csdFile_csb *csb;
    pfNode *root;
    char path[PF_MAXSTRING];

    csb = (csdFile_csb *)pfMalloc( sizeof(csdFile_csb),  pfGetSharedArena() );
    bzero(csb, sizeof(csdFile_csb));
    csb->func_name = func_name;
    csb->arena = pfGetSharedArena();
    //csb->arena = NULL;

    csRegisterTypes();
    
    /*
     *  Find the csb file.
     */
    
    if( !pfFindFile( fileName,  path, R_OK) )
    {
	pfNotify(PFNFY_WARN, PFNFY_RESOURCE,"%s:  Could not find \"%s\".\n",
		func_name, fileName );
	free(csb);
	return(NULL);
    }

    /*
     *  open the csb file for reading
     */
    if ((csb->fp = fopen(path, "rb")) == NULL)
    {
	pfNotify(PFNFY_WARN, PFNFY_RESOURCE,"%s:  Could not open \"%s\" for reading.\n",
		 func_name, fileName );
	free(csb);
	return(NULL);
    }
    else
    {
	pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "%s:  Loading \"%s\".\n", 
	         func_name, fileName);
    }

    /*
     *  Initialize csb structure.
     */
    set_buf_size(512, csb);

    /*
     *  Load the csb file.
     */
    load_csb(csb);
    root = csb->root;

    /*
     *  Close the csb file.
     */
    fclose(csb->fp);

    /*
     *  Link any remaining parts of the scene graph that needs to be linked
     */
    //link_csb(csb);   // doesn't do anything right now

    /*
     *  Free temporary memory used in loading the csb file.
     */
    free_load_csb(csb);

    return(root);
    
}  // end static void load_csb()


// used in GETBUF(s) macro and pfdLoadFile_csb

static int32 *set_buf_size(int size, csdFile_csb *csb)
{
    if (csb->buf_size < size)
    {
	if (csb->buf)
	    free(csb->buf);
	csb->buf = (int32 *)pfMalloc(size * sizeof(int32), csb->arena);
	csb->buf_size = size;
    }

    return(csb->buf);
    
}   // end set_buf_size()


/*
 * ------------------ misc utilities -------------------
 */

void mask_to_bitmask(unsigned int mask, int64* bm)
{
    int i;

    for (i = 0; i < 32; i++)
    {
        if (mask & (1 << i))
	    *bm |= ((int64)1 << i);
    }
    // upper 32 bits should inherit since CSB file didn't contain these fields
    for (i = 32; i < 64; i++)
	*bm |= ((int64)1 << i);
}


void mask_to_bitmask64(int endian_flip, int64 mask, int64* bm)
{
    if (endian_flip)
    {
        int64 left32, right32;

        // this is a double word so it needs an extra flip
        left32 = mask >> 32;
        right32 = mask && 0xFFFFFFFF;
        *bm = right32 << 32;
        *bm |= left32;
    }
    else
        *bm = mask;
}


void endian_flip(void *buf, size_t size)
{
    char *cbuf;
    int i, offset;
    char a, b;

    cbuf = (char *)buf;

    for (i = 0; (i+4) <= size; i += 4)
    {
	a = cbuf[i];
	b = cbuf[i+1];
	cbuf[i] = cbuf[i+3];
	cbuf[i+1] = cbuf[i+2];
	cbuf[i+2] = b;
	cbuf[i+3] = a;
    }

    if (offset = ((i+4) % 4))
    {
	if (offset == 2)
	{
	   a = cbuf[i];
	   cbuf[i] 	= cbuf[i+1];
	   cbuf[i+1] 	= a;
	} else if (offset == 3)
	{
	   a = cbuf[i];
	   cbuf[i] = cbuf[i+2];
	   cbuf[i+2] = a;
	}
    }
    
}   // end endian_flip()


size_t endian_fread(void *ptr, size_t size, size_t nitems, FILE *stream)
{
    size_t r;

    r = fread(ptr, size, nitems, stream);
    endian_flip((void *)ptr, size * nitems);
    return(r);
    
}   // end endian_fread()


static void load_csb(csdFile_csb *csb)
{
    int32 buf[4];
    int i;

    /*
     *  load header
     */
    fread(buf, sizeof(int32), 4, csb->fp);

    if (buf[0] == CSB_MAGIC_NUMBER_E ||
	buf[0] == CSB_MAGIC_ENCODED_E)
    {
	csb->endian_flip = TRUE;
	CSB_FREAD = endian_fread;
	endian_flip(buf, sizeof(int32) * 4);
    }
    else
	CSB_FREAD = fread;

    if (buf[0] != CSB_MAGIC_NUMBER)
    {
	csb->read_error = TRUE;
	pfNotify(PFNFY_WARN, PFNFY_PRINT,"%s: Unrecognized magic number 0x%08x.\n",
		csb->func_name, buf[0] );
	return;
    }
    csb->version = buf[1];

    if (csb->version < CSB_VERSION_NUMBER)
    {
	pfNotify(PFNFY_WARN, PFNFY_PRINT,"%s: Old version number found %d.\n",
		  csb->func_name, buf[1] );
    }

    /*
     *  load lists
     */
    while (csb->root == NULL && !csb->read_error)
    {
	if (CSB_FREAD(buf, sizeof(int32), 3, csb->fp) != 3)
	{
	    csb->read_error = TRUE;
	    pfNotify(PFNFY_WARN, PFNFY_PRINT, "%s: Unexpected EOF encountered.\n",
		    csb->func_name );
	    return;
	}

	if (buf[0] == L_EOF)
	{
	    if( buf[1] != L_NODE )
	    {
	        csb->read_error = TRUE;
		pfNotify(PFNFY_WARN, PFNFY_PRINT, "%s: Must return a pfNode nota %d .\n",
		    csb->func_name,  buf[1] );
		return;
	    }
	    else
	    {
	        
	       csb->root = (pfNode *)csb->rl_list[buf[1]][buf[2]];
	       #ifdef PRINT_SCENE
	        FILE *fp;
	        fp = fopen("scene.out",  "w" );
	       printf("loaded tree struct \n" );
	       pfPrint(csb->root, (PFTRAV_SELF|PFTRAV_DESCEND),
	                     PFPRINT_VB_DEBUG, fp);
	        fclose(fp);
		#endif
	    }
	}
	else if (buf[0] < L_COUNT) 
	{
            int32 listId;
	    // loading known csObjects, or objects subclassed off csNode
 	    listId = buf[0]; 
	    csb->curListLength = buf[1]; 
	    
	    csb->rl_list[listId] = (void **)pfMalloc(sizeof(void **) *
						     csb->curListLength, 
						     csb->arena);
						     
	    // keep track of the number of items in each list					     
	    csb->l_num[listId] = csb->curListLength;
	    
	    if( listId == L_GEOM )
	    {
		csb->geo_ref = (int32 *)pfMalloc( sizeof(int32)*csb->curListLength, 
		                                   csb->arena );
		for( int k = 0; k < csb->curListLength; k++ )
		{
		    csb->geo_ref[k] = 0;
		}
	    }
	    
	    if( listId == L_ISET )
	    {
		csb->iset_size = (int32 *)pfMalloc( sizeof(int32)*csb->curListLength, 
		                                   csb->arena );
		for( int k = 0; k < csb->curListLength; k++ )
		{
		    csb->iset_size[k] = 0;
		}
	    }

	    if ( listId == L_APP )
	    {
		csb->gstate_mtl_mode = (int32 *)pfMalloc( sizeof(int32)*csb->curListLength, 
		                                   csb->arena );
		for( int k = 0; k < csb->curListLength; k++ )
		{
		    csb->gstate_mtl_mode[k] = 0;
		}
	    }
						       
           // pfNotify( PFNFY_NOTICE, PFNFY_PRINT, "list %d size %d \n",  
	   //          listId,  csb->curListLength );
		     						       
	    for (i = 0; i < csb->curListLength && !csb->read_error; i++)
	    {
               csb->rl_list[listId][i] = load_func[listId](i, csb);
            }
		
	    // L_CONNECTIONS contains NULLs...
	} else
	{
	   pfNotify( PFNFY_WARN,  PFNFY_PRINT,  "Uknown list %d \n", buf[0] );  
	}
	
    }   // end while stuff to read
    
}   // end load_csb()

// used in pfdLoadFile_csb()

static void free_load_csb(csdFile_csb *csb)
{
    // call pfDelete on all vertex, normal, color and tex
    // arrays since if there was apfGeoSet in index mode we may have
    // fltttened them
    
    free_list( L_VSET,  csb );
    free_list( L_CSET,  csb );
    free_list( L_NSET,  csb );
    free_list( L_TSET,  csb );
    
    // free up anything allocated in the csdFile
    
    pfDelete(csb->buf);
    pfDelete(csb->geo_ref );
    pfDelete(csb->iset_size );
    pfDelete(csb->gstate_mtl_mode );
    pfDelete(csb);
    
}  //end free_load_csb


static void free_list( int list_id, csdFile_csb *csb )
{
    for( int i = 0; i < csb->l_num[list_id]; i++ )
    {
	pfDelete( csb->rl_list[list_id][i] );
    }

}   // end free_list()

//--------------------------------------------------------------------------

// Load functions


static pfMaterial *load_mtl(int /*id*/, csdFile_csb *csb)
{
   pfMaterial *mtl;
   material_t m;

   CSB_FREAD(&m, sizeof(material_t), 1, csb->fp);
   //printf("material id = %d \n",  id );
   //print_material( &m );
   
   mtl = new pfMaterial();
   mtl->setColor(PFMTL_AMBIENT,  m.ambient[0], m.ambient[1], m.ambient[2]);
   mtl->setColor(PFMTL_DIFFUSE,  m.diffuse[0], m.diffuse[1], m.diffuse[2]);
   mtl->setColor(PFMTL_SPECULAR, m.specular[0], m.specular[1], m.specular[2]);
   mtl->setColor(PFMTL_EMISSION,  m.emissive[0], m.emissive[1], m.emissive[2]); 
   mtl->setShininess(m.shininess*(1.0f/0.0078125f) );
   
   //convert VRML alpha to perfomer
   mtl->setAlpha(1.0 - m.transparency);
   // fprintf( stderr, "mtl transp = %f\n", m.transparency );

   if( m.name_size != -1 )
   {
       load_name( mtl,  m.name_size,  csb );
   }

   return(mtl);
 
}   // end load_mtl()

static void produceClearCoat(pfTexture *tex, float index, float contrastScale,
	float contrastBias)
{
    static int genInited = FALSE;
    static ClearCoatGenFunc genFunc = NULL;

    if (! genInited) {
	void* dso = dlopen(NULL, RTLD_LAZY);
	genFunc = (ClearCoatGenFunc)dlsym(dso, "generateClearCoat");
	dlclose(dso);
	genInited = TRUE;
    }

    if (genFunc != NULL) {
	double start = pfGetTime();

	int channels;
	int width;
	int height;
	int depth;
	unsigned char *orig_bytes;

	tex->getImage((uint **)&orig_bytes, &channels, &width, &height, &depth);

	if (depth != 1) {
	    pfNotify(PFNFY_WARN, PFNFY_USAGE,
		     "libpfcsb::produceClearCoat: internal error - "
		     "unsupported z (depth) of texture %i", depth);
	    return;
	}

	pfNotify(PFNFY_NOTICE, PFNFY_PRINT,
		 "libpfcsb::produceClearCoat: producing %.2f ClearCoat map "
		 "[%s] (%ix%i)", index, tex->getName(), width, height);
	if ((contrastScale != 1.0f) || (contrastBias != 0.0f))
	    pfNotify(PFNFY_NOTICE, PFNFY_PRINT,
		     "libpfcsb::produceClearCoat: using contrast scale "
		     "%.2f bias %.2f", contrastScale, contrastBias);

	int newchannels;
	int format;
	int pfformat;
	switch ( channels ) {
	case 1:
	    format = GL_LUMINANCE;
	    pfformat = PFTEX_IA_8;
	    newchannels = 2;
	    break;
	case 2:
	    format = GL_LUMINANCE_ALPHA;
	    pfformat = PFTEX_IA_8;
	    newchannels = 2;
	    break;
	case 3:
	    format = GL_RGB;
	    pfformat = PFTEX_RGBA_8;
	    newchannels = 4;
	    break;
	case 4:
	    format = GL_RGBA;
	    pfformat = PFTEX_RGBA_8;
	    newchannels = 4;
	    break;
	default:
	    pfNotify(PFNFY_WARN, PFNFY_USAGE,
		     "libpfcsb::produceClearCoat: internal error - "
		     "unsupported number of channels %i", channels);
	    return;
	} // switch channels

	unsigned char *bytes = (unsigned char *)
	    pfMalloc( width*height*newchannels );

	(*genFunc)(orig_bytes, width, height, format, GL_UNSIGNED_BYTE,
			  bytes, index, contrastScale, contrastBias);

	tex->setImage( (uint *)bytes, newchannels, width, height, depth );
	tex->setFormat(PFTEX_INTERNAL_FORMAT, pfformat);

	double total = pfGetTime() - start;
	pfNotify(PFNFY_NOTICE, PFNFY_PRINT, "ClearCoat calculation took %f "
		"seconds", total);
    } else
	pfNotify(PFNFY_WARN, PFNFY_USAGE,
		"libpfcsb::produceClearCoat: ClearCoat disabled.");
} // end produceClearCoat

static pfTexture *load_tex(int /*id*/, csdFile_csb *csb)
{
    pfTexture *tex;
    texture_t t;
    unsigned int *image2;
    uint *image_ptr;
    int comp;
    int ns,  nt,  nr;
    int            channels;
    int            xRes;
    int            yRes;
#if defined(__linux_has_ifl__) || !defined(__linux__)
    iflStatus      sts;
    iflFile*       file;
    iflSize        dims;
#endif
    char	   filePath[512];
    
    // read texture info and file name
    CSB_FREAD(&t, sizeof(texture_t), 1, csb->fp);
 
    fread((char *)csb->buf, t.file_name_size, 1,  csb->fp);
    ((char *)csb->buf)[t.file_name_size] = '\0';
    
    if (!pfFindFile((char *)csb->buf, filePath, R_OK))
    {
	pfNotify(PFNFY_WARN, PFNFY_RESOURCE,
	    "libpfcsb::load_tex: Could not find file \"%s\"", (char *)csb->buf);
	return NULL;
    }

    tex = new pfTexture();

    // see if we can read the texture
    if (!tex->loadFile(filePath))
    { // else try IFL
#if defined(__linux_has_ifl__) || !defined(__linux__)

	// Ask IFL to do its thing
	file = iflFile::open(filePath, O_RDONLY, &sts );
	if (sts != iflOKAY)
	{
	       pfDelete(tex);
	       return NULL;    
       }
    
  
	// Open the file and find out about it's dimensions
	file->getDimensions(dims);

	channels = dims.c;
	xRes     = dims.x;
	yRes     = dims.y;

	image2 = (unsigned int *)pfMalloc( sizeof(char)*xRes*yRes*channels, csb->arena );
	if( image2 == NULL )
	{
	    pfNotify( PFNFY_WARN,  PFNFY_PRINT, "error pfMalloc() load_tex %s \n",(char *)csb->buf );
	}
		
	pfNotify( PFNFY_INFO, PFNFY_PRINT, 
	       "Reading texture map, %s, %d %d, comp=%d\n",  (char *)csb->buf, xRes, yRes, channels );

	iflConfig cfg(iflUChar, iflInterleaved);
	sts = file->getTile(0, 0, 0, dims.x, dims.y, 1, image2, &cfg);
	if (sts != iflOKAY)
	{
	    pfNotify( PFNFY_WARN,  PFNFY_PRINT, "iflFile::getTile load_tex %s \n",(char *)csb->buf );
	}

	// set the textures image
	tex->setImage( image2,  channels,  xRes,  yRes,  1 );
#else
	pfNotify(PFNFY_WARN, PFNFY_PRINT, "Only .rgb files are supported at this time.\n");
	pfNotify(PFNFY_WARN, PFNFY_PRINT, "Skipping texture: %s\n", filePath);
	return NULL;
#endif
    }
    tex->setName( (char *)csb->buf );
    // for debugging show what we set
    
    tex->getImage( &image_ptr,  &comp,  &ns,  &nt,  &nr );
    pfNotify(PFNFY_INFO,PFNFY_PRINT,
    "tex image %s %p   comp = %d  ns = %d nt = %d nr = %d \n", 
    	tex->getName(), image_ptr,  comp,  ns,  nt,  nr );

    // the format index reported by the csb file is not 
    // makeing any sense, but the default for
    // the tex file is working, so for now rely on the default
    //tex->setFormat(PFTEX_INTERNAL_FORMAT, txf_table[t.format] );
    
    tex->setFormat(PFTEX_EXTERNAL_FORMAT, PFTEX_PACK_8 );
    tex->setRepeat( PFTEX_WRAP_S, txr_table[t.repeat_s] );
    tex->setRepeat( PFTEX_WRAP_T, txr_table[t.repeat_t] );
    tex->setFilter( PFTEX_MINFILTER, txmnf_table[t.min_filter]);
    tex->setFilter( PFTEX_MAGFILTER, txmgf_table[t.mag_filter]);
    
    // debug info
    //printf("repeat S: %d   T: %d  \n", t.repeat_s,  t.repeat_t ); 
    //printf("filter MIN: %d   MAG %d \n",  t.min_filter, t.mag_filter );  
    //printf("texture format is %d \n", t.format );  
    //printf("act FORMAT %d \n", tex->getFormat(PFTEX_INTERNAL_FORMAT) );
    //printf("search for fomat \n");
    //for( i = 0; i < txf_table[0]; i++ )
    //{
    //   if( txf_table[i] == tex->getFormat(PFTEX_INTERNAL_FORMAT) )
    //   {
    //      printf("act FORMAT is table entry %d \n", i );
    //   }
    //}
	  
     if( t.name_size != -1 )
     {
	 load_name( tex,  t.name_size,  csb );
	 ((char *)csb->buf)[t.name_size] = '\0';
	 tex->setName( (char *)csb->buf );
	 float index, contrastScale, contrastBias;
	 int n = sscanf((char *)csb->buf + t.file_name_size,
			"_i%f_cs%f_cb%f", &index,
			&contrastScale, &contrastBias);
	 if (n == 3) {
	     fprintf(stderr, "*** ClearCoat i%f cs%f cb%f\n", index,
		     contrastScale, contrastBias);
	     produceClearCoat(tex, index, contrastScale, contrastBias);
	 }
     }

    return(tex);
    
}   // end load_tex()

static pfTexGen *load_texgen(int /*id*/, csdFile_csb *csb)
{
    pfTexGen *texgen;
    texgen_t t;
    
    CSB_FREAD(&t, sizeof(texgen_t), 1, csb->fp);

    texgen = new pfTexGen();
    
    texgen->setMode( PF_S,   tgm_table[t.mode_s] );
    texgen->setMode( PF_T,   tgm_table[t.mode_t] );
    texgen->setMode( PF_R,   tgm_table[t.mode_q] );
    texgen->setMode( PF_Q,   tgm_table[t.mode_r] );
    texgen->setPlane( PF_S,  t.plane_s[0], t.plane_s[1], t.plane_s[2], t.plane_s[3] );
    texgen->setPlane( PF_T,  t.plane_t[0], t.plane_t[1], t.plane_t[2], t.plane_t[3] );
    texgen->setPlane( PF_R,  t.plane_r[0], t.plane_r[1], t.plane_r[2], t.plane_r[3] );
    texgen->setPlane( PF_Q,  t.plane_q[0], t.plane_q[1], t.plane_q[2], t.plane_q[3] );
    
    if( t.name_size != -1 )
    {
        load_name( texgen,  t.name_size,  csb );
    }
    
    return(texgen);
    
}   // end load_texgen()

/*
 * loading appearances
 */

#define OLD_OLD_LIGHT_ENABLE            0
#define OLD_OLD_MATERIAL                1
#define OLD_OLD_MATERIAL_MODE_ENABLE    2
#define OLD_OLD_TEX_ENABLE              3
#define OLD_OLD_TEXTURE                 4
#define OLD_OLD_TRANSP_ENABLE           5
#define OLD_OLD_CULL_FACE               6
#define OLD_OLD_ALPHA_FUNC              7
#define OLD_OLD_ALPHA_REF               8
#define OLD_OLD_TRANSP_MODE             9
#define OLD_OLD_TEX_MODE                10
#define OLD_OLD_TEX_ENV                 11
#define OLD_OLD_TEX_BLEND_COLOR         12
#define OLD_OLD_TEX_GEN_ENABLE          13
#define OLD_OLD_TEX_GEN                 14
#define OLD_OLD_SHADE_MODEL             15
#define OLD_OLD_FOG_ENABLE              16
#define OLD_OLD_BLEND_COLOR             17
#define OLD_OLD_SRC_BLEND_FUNC          18
#define OLD_OLD_DST_BLEND_FUNC          19
#define OLD_OLD_COLOR_MASK              20
#define OLD_OLD_DEPTH_FUNC              21
#define OLD_OLD_DEPTH_MASK              22
#define OLD_OLD_POLY_MODE               23
#define OLD_OLD_LINE_STIPPLE_PATTERN    24
#define OLD_OLD_LINE_STIPPLE_FACTOR     25
#define OLD_OLD_TEX_TRANSFORM           26
#define OLD_OLD_BACK_MATERIAL           27

#define OLD_TEXTURE                     0
#define OLD_TEX_ENABLE                  1
#define OLD_TEX_MODE                    2
#define OLD_TEX_BLEND_COLOR             3
#define OLD_TEX_ENV                     4
#define OLD_TEX_GEN                     5
#define OLD_TEX_GEN_ENABLE              6
#define OLD_MATERIAL                    7
#define OLD_LIGHT_ENABLE                8
#define OLD_SHADE_MODEL                 9
#define OLD_TRANSP_ENABLE               10
#define OLD_TRANSP_MODE                 11
#define OLD_ALPHA_FUNC                  12
#define OLD_ALPHA_REF                   13
#define OLD_BLEND_COLOR                 14
#define OLD_SRC_BLEND_FUNC              15
#define OLD_DST_BLEND_FUNC              16
#define OLD_COLOR_MASK                  17
#define OLD_DEPTH_FUNC                  18
#define OLD_DEPTH_MASK                  19
#define OLD_FOG_ENABLE                  20
#define OLD_POLY_MODE                   21
#define OLD_LINE_STIPPLE_PATTERN        22
#define OLD_LINE_STIPPLE_FACTOR         23
#define OLD_TEX_TRANSFORM               24
#define OLD_BACK_MATERIAL               25
#define OLD_DEPTH_ENABLE                26
#define OLD_FOG_MODE                    27
#define OLD_FOG_DENSITY                 28
#define OLD_FOG_START                   29
#define OLD_FOG_END                     30
#define OLD_FOG_INDEX                   31
#define OLD_FOG_COLOR                   32
#define OLD_MATERIAL_MODE_ENABLE        33

#define TEXTURE				0
#define TEX_ENABLE 			1
#define TEX_MODE			2
#define TEX_BLEND_COLOR			3
#define TEX_ENV				4
#define TEX_GEN				5
#define TEX_GEN_ENABLE			6
#define LIGHT_ENABLE			7
#define SHADE_MODEL			8
#define TRANSP_ENABLE			9
#define TRANSP_MODE			10
#define ALPHA_FUNC			11
#define ALPHA_REF			12
#define BLEND_COLOR			13
#define SRC_BLEND_FUNC			14
#define DST_BLEND_FUNC			15
#define COLOR_MASK			16
#define DEPTH_FUNC			17
#define DEPTH_MASK			18
#define FOG_ENABLE			19
#define POLY_MODE			20
#define LINE_STIPPLE_PATTERN		21
#define LINE_STIPPLE_FACTOR		22
#define TEX_TRANSFORM			23
#define MATERIAL			24
#define BACK_MATERIAL			25
#define DEPTH_ENABLE			26
#define MATERIAL_MODE_ENABLE		27

typedef struct {
    int lightEnable;
    int material;
    int materialModeEnable;
    int texEnable;
    int texture;
    int transpEnable;
    int cullFace;
    int alphaFunc;
    int alphaRef;
    int transpMode;
    int texMode;
    int texEnv;
    int texBlendColor;
    int texGenEnable;
    int texGen;
    int shadeModel;
    int fogEnable;
    int blendColor;
    int srcBlendFunc;
    int dstBlendFunc;
    int colorMask;
    int depthFunc;
    int depthMask;
    int polyMode;
    int lineStipplePattern;
    int lineStippleFactor;
    int texTransform;
    int backMaterial;
    int depthEnable;
    int fogMode;
    int fogDensity;
    int fogStart;
    int fogEnd;
    int fogIndex;
    int fogColor;
} appearance_local_t;

static int
bitOff(int64 mask, int bit)
{
    if (bit == -1) return 0;
    return ((mask & ((int64)1 << bit)) == 0);
}

static void
set_appearance_local(int64 mask, appearance_local_t *local, int tex, int version)
{
    if (version < CSB_VERSION_REORDERD_INHERTANCE_MASK)
    {
	local->lightEnable 	  = bitOff(mask, OLD_OLD_LIGHT_ENABLE);
	local->material		  = bitOff(mask, OLD_OLD_MATERIAL);
	local->materialModeEnable = bitOff(mask, OLD_OLD_MATERIAL_MODE_ENABLE);
	local->transpEnable	  = bitOff(mask, OLD_OLD_TRANSP_ENABLE);
	local->cullFace		  = bitOff(mask, OLD_OLD_CULL_FACE);
	local->alphaFunc	  = bitOff(mask, OLD_OLD_ALPHA_FUNC);
	local->alphaRef		  = bitOff(mask, OLD_OLD_ALPHA_REF);
	local->transpMode	  = bitOff(mask, OLD_OLD_TRANSP_MODE);
	local->texMode		  = bitOff(mask, OLD_OLD_TEX_MODE);
	local->texEnv		  = bitOff(mask, OLD_OLD_TEX_ENV);
	local->texBlendColor	  = bitOff(mask, OLD_OLD_TEX_BLEND_COLOR);
	local->texGenEnable	  = bitOff(mask, OLD_OLD_TEX_GEN_ENABLE);
	local->texGen		  = bitOff(mask, OLD_OLD_TEX_GEN);
	local->shadeModel	  = 1; // old version ignores inheritance bit
	local->fogEnable	  = bitOff(mask, OLD_OLD_FOG_ENABLE);
	local->blendColor	  = bitOff(mask, OLD_OLD_BLEND_COLOR);
	local->srcBlendFunc	  = bitOff(mask, OLD_OLD_SRC_BLEND_FUNC);
	local->dstBlendFunc	  = bitOff(mask, OLD_OLD_DST_BLEND_FUNC);
	local->colorMask	  = bitOff(mask, OLD_OLD_COLOR_MASK);
	local->depthFunc	  = bitOff(mask, OLD_OLD_DEPTH_FUNC);
	local->depthMask	  = bitOff(mask, OLD_OLD_DEPTH_MASK);
	local->polyMode		  = bitOff(mask, OLD_OLD_POLY_MODE);
	local->lineStipplePattern = bitOff(mask, OLD_OLD_LINE_STIPPLE_PATTERN);
	local->lineStippleFactor  = bitOff(mask, OLD_OLD_LINE_STIPPLE_FACTOR);
	local->texTransform	  = bitOff(mask, OLD_OLD_TEX_TRANSFORM);
	local->backMaterial	  = bitOff(mask, OLD_OLD_BACK_MATERIAL);
	local->depthEnable	  = 0;
	local->fogMode		  = 0;
	local->fogDensity	  = 0;
	local->fogStart		  = 0;
	local->fogEnd		  = 0;
	local->fogIndex		  = 0;
	local->fogColor		  = 0;

	if (tex != -1)
	{
	    local->texEnable	  = 1;
	    local->texture	  = 1;
	}
	else
	{
	    local->texEnable	  = bitOff(mask, OLD_OLD_TEX_ENABLE);
	    local->texture 	  = bitOff(mask, OLD_OLD_TEXTURE);
	}
    }
    else if (version < CSB_VERSION_MOVED_MATERIAL_BIT)
    {
	local->lightEnable 	  = bitOff(mask, OLD_LIGHT_ENABLE);
	local->material		  = bitOff(mask, OLD_MATERIAL);
	local->materialModeEnable = bitOff(mask, OLD_MATERIAL_MODE_ENABLE);
	local->texEnable	  = bitOff(mask, OLD_TEX_ENABLE);
	local->texture		  = bitOff(mask, OLD_TEXTURE);
	local->transpEnable	  = bitOff(mask, OLD_TRANSP_ENABLE);
	local->cullFace		  = 0;
	local->alphaFunc	  = bitOff(mask, OLD_ALPHA_FUNC);
	local->alphaRef		  = bitOff(mask, OLD_ALPHA_REF);
	local->transpMode	  = bitOff(mask, OLD_TRANSP_MODE);
	local->texMode		  = bitOff(mask, OLD_TEX_MODE);
	local->texEnv		  = bitOff(mask, OLD_TEX_ENV);
	local->texBlendColor	  = bitOff(mask, OLD_TEX_BLEND_COLOR);
	local->texGenEnable	  = bitOff(mask, OLD_TEX_GEN_ENABLE);
	local->texGen		  = bitOff(mask, OLD_TEX_GEN);
	local->shadeModel	  = bitOff(mask, OLD_SHADE_MODEL);
	local->fogEnable	  = bitOff(mask, OLD_FOG_ENABLE);
	local->blendColor	  = bitOff(mask, OLD_BLEND_COLOR);
	local->srcBlendFunc	  = bitOff(mask, OLD_SRC_BLEND_FUNC);
	local->dstBlendFunc	  = bitOff(mask, OLD_DST_BLEND_FUNC);
	local->colorMask	  = bitOff(mask, OLD_COLOR_MASK);
	local->depthFunc	  = bitOff(mask, OLD_DEPTH_FUNC);
	local->depthMask	  = bitOff(mask, OLD_DEPTH_MASK);
	local->polyMode		  = bitOff(mask, OLD_POLY_MODE);
	local->lineStipplePattern = bitOff(mask, OLD_LINE_STIPPLE_PATTERN);
	local->lineStippleFactor  = bitOff(mask, OLD_LINE_STIPPLE_FACTOR);
	local->texTransform	  = bitOff(mask, OLD_TEX_TRANSFORM);
	local->backMaterial	  = bitOff(mask, OLD_BACK_MATERIAL);
	local->depthEnable	  = bitOff(mask, OLD_DEPTH_ENABLE);
	local->fogMode		  = bitOff(mask, OLD_FOG_MODE);
	local->fogDensity	  = bitOff(mask, OLD_FOG_DENSITY);
	local->fogStart		  = bitOff(mask, OLD_FOG_START);
	local->fogEnd		  = bitOff(mask, OLD_FOG_END);
	local->fogIndex		  = bitOff(mask, OLD_FOG_INDEX);
	local->fogColor		  = bitOff(mask, OLD_FOG_COLOR);
   } 
   else
   {
	local->lightEnable 	  = bitOff(mask, LIGHT_ENABLE);
	local->material		  = bitOff(mask, MATERIAL);
	local->materialModeEnable = bitOff(mask, MATERIAL_MODE_ENABLE);
	local->texEnable	  = bitOff(mask, TEX_ENABLE);
	local->texture		  = bitOff(mask, TEXTURE);
	local->transpEnable	  = bitOff(mask, TRANSP_ENABLE);
	local->cullFace		  = 0;
	local->alphaFunc	  = bitOff(mask, ALPHA_FUNC);
	local->alphaRef		  = bitOff(mask, ALPHA_REF);
	local->transpMode	  = bitOff(mask, TRANSP_MODE);
	local->texMode		  = bitOff(mask, TEX_MODE);
	local->texEnv		  = bitOff(mask, TEX_ENV);
	local->texBlendColor	  = bitOff(mask, TEX_BLEND_COLOR);
	local->texGenEnable	  = bitOff(mask, TEX_GEN_ENABLE);
	local->texGen		  = bitOff(mask, TEX_GEN);
	local->shadeModel	  = bitOff(mask, SHADE_MODEL);
	local->fogEnable	  = bitOff(mask, FOG_ENABLE);
	local->blendColor	  = bitOff(mask, BLEND_COLOR);
	local->srcBlendFunc	  = bitOff(mask, SRC_BLEND_FUNC);
	local->dstBlendFunc	  = bitOff(mask, DST_BLEND_FUNC);
	local->colorMask	  = bitOff(mask, COLOR_MASK);
	local->depthFunc	  = bitOff(mask, DEPTH_FUNC);
	local->depthMask	  = bitOff(mask, DEPTH_MASK);
	local->polyMode		  = bitOff(mask, POLY_MODE);
	local->lineStipplePattern = bitOff(mask, LINE_STIPPLE_PATTERN);
	local->lineStippleFactor  = bitOff(mask, LINE_STIPPLE_FACTOR);
	local->texTransform	  = bitOff(mask, TEX_TRANSFORM);
	local->backMaterial	  = bitOff(mask, BACK_MATERIAL);
	local->depthEnable	  = bitOff(mask, DEPTH_ENABLE);
	local->fogMode		  = 0;
	local->fogDensity	  = 0;
	local->fogStart		  = 0;
	local->fogEnd		  = 0;
	local->fogIndex		  = 0;
	local->fogColor		  = 0;
   }
}



static pfGeoState *load_appearance_bitmask32(appearance895_t& a, csdFile_csb *csb)
{
    int64 inherit_mask;
    appearance_local_t local;

    pfGeoState* app = new pfGeoState;
    
    mask_to_bitmask(a.inherit, &inherit_mask);
    set_appearance_local(inherit_mask, &local, a.tex, csb->version);

    // if the texture is NULL then don't use it
    if (local.texture && a.tex != -1 && csb->rl_list[L_TEX][a.tex] != NULL)
    {
	if (local.texEnv)
	{
	    pfTexEnv *tenv = new pfTexEnv();
            tenv->setMode(cte_table[a.tenv]);
	    if (local.texBlendColor)
	    {
        	tenv->setBlendColor(a.tex_bcolor[0], a.tex_bcolor[1],
                		    a.tex_bcolor[2], a.tex_bcolor[3] );
	    }
            app->setAttr(PFSTATE_TEXENV, tenv);
	}
        app->setAttr(PFSTATE_TEXTURE,
                     (pfTexture *)csb->rl_list[L_TEX][a.tex]);

	if (local.texEnable)
	    app->setMode(PFSTATE_ENTEXTURE, a.tex_enable == 1 ? PF_ON : PF_OFF);
    }

    // if (local.texMode)
    // app->setTexMode((csContext::TexModeEnum)ctxm_table[a.tex_mode]);

    if (local.texGen && a.tgen != -1)
        app->setAttr(PFSTATE_TEXGEN, csb->rl_list[L_TEXGEN][a.tgen]);

    if (local.texGenEnable && a.tgen_enable == 1)
        app->setMode(PFSTATE_ENTEXGEN, PF_ON);

    if (local.material && a.mtl != -1)
        app->setAttr(PFSTATE_FRONTMTL,
                     (pfMaterial *)csb->rl_list[L_MTL][a.mtl]);

    if (local.lightEnable) 
	app->setMode(PFSTATE_ENLIGHTING, a.light_enable == 1 ? PF_ON : PF_OFF);
    else
	// XXX need to explicitly set lighting on rather than inherit
	// from global geostate since perfly does not handle this correctly
	app->setMode(PFSTATE_ENLIGHTING, PF_ON);
	

    if (local.shadeModel)
	app->setMode( PFSTATE_SHADEMODEL, csm_table[a.shade_model] );

    if (local.alphaFunc)
	app->setMode( PFSTATE_ALPHAFUNC, caf_table[a.alpha_func] );

    if (local.alphaRef)
	app->setVal( PFSTATE_ALPHAREF, a.alpha_ref  );

    if (local.transpEnable && a.transp_enable == 1)
	app->setMode( PFSTATE_TRANSPARENCY,  ctrm_table[a.transp_mode] );

    // if (local.blendColor)
    //     app->setBlendColor(a.bcolor[0], a.bcolor[1], a.bcolor[2], a.bcolor[3]);
    // if (local.srcBlendFunc)
    //     app->setSrcBlendFunc((csContext::SrcBlendFuncEnum)csbf_table[a.src_bfunc]);
    // if (local.dstBlendFunc)
    //     app->setDstBlendFunc((csContext::DstBlendFuncEnum)cdbf_table[a.dst_bfunc]);

    if (csb->version < -995)
    {
        appearance996_t *a996 = (appearance996_t*) &a;
	// if (local.colorMask)
        // app->setColorMask(a996->color_mask[0], a996->color_mask[1],
        //                   a996->color_mask[2], a996->color_mask[3]);
	// if (local.depthFunc)
        // app->setDepthFunc((csContext::DepthFuncEnum)cdf_table[a996->depth_func]);
	// if (local.depthMask)
        // app->setDepthMask(a996->depth_mask);

	if (local.fogEnable)
	    app->setMode(PFSTATE_ENFOG, a996->fog_enable == 1 ? PF_ON : PF_OFF);

	if (local.polyMode) 
	    if (cpm_table[a996->poly_mode] == PFSTATE_ENWIREFRAME)
		app->setMode(PFSTATE_ENWIREFRAME, PF_ON);
	    else
		app->setMode(PFSTATE_ENWIREFRAME, PF_OFF);
    } 
    else 
    {
	// if (local.colorMask)
        // app->setColorMask(a.color_mask[0], a.color_mask[1],
        //                  a.color_mask[2], a.color_mask[3]);
	// if (local.depthFunc)
        // app->setDepthFunc((csContext::DepthFuncEnum)cdf_table[a.depth_func]);
	// if (local.depthMask)
        // app->setDepthMask(a.depth_mask);

	if (local.fogEnable)
	    app->setMode(PFSTATE_ENFOG, a.fog_enable == 1 ? PF_ON : PF_OFF);

	if (local.polyMode) 
	    if (cpm_table[a.poly_mode] == PFSTATE_ENWIREFRAME)
		app->setMode(PFSTATE_ENWIREFRAME, PF_ON);
	    else
		app->setMode(PFSTATE_ENWIREFRAME, PF_OFF);
    }

    if (csb->version >= CSB_VERSION_TEX_STIP_N_TWOSIDE)
    {
	if (local.backMaterial && a.back_mtl != -1)
	    app->setAttr(PFSTATE_BACKMTL,
                         (pfMaterial *)csb->rl_list[L_MTL][a.back_mtl]);

	// if (local.lineStipplePattern)
	// app->setLineStipplePattern(a.line_stipple_pattern);
	// if (local.lineStippleFactor)
	// app->setLineStippleFactor(a.line_stipple_factor);

	if (local.texTransform)
	{
	    pfMatrix *tex_transform;
	    tex_transform = (pfMatrix *)pfMalloc(sizeof(pfMatrix), csb->arena);
	    tex_transform->set(a.tex_transform);
	    app->setAttr(PFSTATE_TEXMAT, tex_transform);
	    app->setMode(PFSTATE_ENTEXMAT, PFTR_ON);
	}
    }

    if (csb->version >= CSB_VERSION_ADDED_DEPTH_ENABLE)
    {
	// if (local.depthEnable)
        // app->setDepthEnable(a.depth_enable);
    }

    return app;
}



static pfGeoState *load_appearance_bitmask64(int id, appearance_t& a, csdFile_csb *csb)
{
    int64 inherit_mask;
    appearance_local_t local;

    pfGeoState* app = new pfGeoState;

    mask_to_bitmask64(csb->endian_flip, a.inherit, &inherit_mask);
    set_appearance_local(inherit_mask, &local, a.tex, csb->version);

    // if the texture is NULL then don't use it
    if (local.texture && a.tex != -1 && csb->rl_list[L_TEX][a.tex] != NULL)
    {
	if (local.texEnv)
	{
	    pfTexEnv *tenv = new pfTexEnv();
	    tenv->setMode(cte_table[a.tenv]);
	    tenv->setBlendColor(a.tex_bcolor[0], a.tex_bcolor[1],
			        a.tex_bcolor[2], a.tex_bcolor[3] );
	    app->setAttr(PFSTATE_TEXENV, tenv);
	}

	app->setAttr(PFSTATE_TEXTURE, 
		     (pfTexture *)csb->rl_list[L_TEX][a.tex]);

	if (local.texEnable)
	    app->setMode(PFSTATE_ENTEXTURE, a.tex_enable == 1 ? PF_ON : PF_OFF);
    }

    // if (local.texMode)
    // app->setTexMode((csContext::TexModeEnum)ctxm_table[a.tex_mode]);

    if (local.texGen && a.tgen != -1)
        app->setAttr(PFSTATE_TEXGEN, csb->rl_list[L_TEXGEN][a.tgen]);

    if (local.texGenEnable && a.tgen_enable == 1)
        app->setMode(PFSTATE_ENTEXGEN, PF_ON);

    if (local.material && a.mtl != -1)
        app->setAttr(PFSTATE_FRONTMTL,
                     (pfMaterial *)csb->rl_list[L_MTL][a.mtl]);

    if (local.lightEnable)
        app->setMode(PFSTATE_ENLIGHTING, a.light_enable ? PF_ON : PF_OFF);
    else
	// XXX need to explicitly set lighting on rather than inherit
	// from global geostate since perfly does not handle this correctly
	app->setMode(PFSTATE_ENLIGHTING, PF_ON);

    if (local.shadeModel) 
	app->setMode( PFSTATE_SHADEMODEL, csm_table[a.shade_model] );

    if (local.alphaFunc)
	app->setMode( PFSTATE_ALPHAFUNC, caf_table[a.alpha_func] );

    if (local.alphaRef)
	app->setVal( PFSTATE_ALPHAREF, a.alpha_ref  );

    if (local.transpEnable && a.transp_enable == 1)
	app->setMode( PFSTATE_TRANSPARENCY,  ctrm_table[a.transp_mode] );

    // if (local.blendColor)
    // app->setBlendColor(a.bcolor[0], a.bcolor[1], a.bcolor[2], a.bcolor[3]);
    // if (local.srcBlendFunc)
    // app->setSrcBlendFunc((csContext::SrcBlendFuncEnum)csbf_table[a.src_bfunc]);
    // if (local.dstBlendFunc)
    // app->setDstBlendFunc((csContext::DstBlendFuncEnum)cdbf_table[a.dst_bfunc]);

    // if (local.colorMask)
    // app->setColorMask(a.color_mask[0], a.color_mask[1],
    //                  a.color_mask[2], a.color_mask[3]);
    // if (local.depthFunc)
    // app->setDepthFunc((csContext::DepthFuncEnum)cdf_table[a.depth_func]);
    // if (local.depthMask)
    // app->setDepthMask(a.depth_mask);

    if (local.fogEnable)
        app->setMode(PFSTATE_ENFOG, a.fog_enable == 1 ? PF_ON : PF_OFF);

    if (local.polyMode) 
	if (cpm_table[a.poly_mode] == PFSTATE_ENWIREFRAME)
	    app->setMode(PFSTATE_ENWIREFRAME, PF_ON);
	else
	    app->setMode(PFSTATE_ENWIREFRAME, PF_OFF);

    if (local.backMaterial && a.back_mtl != -1)
        app->setAttr(PFSTATE_BACKMTL,
                     (pfMaterial *)csb->rl_list[L_MTL][a.back_mtl]);
    else if(!local.backMaterial && a.mtl != -1) {
        // Ref bug # 642531, set back material to front material if none
        // is specified. Also turn off backface culing.
        app->setMode(PFSTATE_CULLFACE, PFCF_OFF);
        app->setAttr(PFSTATE_BACKMTL,
                     (pfMaterial *)csb->rl_list[L_MTL][a.mtl]);
    }


    // if (local.lineStipplePattern)
    // app->setLineStipplePattern(a.line_stipple_pattern);
    // if (local.lineStippleFactor)
    // app->setLineStippleFactor(a.line_stipple_factor);

    if (local.texTransform)
    {
	pfMatrix *tex_transform;
	tex_transform = (pfMatrix *)pfMalloc(sizeof(pfMatrix), csb->arena);
	tex_transform->set(a.tex_transform);
	app->setAttr(PFSTATE_TEXMAT, tex_transform);
    }

    // if (local.depthEnable)
    // app->setDepthEnable(a.depth_enable);

    if (csb->version >= CSB_VERSION_ADDED_MATERIAL_MODE)
    {
	if (local.materialModeEnable)
	    csb->gstate_mtl_mode[id] = a.material_mode_enable;
	else
	    csb->gstate_mtl_mode[id] = NO_COLOR_MATERIAL;
    }

    return app;
}


static pfGeoState *load_appearance(int id, csdFile_csb *csb)
{
    pfGeoState *app;
    appearance_t a;
    appearance893_t a893;  // versions since fog added have larger appearance_t struct

    if (csb->version < -995) {
        CSB_FREAD(&a, sizeof(appearance996_t), 1, csb->fp);
    } else if (csb->version < CSB_VERSION_TEX_STIP_N_TWOSIDE) {
        CSB_FREAD(&a, sizeof(appearance991_t), 1, csb->fp);
    } else if (csb->version < CSB_VERSION_ADDED_DEPTH_ENABLE) {
        CSB_FREAD(&a, sizeof(appearance896_t), 1, csb->fp);
    } else if (csb->version < CSB_VERSION_BITMASK64_FOG) {
        CSB_FREAD(&a, sizeof(appearance895_t), 1, csb->fp);
    } else if (csb->version < CSB_VERSION_ADDED_MATERIAL_MODE) {
        CSB_FREAD(&a893, sizeof(appearance894_t), 1, csb->fp);
    } else if (csb->version < CSB_VERSION_FOG) {
        CSB_FREAD(&a893, sizeof(appearance893_t), 1, csb->fp);
    } else {
        CSB_FREAD(&a, sizeof(appearance_t), 1, csb->fp);
    }

    // versions before -894 had a 32 bit inherit mask, when it changed
    // to 64 bit the entire appearance_t structure changed since it
    // just happens to be the first element. argh.  -trina
    if (csb->version < CSB_VERSION_BITMASK64_FOG)
    {
        appearance895_t *a895 = (appearance895_t*) &a;
        app = load_appearance_bitmask32(*a895, csb);
    }
    else
    {
        // Versions containing FOG elements have appearance_t structs
        // which do not map nicely into the current appearance_t which
        // has no FOG elements, need to map old to new.
        if (csb->version < CSB_VERSION_FOG)
        {
            // copy all elements up to and including depth_enable
            memcpy(&a, &a893, sizeof(appearance_t)-sizeof(int));
            // skip fog elements, copy material_mode_enable if there
            if (csb->version >= CSB_VERSION_ADDED_MATERIAL_MODE)
                a.material_mode_enable = a893.material_mode_enable;
        }

        app = load_appearance_bitmask64(id, a, csb);
    }

    if( a.name_size != -1 )
	load_name( app,  a.name_size,  csb );

    return(app);
    
}   // end load_appearance


static pfVec3 *load_vset(int /*id*/, csdFile_csb *csb)
{
    pfVec3 *vset;
    arrayset_t s;
   
    CSB_FREAD(&s, sizeof(arrayset_t), 1, csb->fp);
   
    if( s.array_type == ARRAY_TYPE_3F )
    {
	vset = (pfVec3 *)pfMalloc( sizeof(pfVec3)*s.size,
                                   csb->arena );
	CSB_FREAD(vset, sizeof(pfVec3), s.size, csb->fp); 
    }
    else
    {
	csb->read_error = TRUE;
    }
   
    if( s.name_size != -1 )
    {
 	load_name(vset,  s.name_size,  csb );
    }

    return( vset );
   
}   // end load_vset()

static pfVec4 *load_cset(int /*id*/, csdFile_csb *csb)
{
    pfVec4 *cset;
    arrayset_t s;
    pfVec4 *v4_ptr;
    pfVec3 *v3_ptr;
    
    //printf("load cset \n" );
    
    CSB_FREAD(&s, sizeof(arrayset_t), 1, csb->fp);
    
    if( s.array_type == ARRAY_TYPE_4F )
    {
        cset = (pfVec4 *)pfMalloc( sizeof(pfVec4)*s.size,  
	                           csb->arena );
	CSB_FREAD(cset, sizeof(pfVec4), s.size, csb->fp);
    }
    else if( s.array_type == ARRAY_TYPE_3F )
    {
        pfNotify( PFNFY_WARN,  PFNFY_NOTICE,
	           "Perfomer does not support 3 component color \n \
		   converting to 4 component \n" );

	// read in the 3 componente array
        pfVec3 *tmp_cset = (pfVec3 *)pfMalloc( sizeof(pfVec3)*s.size,  
	                                       csb->arena );
        CSB_FREAD(tmp_cset, sizeof(pfVec3), s.size, csb->fp);
	
	// convert to a 4 component array
	cset =  (pfVec4 *)pfMalloc( sizeof(pfVec4)*s.size,
	                            csb->arena );
	v4_ptr = cset;
	v3_ptr = tmp_cset;
	for( int i = 0; i < s.size; i++ )
	{
	    v4_ptr->set( v3_ptr->vec[0], v3_ptr->vec[1],  v3_ptr->vec[2],  1.0 );
	    v4_ptr++;
	    v3_ptr++; 
	}
	
	pfDelete(tmp_cset);
    }
    else
    {
        csb->read_error = TRUE;
    }
    
    if( s.name_size != -1 )
    {
       load_name(cset,  s.name_size,  csb );
    }

    return( cset );
    
}   // end load_cset()

static pfVec3 *load_nset(int /*id*/, csdFile_csb *csb)
{
    pfVec3 *nset;
    arrayset_t s;
    
    CSB_FREAD(&s, sizeof(arrayset_t), 1, csb->fp);
    
    if (s.array_type == ARRAY_TYPE_3F)
    {
       nset = (pfVec3 *)pfMalloc( sizeof(pfVec3)*s.size, 
                                  csb->arena );
       CSB_FREAD(nset, sizeof(pfVec3), s.size, csb->fp);
    }
    else
    {
	   csb->read_error = TRUE;
    }
    
    if( s.name_size != -1 )
    {
       load_name(nset,  s.name_size,  csb );
    }

    //printf("loaded nset with %d normals \n",  s.count );
    return( nset );
    
}   // end load_nset()

static void *load_tset(int /*id*/, csdFile_csb *csb)
{
    pfVec2 *tset;
    arrayset_t s;

    CSB_FREAD(&s, sizeof(arrayset_t), 1, csb->fp);

    if (s.array_type == ARRAY_TYPE_2F)
    {
       tset = (pfVec2 *)pfMalloc( sizeof(pfVec2)*s.size,
                                  csb->arena );
       CSB_FREAD(tset, sizeof(pfVec2), s.size, csb->fp);
    }
    else
    {
	csb->read_error = TRUE;
    }

    if( s.name_size != -1 )
    {
       load_name(tset,  s.name_size,  csb );
    }

    return( tset );
    
}   // end load_tset()

static int32 *load_iset(int id, csdFile_csb *csb)
{
    int32 *iset;
    arrayset_t s;
    
    CSB_FREAD(&s, sizeof(arrayset_t), 1, csb->fp);
    
    // remeber size of iset
    csb->iset_size[id] = s.size;
    
    if( s.array_type == ARRAY_TYPE_1I )
    {
	iset = (int32 *)pfMalloc( sizeof(int32)*s.size,
	                          csb->arena );
	CSB_FREAD(iset, sizeof(int32), s.size, csb->fp);
    }
    else
    {
	csb->read_error = TRUE;
    }
    
    if( s.name_size != -1 )
    {
       load_name(iset,  s.name_size,  csb );
    }

    //printf("loaded iset %d size = %d  \n",  id, s.size );
  
    return( iset );
    
}   // end load_iset()



static void load_bpc_data(pfGeoSet * /*gset*/, csdFile_csb *csb)
{
    if (csb->version < CSB_VERSION_BPCULL_DATA)
        return;

    int prim_count;
    CSB_FREAD(&prim_count, sizeof(int), 1, csb->fp);

    unsigned char mode;
    CSB_FREAD(&mode, sizeof(unsigned char), 1, csb->fp);
    // XXX
    // gset->setBPCullPrimNormModeEnable(mode);

    CSB_FREAD(&mode, sizeof(unsigned char), 1, csb->fp);
    // XXX
    // gset->setBPCullDynamicBuildMode(mode);

    if (prim_count >= 0)
    {
        // XXX
        // gset->setBPCullPoint(new csVec3f[prim_count]);
        // CSB_FREAD(gset->getBPCullPoint(),  sizeof(csVec3f), prim_count, csb->fp);
        // gset->setBPCullCenter(new csVec3f[prim_count]);
        // CSB_FREAD(gset->getBPCullCenter(), sizeof(csVec3f), prim_count, csb->fp);
        // gset->setBPCullDelta(new csFloat[prim_count]);
        // CSB_FREAD(gset->getBPCullDelta(),  sizeof(csFloat), prim_count, csb->fp);

        char* vec_buf = new char[sizeof(pfVec3) * prim_count];
        float* float_buf = new float[prim_count];
        CSB_FREAD(vec_buf, sizeof(pfVec3), prim_count, csb->fp);
        CSB_FREAD(vec_buf, sizeof(pfVec3), prim_count, csb->fp);
        CSB_FREAD(float_buf,  sizeof(float), prim_count, csb->fp);
        delete [] vec_buf;
        delete [] float_buf;
    }
}


static pfGeoSet *load_lineset(int /*id*/, csdFile_csb *csb)
{
    pfGeoSet *lineset;
    lineset_t s;
    
    CSB_FREAD(&s, sizeof(lineset_t), 1, csb->fp);
    
    lineset = new pfGeoSet();
    
    set_geoset_data(lineset, (geoset_t *)&s, csb);
    lineset->setPrimType( PFGS_LINES );
    lineset->setLineWidth(s.width);
    
    load_bpc_data(lineset, csb);

    if( s.name_size != -1 )
    {
       load_name(lineset,  s.name_size,  csb );
    }

    return(lineset);
    
}   // end load_lineset()

static pfGeoSet *load_linestripset(int /*id*/, csdFile_csb *csb)
{
    pfGeoSet *linestripset;
    linestripset_t s;
    int32 *lengths;
   
    CSB_FREAD(&s, sizeof(linestripset_t), 1, csb->fp);
    
    linestripset = new pfGeoSet();
    
    set_geoset_data(linestripset, (geoset_t *)&s, csb);
    linestripset->setPrimType( PFGS_LINESTRIPS );
    linestripset->setLineWidth(s.width);
 
    lengths = (int32 *)pfMalloc( sizeof(int32)*s.num_lengths, 
                                 csb->arena );
    CSB_FREAD(lengths, sizeof(int32), s.num_lengths, csb->fp);
    linestripset->setPrimLengths( lengths );
    
    load_bpc_data(linestripset, csb);

    if( s.name_size != -1 )
    {
       load_name(linestripset,  s.name_size,  csb );
    }

    return(linestripset);

}   // end load_linestripset()

static pfGeoSet *load_pointset(int /*id*/, csdFile_csb *csb)
{
    pfGeoSet *pointset;
    pointset_t s;
    
    CSB_FREAD(&s, sizeof(pointset_t), 1, csb->fp);
    
    pointset = new pfGeoSet();
    
    set_geoset_data(pointset, (geoset_t *)&s, csb);
    pointset->setPrimType( PFGS_POINTS );
    pointset->setPntSize(s.size);
    
    load_bpc_data(pointset, csb);

    if( s.name_size != -1 )
    {
       load_name(pointset,  s.name_size,  csb );
    }

    return( pointset );
    
}   // end load_pointset()

static pfGeoSet *load_polyset(int /*id*/, csdFile_csb *csb)
{
    pfGeoSet *polyset;
    polyset_t s;
    int32 *lengths;
    
    CSB_FREAD(&s, sizeof(polyset_t), 1, csb->fp);
    
    polyset = new pfGeoSet();
    set_geoset_data(polyset, (geoset_t *)&s, csb);
    polyset->setPrimType( PFGS_POLYS );
    
    lengths = (int32 *)pfMalloc( sizeof(int32)*s.num_lengths, 
                                 csb->arena );
    CSB_FREAD(lengths, sizeof(int32), s.num_lengths, csb->fp);
    polyset->setPrimLengths( lengths );

    load_bpc_data(polyset, csb);

    if (s.name_size != -1)
    {
        load_name(polyset, s.name_size, csb);
    }

    return( polyset );
    
}   // end load_polyset()

static pfGeoSet *load_quadset(int /*id*/, csdFile_csb *csb)
{
    pfGeoSet *quadset;
    quadset_t s;
    
    CSB_FREAD(&s, sizeof(quadset_t), 1, csb->fp);
    
    quadset = new pfGeoSet();
    set_geoset_data(quadset, (geoset_t *)&s, csb);
    quadset->setPrimType( PFGS_QUADS );
    
    //printf("quadset loaded \n" );
    //print_gset_data( (geoset_t *)&s );
    
    load_bpc_data(quadset, csb);

    if( s.name_size != -1 )
    {
       load_name(quadset,  s.name_size,  csb );
    }

    return( quadset );
    
}   // end load_quadset()

static pfGeoSet *load_triset(int /*id*/, csdFile_csb *csb)
{
    pfGeoSet *triset;
    triset_t s;
    
    CSB_FREAD(&s, sizeof(triset_t), 1, csb->fp);
    
    triset = new pfGeoSet();
    
    set_geoset_data(triset, (geoset_t *)&s, csb);
    triset->setPrimType( PFGS_TRIS );

    load_bpc_data(triset, csb);

    if( s.name_size != -1 )
    {
	load_name( triset, s.name_size, csb );
    }

    return(triset);
    
}   // end load_triset()

static pfGeoSet *load_tristripset(int /*id*/, csdFile_csb *csb)
{
    pfGeoSet *tristripset;
    tristripset_t s;
    int32 *lengths;
    int32 sum;

    //printf("load tristripset \n");

    CSB_FREAD(&s, sizeof(tristripset_t), 1, csb->fp);
 
    //print_gset_data( (geoset_t *)&s );
    //printf("num_lengths = %d \n",  s.num_lengths );

    lengths = (int32 *)pfMalloc( sizeof(int32)*s.num_lengths, 
                                  csb->arena );
    if( s.num_lengths && lengths == NULL )
    {
	pfNotify( PFNFY_NOTICE, PFNFY_PRINT, 
                  "pfMalloc error \n");
    }
				    
    CSB_FREAD(lengths, sizeof(int32), s.num_lengths, csb->fp);
   
     	         
    tristripset = new pfGeoSet;
    if( tristripset == NULL )
    {
	pfNotify( PFNFY_NOTICE, PFNFY_PRINT, 
                  "load_tristrip: error new pfGeoSet \n");	
    }

    set_geoset_data( tristripset, (geoset_t *)&s, csb );
    tristripset->setPrimType( PFGS_TRISTRIPS );
    tristripset->setPrimLengths( lengths );
    
    load_bpc_data(tristripset, csb);

    if( s.name_size != -1 )
    {
	load_name( tristripset, s.name_size, csb );
    }

    return(tristripset);
    
}   // end load_tristripset()

static void *load_geometry(int /*id*/, csdFile_csb *csb)
{
    void *geometry;
    geometry_ref_t g;
   
    CSB_FREAD(&g, sizeof(geometry_ref_t), 1, csb->fp);
    //printf("load geometry refrence id =%d \n",  id );
   
    if (g.list_id != -1)
    {
        //printf("list id = %d \n",  g.list_id );
        //printf("list_item = %d \n",  g.list_item );
	geometry = (void *)csb->rl_list[g.list_id][g.list_item];
    }
    else
    {
        printf("list id = %d \n",  g.list_id );
	geometry = NULL;
    }

   return(geometry);
       
}   // end load_geometry()


static void *load_engine(int /* id */, csdFile_csb *csb)
{
    engine_ref_t e;

    CSB_FREAD(&e, sizeof(engine_ref_t), 1, csb->fp);

    /*
    if (e.list_id != -1)
    {
        engine = (csEngine *)csb->rl_list[e.list_id][e.list_item];
        if (csb->engine_list != NULL)
            csb->engine_list->append(engine);
    }
    else
        engine = NULL;
    */

    return(NULL);
}


#define LOAD_INTERPOLATOR(size)                                         \
    interpolator_t i;                                                   \
    float32 *k, *kv;                                                    \
                                                                        \
    CSB_FREAD(&i, sizeof(interpolator_t), 1, csb->fp);                  \
                                                                        \
    k = new float32[i.num_keys];					\
    CSB_FREAD(k, sizeof(float32), i.num_keys, csb->fp);                 \
    delete k;								\
									\
    kv = new float32[i.num_keyValues * size];				\
    CSB_FREAD(kv, sizeof(float32), i.num_keyValues * size, csb->fp);    \
    delete kv;								\
                                                                        \
    if (i.name_size != -1)                                              \
        load_name(interp, i.name_size, csb);                            \


static void *load_norminterp(int /* id */, csdFile_csb *csb)
{
    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csNormalInterpolator");

    void *interp = NULL;
    LOAD_INTERPOLATOR(3);
    return(interp);
}

static void *load_posinterp(int /* id */, csdFile_csb *csb)
{
    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csPositionInterpolator");

    void *interp = NULL;
    LOAD_INTERPOLATOR(3);
    return(interp);
}

static void *load_scalarinterp(int /* id */, csdFile_csb *csb)
{
    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csScalarInterpolator");

    void *interp = NULL;
    LOAD_INTERPOLATOR(1);
    return(interp);
}

static void *load_colorinterp(int /* id */, csdFile_csb *csb)
{
    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csColorInterpolator");

    void *interp = NULL;
    LOAD_INTERPOLATOR(3);
    return(interp);
}

static void *load_coordinterp(int /* id */, csdFile_csb *csb)
{
    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csCoordinateInterpolator");

    void *interp = NULL;
    LOAD_INTERPOLATOR(3);
    return(interp);
}


static void *load_orientinterp(int /* id */, csdFile_csb *csb)
{
    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csOrientationInterpolator");

    void *interp = NULL;

    interpolator_t i;
    float32 *k, *kv;

    CSB_FREAD(&i, sizeof(interpolator_t), 1, csb->fp);

    k = new float32[i.num_keys];
    CSB_FREAD(k, sizeof(float32), i.num_keys, csb->fp);
    delete [] k;

    kv = new float32[i.num_keyValues * 4];
    CSB_FREAD(kv, sizeof(float32), i.num_keyValues * 4, csb->fp);
    delete [] kv;

    if (i.name_size != -1)
        load_name(interp, i.name_size, csb);

    return(interp);
}


#define LOAD_MORPHENG(size)                                             \
    morpheng_t m;                                                       \
    int *c, *i;                                                 	\
    float32 *w, *in;                                                    \
                                                                        \
    CSB_FREAD(&m, sizeof(morpheng_t), 1, csb->fp);                      \
                                                                        \
    c = new int[m.num_counts];						\
    CSB_FREAD(c, sizeof(int), m.num_counts, csb->fp);                   \
    delete [] c;							\
                                                                        \
    i = new int[m.num_indices];						\
    CSB_FREAD(i, sizeof(int), m.num_indices, csb->fp);          	\
    delete [] i;							\
                                                                        \
    w = new float32[m.num_weights];					\
    CSB_FREAD(w, sizeof(float32), m.num_weights, csb->fp);              \
    delete [] w;							\
                                                                        \
    in = new float32[m.num_inputs * size ];		 		\
    CSB_FREAD(in, sizeof(float32), m.num_inputs * size, csb->fp);       \
    delete [] in;							\
									\
    if (m.name_size != -1)                                              \
        load_name(morph, m.name_size, csb);                             \


static void *load_morpheng3f(int /* id */, csdFile_csb *csb)
{
    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csMorphEng3f");

    void *morph = NULL;
    LOAD_MORPHENG(3);
    return (morph);
}

static void *load_morpheng4f(int /* id */, csdFile_csb *csb)
{
    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csMorphEng4f");

    void *morph = NULL;
    LOAD_MORPHENG(4);
    return (morph);
}

static void *load_selecteng3f(int /* id */, csdFile_csb *csb)
{
    selecteng_t s;
    float32 *in;
    void *select = NULL;

    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csSelectEng3f");

    CSB_FREAD(&s, sizeof(selecteng_t), 1, csb->fp);

    in = new float32[s.num_inputs * 3];
    CSB_FREAD(in, sizeof(float32), s.num_inputs * 3, csb->fp);
    delete in;

    if (s.name_size != -1)
        load_name(select, s.name_size, csb);

    return(select);
}

static void *load_selecteng4f(int /* id */, csdFile_csb *csb)
{
    selecteng_t s;
    float32 *in;
    void *select = NULL;

    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csSelectEng4f");

    CSB_FREAD(&s, sizeof(selecteng_t), 1, csb->fp);

    in = new float32[s.num_inputs * 4];
    CSB_FREAD(in, sizeof(float32), s.num_inputs * 4, csb->fp);
    delete [] in;

    if (s.name_size != -1)
        load_name(select, s.name_size, csb);

    return(select);
}

static void *load_transeng3f(int /* id */, csdFile_csb *csb)
{
    transeng_t t;
    int *c, *i;
    float32 *m, *in;
    void *trans = NULL;

    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csTransformEng3f");

    CSB_FREAD(&t, sizeof(transeng_t), 1, csb->fp);

    c = new int[t.num_counts];
    CSB_FREAD(c, sizeof(int), t.num_counts, csb->fp);
    delete [] c;

    i = new int[t.num_indices];
    CSB_FREAD(i, sizeof(int), t.num_indices, csb->fp);
    delete [] i;

    m = new float32[t.num_matrices * 16];
    CSB_FREAD(m, sizeof(float32), t.num_matrices * 16, csb->fp);
    delete [] m;

    in = new float32[t.num_inputs * 3];
    CSB_FREAD(in, sizeof(float32), t.num_inputs * 3, csb->fp);
    delete in;

    if (t.name_size != -1)
        load_name(trans, t.name_size, csb);

    return(trans);
}

static void *load_spline(int /* id */, csdFile_csb *csb)
{
    spline_t s;
    float32 *k;
    void *spline = NULL;

    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csSpline");

    CSB_FREAD(&s, sizeof(spline_t), 1, csb->fp);

    k = new float32[s.num_keys];
    CSB_FREAD(k, sizeof(float32), s.num_keys, csb->fp);
    delete [] k;

    if (s.name_size != -1)
        load_name(spline, s.name_size, csb);

    return(spline);
}

static void *load_timesensor(int /* id */, csdFile_csb *csb)
{
    timesensor_t t;
    void *sensor = NULL;

    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csTimeSensor");

    CSB_FREAD(&t, sizeof(timesensor_t), 1, csb->fp);

    if (t.name_size != -1)
        load_name(sensor, t.name_size, csb);

    return(sensor);
}


csdCustomObject *loadCustomHeader(char *customName, csdFile_csb *csb)
{
    CSB_FREAD(customName, CSD_CUSTOMNAME, 1, csb->fp);
    return (csdCustomObject *)(headCustomList->findCustomObject(customName));
    
}   // end loadCustomHeader()



static pfNode *load_node(int /*id*/, csdFile_csb *csb)
{
    int32 n_id;
    pfNode *node;
    pfType *node_type;
    all_nodes_t n;
    char customName[CSD_CUSTOMNAME];
    csdCustomObject *registeredObj = NULL;
    int i;
    int32 *children;
   
    node_type = pfNode::getClassType();
    CSB_FREAD(&n_id, sizeof(int32), 1, csb->fp);
    switch(n_id)
    {
	case L_CUSTOM:   // Must be a custom object 
	  if( registeredObj = loadCustomHeader(customName,csb) )
	  {
	     //printf("found a registered object \n");
	     node = (pfNode *)registeredObj->new_func();
	  }
	  else
	  {
              pfNotify(PFNFY_WARN, PFNFY_RESOURCE, 
	           "csdLoadFile_csb: Node type %s not found in registered types\n", 
	           customName);
              return NULL;
	  }
	  break;
	case N_GROUP:
	  node = new pfGroup();
	  node_type = pfGroup::getClassType();
	  //printf("node is a Group \n");
	  break;
	case N_SHAPE : 
	  node = new pfGeode();
	  node_type = pfGeode::getClassType();
          //printf("node is a Geode \n");
	  break;
	case N_SWITCH: 
	  node = new pfSwitch();
	  node_type = pfSwitch::getClassType();
	  //printf("node is a Switch \n");
	  break;
	case N_TRANSFORM: 
	  node = new pfDCS();
	  node_type = pfDCS::getClassType();
	  //printf("node is a DCS \n");	  	  
	  break;
	case N_LOD: 
	   node = new pfLOD();
	   node_type = pfLOD::getClassType();
	   //printf("node is a LOD \n");
	  break;
        case N_BILLBOARD:
	   // XXX billboard is not implemented yet
           // node = new pfBillboard();
	   // node_type = pfBillboard::getClassType();
           // break;
	   node = new pfGroup();
	   csBillboard_load(node, csb);
	   return node;
        case N_ENVIRONMENT:
	   // XXX environment is not implemented yet
           // node = new csEnvironment;
	   // node_type = csEnvironment::getClassType();
           // break;
	   node = new pfGroup();
	   csEnvironment_load(node, csb);
	   return node;
        case N_DIRECTIONAL_LIGHT:
	   // XXX directional light is not implemented yet
           // node = new csDirectionalLight;
	   // node_type = csDirectionalLight::getClassType();
           // break;
	   csDirectionalLight_load(NULL, csb);
	   return NULL;
        case N_POINT_LIGHT:
	   // XXX point light is not implemented yet
           // node = new csPointLight;
	   // node_type = csPointLight::getClassType();
           // break;
	   csPointLight_load(NULL, csb);
	   return NULL;
        case N_SPOT_LIGHT:
	   // XXX spot light is not implemented yet
           // node = new csSpotLight;
	   // node_type = csSpotLight::getClassType();
           // break;
	   csSpotLight_load(NULL, csb);
	   return NULL;
        case N_FOG:
	   // XXX fog is not implemented yet
           // node = new csFog;
	   // node_type = csFog::getClassType();
           // break;
	   csFog_load(NULL, csb);
	   return NULL;

        default:
	break;
    } 

   if( csb->version >= CSB_VERSION_CUSTOMSTORELOAD )
   {
      //printf("version >= CSB_VERSION_CUSTOMSTORELOAD \n");
      if (registeredObj == NULL)
      {
         //printf("registers object == NULL looking by type \n");
         registeredObj = headCustomList->findCustomObject(node_type);
      }
      
      if (registeredObj)
      {
         //printf("registeredObj is non null loading \n");
         registeredObj->load_func(node,csb);
      }
      else
      {
         //printf("registeredObj is NULL ,  what to do \n");
         node = NULL;
      }
 
   }
   else
   { 
        // for older versions, there are only 5 node types - this is faster
        // need to check in order of derivation
        if (node_type->isDerivedFrom(pfLOD::getClassType()))
        {
            csLOD_load(node, csb);
        }
        else if (node_type->isDerivedFrom(pfSwitch::getClassType()))
        {
            csSwitch_load(node, csb);
        }
        else if (node_type->isDerivedFrom(pfDCS::getClassType()))
        {
            csTransform_load(node, csb);
        }
        else if (node_type->isDerivedFrom(pfGroup::getClassType()))
        {
            pfGroup_load(node, csb);
        }
        else if (node_type->isDerivedFrom(pfGeode::getClassType()))
        {
            csShape_load(node, csb);
        }
   }
    
   //printf("loaded node \n" );
   //pfPrint(node, (PFTRAV_SELF), PFPRINT_VB_DEBUG, NULL);

   return(node);
       
}   // end load_node()

static pfGeoSet *load_box(int /*id*/, csdFile_csb *csb)
{
    pfGeoSet *gset;  
    pfMatrix m;
    box_t b;
    
    //pfNotify( PFNFY_WARN, PFNFY_PRINT,  "just say no to csBox\n" );
   
    CSB_FREAD(&b, sizeof(box_t), 1, csb->fp);
   
    gset = pfdNewCube(csb->arena);
    
    m.makeTrans( b.center[0], b.center[1], b.center[2] );
    m.postScale( m,  b.size[0], b.size[1],  b.size[2] );
    
    pfdXformGSet( gset,  m );
    
    if (b.name_size != -1)
    {
	load_name(gset, b.name_size, csb);
    }
    
    return(gset);
   
}   // end load_box()

static pfGeoSet *load_cone(int /*id*/, csdFile_csb *csb)
{
    pfGeoSet *gset;
    pfMatrix m;
    cone_t c;  
   
    //pfNotify( PFNFY_WARN,  PFNFY_PRINT,  "just say no to csCone\n" );
   
    CSB_FREAD(&c, sizeof(cone_t), 1, csb->fp); 
   
    c.height /= 2.0f;

    gset = pfdNewCone( 400,  csb->arena );
    
    m.makeTrans( c.center[0], c.center[1], c.center[2] );
    m.postScale( m,  c.bottom_radius, c.bottom_radius,  c.height );

    pfdXformGSet( gset,  m );
  
    if (c.name_size != -1)
    {
	load_name(gset, c.name_size, csb);
    }
    
    return(NULL);
      
}   // end load_cone()

static pfGeoSet *load_cylinder(int /*id*/, csdFile_csb *csb)
{
    pfGeoSet *gset;
    pfMatrix m;
    cylinder_t c;
    
    //pfNotify( PFNFY_WARN,  PFNFY_PRINT,  "just say no to csCylinder\n" ); 
       
    CSB_FREAD(&c, sizeof(cylinder_t), 1, csb->fp);

    c.height /= 2.0f;
    
    gset = pfdNewCylinder( 400,  csb->arena );
    m.makeTrans( c.center[0], c.center[1], c.center[2] );
    m.postScale( m, c.radius, c.radius, c.height );
  
    pfdXformGSet( gset,  m );
  
    if (c.name_size != -1)
    {
	load_name(gset, c.name_size, csb);
    }

    return(gset);
    
}   // end load_cylinder()

static pfGeoSet *load_sphere(int /*id*/, csdFile_csb *csb)
{
    pfGeoSet *gset;
    pfMatrix m;
    sphere_t s;
    
    CSB_FREAD(&s, sizeof(sphere_t), 1, csb->fp);
    
    gset = pfdNewSphere( 500, csb->arena );
    
    m.makeTrans( s.center[0], s.center[1], s.center[2] );
    m.scale(  s.radius, m );
   
    pfdXformGSet( gset,  m );

    if (s.name_size != -1)
    {
	load_name(gset, s.name_size, csb);
    }

    return(gset);
    
}   // end load_sphere()

// how do children get added to a sprite ?
static pfBillboard *load_sprite(int /*id*/, csdFile_csb *csb)
{
   sprite_t s; 
   pfBillboard *sprite;
   
   CSB_FREAD(&s, sizeof(sprite_t), 1, csb->fp);
   
   pfNotify( PFNFY_WARN, PFNFY_PRINT,  "csSprite not supported\n" );

   sprite = new pfBillboard();
   
   return(sprite); 
   
}   // end load_sprite()

static pfGeoSet *load_trifanset(int /*id*/, csdFile_csb *csb)
{
    pfGeoSet *trifanset;
    trifanset_t s;
    int32 *lengths;
    pfVec3 *vert = NULL;
    pfVec3 *norm = NULL;
    pfVec2 *tex_coord = NULL;
    void *color = NULL;
 
    //printf("load trifan !!! \n");
    CSB_FREAD(&s, sizeof(trifanset_t), 1, csb->fp);

    lengths = (int32 *)pfMalloc( sizeof(int32)*s.num_lengths,  
                                 csb->arena );
    CSB_FREAD(lengths, sizeof(int32), s.num_lengths, csb->fp);

    trifanset = new pfGeoSet();
    set_geoset_data( trifanset, (geoset_t *)&s, csb );
  
    // finish up geoset info
    trifanset->setPrimType( PFGS_TRIFANS );
  
    trifanset->setPrimLengths( lengths );

    load_bpc_data(trifanset, csb);

    if (s.name_size != -1)
    {
	load_name(trifanset, s.name_size, csb);
    }

    return(trifanset);
   
}   // end load_trifanset()

static void *load_connection(int /*id*/, csdFile_csb *csb)
{
   int32   storage[6];
   //void   *fromCtr;
   //void   *toCtr;

   CSB_FREAD(storage, sizeof(int32), 6, csb->fp);

   //fromCtr = (void *) csb->rl_list[storage[0]][storage[1]];
   //toCtr = (void *) csb->rl_list[storage[3]][storage[4]];

   pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported: field connections\n");

   //fromCtr->connect( storage[2], toCtr, storage[5] );

   return(NULL);   // L_CONNECTIONS is NULLs after loading.
   
}   // end load_connection


// END MAIN LOAD FUNCTIONS
//-------------------------------------------------------------------------
// LOAD HELPER FUNCTIONS

static void load_name(void */*container*/, int name_size, csdFile_csb *csb)
{
    if (name_size > 0)
    {
        CSB_FREAD((char *)csb->buf, name_size, 1,  csb->fp);
        ((char *)csb->buf)[name_size] = '\0';
        //pfNotify( PFNFY_NOTICE, PFNFY_PRINT,  "load name %s \n",  csb->buf );
    }
}   // end load_name()

static void load_node_name(pfNode *node, int name_size, csdFile_csb *csb)
{
    if (name_size > 0)
    {
        CSB_FREAD((char *)csb->buf, name_size, 1,  csb->fp);
        ((char *)csb->buf)[name_size] = '\0';
	node->setName( (char *)csb->buf );
        //pfNotify( PFNFY_NOTICE, PFNFY_PRINT,  "load name %s \n",  csb->buf );
    }
}   // end load_name()


// cosmo seems to support mixed index and non indexed geo sets
// and performer does not so convert everything to non-indexed

static void set_geoset_data( pfGeoSet *gset,  geoset_t *g,  csdFile_csb *csb)
{
    int32 *index_ptr;
    int32 index_size;
    pfVec3 *vert = NULL;
    pfVec3 *norm = NULL;
    pfVec2 *tex_coord = NULL;
    pfVec4 *color = NULL;
 
    // find pointers to attribute lists
    if( g->coords != -1 )
    {
        vert = (pfVec3 *)csb->rl_list[L_VSET][g->coords];
    }
    if( g->normals != -1 )
    {
        norm = (pfVec3 *)csb->rl_list[L_NSET][g->normals];
    }
    if( g->tex_coords != -1 )
    {
       tex_coord = (pfVec2 *)csb->rl_list[L_TSET][g->tex_coords];
    }
    if( g->colors != -1 )
    {
	color = (pfVec4 *)csb->rl_list[L_CSET][g->colors];
    }
    
    // assign attribute lists
    if( g->coord_index != -1 )
    {
       index_ptr = (int32 *)csb->rl_list[L_ISET][g->coord_index];
       index_size = csb->iset_size[g->coord_index];
       pfVec3 *new_vert = (pfVec3 *)pfMalloc( sizeof(pfVec3)*index_size,
			    csb->arena );

      for( int i = 0; i < index_size; i ++ )
      {
         new_vert[i] = vert[*index_ptr];
	 index_ptr++;
	 
      }   // end for each new vertex
       
       gset->setAttr( PFGS_COORD3,  PFGS_PER_VERTEX,  new_vert,  
                           NULL );

       // delete old vertex array, we might use it or index again ?
       // I guess clean up all indexes at end of load ??
       // this is a leak here and at the 4 spots below
       // need to to refrence counting on arrays
       // but should be able to just delete all indexes
    }
    else
    {
	gset->setAttr( PFGS_COORD3,  PFGS_PER_VERTEX,  vert,  NULL );	
    }
    
    if( g->normal_index != -1)
    {
        index_ptr = (int32 *)csb->rl_list[L_ISET][g->normal_index];
	index_size = csb->iset_size[g->normal_index];
	
	pfVec3 *new_norm = (pfVec3 *)pfMalloc( sizeof(pfVec3)*index_size,
			                       csb->arena );

        for( int i = 0; i < index_size; i ++ )
        {
             new_norm[i] = norm[*index_ptr];
	     index_ptr++;
	 
        }   // end for each new normal
  
        gset->setAttr( PFGS_NORMAL3, gnb_table[g->normal_bind],  new_norm,  
	                    NULL );	 
    }
    else
    {
	if (g->normals != -1)
	    gset->setAttr( PFGS_NORMAL3, gnb_table[g->normal_bind],  norm,  
	                    NULL );
    }
 
    if( g->color_index != -1)
    {
        index_ptr = (int32 *)csb->rl_list[L_ISET][g->color_index];
	index_size = csb->iset_size[g->color_index];
	
	pfVec4 *new_color = (pfVec4 *)pfMalloc( sizeof(pfVec4)*index_size,
			                        csb->arena );

        for( int i = 0; i < index_size; i ++ )
        {
             new_color[i] = color[*index_ptr];
	     index_ptr++;
	 
        }   // end for each new normal

       gset->setAttr( PFGS_COLOR4, gcb_table[g->color_bind],  new_color,  
	                    NULL );
    }
    else
    {
	if (g->colors != -1)
	    gset->setAttr( PFGS_COLOR4, gcb_table[g->color_bind],  color,  
	                    NULL );
    }

    if( g->tex_coord_index != -1)
    {
        index_ptr = (int32 *)csb->rl_list[L_ISET][g->tex_coord_index];
	index_size = csb->iset_size[g->tex_coord_index];
	
	pfVec2 *new_tex_coord = (pfVec2 *)pfMalloc( sizeof(pfVec2)*index_size,
			                        csb->arena );

        for( int i = 0; i < index_size; i ++ )
        {
             new_tex_coord[i] = tex_coord[*index_ptr];
	     index_ptr++;
	 
        }   // end for each new normal

        gset->setAttr( PFGS_TEXCOORD2, gtb_table[g->tex_coord_bind], 
	                new_tex_coord, NULL );
    }
    else
    {
	if (g->tex_coords != -1)
	    gset->setAttr( PFGS_TEXCOORD2, gtb_table[g->tex_coord_bind], 
			   tex_coord, NULL );
    }
    
    // finish up geoset info

    gset->setNumPrims(g->prim_count );
    
}   // end set_geoset_data()

// set node bounding sphere mode

static void set_node_data(pfNode *node, node_t *g, csdFile_csb */*csb*/)
{
    node->setBound(NULL, nbm_table[g->bound_mode]);
    if (g->sphere_bound != -1)
    {
	// XXX;

    }
    // does nothing in the cscsb loader
    //set_container_data(node, (container_t *)g, csb);
    
}   // end set_node_data()

// convert a geo set to flat shaded.
// right now all geo sets are non-index

static void convert_to_flat_shade( pfGeoSet *gset, csdFile_csb *csb  )
{
   int prim_type;
 
   prim_type = gset->getPrimType();
  
   if( prim_type == PFGS_TRISTRIPS )
   {
       if( gset->getAttrBind(PFGS_NORMAL3) == PFGS_PER_VERTEX )
       {
           fix_tristrip_normals( gset, csb ); 
       }
       gset->setPrimType(PFGS_FLAT_TRISTRIPS);
   }
   
   if( prim_type == PFGS_LINESTRIPS )
   {
       if( gset->getAttrBind(PFGS_NORMAL3) == PFGS_PER_VERTEX )
       {
           fix_linestrip_normals( gset, csb );
       }
       gset->setPrimType(PFGS_FLAT_LINESTRIPS);
   }
   
}   // end convert_to_flat_shade(

static void fix_tristrip_normals( pfGeoSet *gset,  csdFile_csb *csb  )
{
   int i;
   int k;
   int sum;
   int prim_count;
   pfVec3 *n_ptr;
   pfVec3 *norm;
   ushort *index;
   int32 *lengths; 

   gset->getAttrLists( PFGS_NORMAL3, (void **)&n_ptr, &index  );
   lengths = gset->getPrimLengths(); 
   prim_count = gset->getNumPrims();
   
   sum = 0;
   for( i = 0; i < prim_count; i++ )
   {
       sum = sum + (PF_ABS(lengths[i]) - 2);
   }
   
   pfVec3 *new_n_ptr = (pfVec3 *)pfMalloc( sizeof(pfVec3)*sum, 
                                           csb->arena );
   norm = new_n_ptr;
					   
    for( i = 0; i < prim_count; i++ )
    {
        n_ptr++; 
	n_ptr++;
	
	for(k = 2; k < PF_ABS(lengths[i]); k++ )
	{
	    new_n_ptr->vec[0] = n_ptr->vec[0];
	    new_n_ptr->vec[1] = n_ptr->vec[1];
	    new_n_ptr->vec[2] = n_ptr->vec[2];
	    new_n_ptr++;
	    n_ptr++;
	}
    }
    
    // set pointer to new normal array and delete old one
    
    gset->setAttr( PFGS_NORMAL3, PFGS_PER_VERTEX, norm, NULL );
    pfDelete( n_ptr );
   
}   // end fix_tristrip_normals()

static void fix_linestrip_normals( pfGeoSet *gset,  csdFile_csb *csb  )
{
   int i;
   int k;
   int sum;
   int prim_count;
   pfVec3 *n_ptr;
   pfVec3 *norm;
   ushort *index;
   int32 *lengths; 
   
   gset->getAttrLists( PFGS_NORMAL3, (void **)&n_ptr, &index  );
   lengths = gset->getPrimLengths(); 
   prim_count = gset->getNumPrims();
   
   sum = 0;
   for( i = 0; i < prim_count; i++ )
   {
       sum = sum + (PF_ABS(lengths[i]) - 1);
   }
   
   pfVec3 *new_n_ptr = (pfVec3 *)pfMalloc( sizeof(pfVec3)*sum, 
                                           csb->arena );
   norm = new_n_ptr;
					   
    for( i = 0; i < prim_count; i++ )
    {
        n_ptr++; 
	
	for(k = 1; k < PF_ABS(lengths[i]); k++ )
	{
	    new_n_ptr->vec[0] = n_ptr->vec[0];
	    new_n_ptr->vec[1] = n_ptr->vec[1];
	    new_n_ptr->vec[2] = n_ptr->vec[2];
	    
	    new_n_ptr++;
	    n_ptr++;
	}
    }
    
    // set pointer to new normal array and delete old one
    
    gset->setAttr( PFGS_NORMAL3, PFGS_PER_VERTEX, norm, NULL );
    pfDelete( n_ptr );
   
}   // end fix_linestrip_normals()

//-------------------------------------------------------------------
// debug functions

static void print_gset_data( geoset_t *g )
{
    printf("prim_count = %d \n",  g->prim_count );
    printf("normal_bind = %d \n",  g->normal_bind );
    printf("color_bind = %d \n",  g->color_bind );
    printf("tex_coord_bind = %d\n",  g->tex_coord_bind );
    printf("coords = %d \n", g->coords );
    printf("normals = %d \n", g->normals );
    printf("colors = %d \n", g->colors );
    printf("tex_coords = %d \n", g->tex_coords );
    printf("coord_index = %d \n", g->coord_index );
    printf("normal_index = %d \n", g->normal_index );
    printf("color_index = %d \n", g->color_index );
    printf("tex_coord_index = %d \n", g->tex_coord_index );
    printf("cull_face = %d \n\n", g->cull_face );

}   // end print_geoset_data()

static void print_appearance_data ( appearance_t *a )
{
    printf("inherit = %X \n", a->inherit );
    printf("tex = %d \n", a->tex );
    printf("tex_enable = %d \n", a->tex_enable );
    printf("tex_mode = %d \n", a->tex_mode );
    printf("tex blend color %f \t %f \t %f \t %f \n", a->tex_bcolor[0],
            a->tex_bcolor[1], a->tex_bcolor[2], a->tex_bcolor[3] );
    printf("tenv = %d \n", a->tenv);
    printf("tgen = %d \n", a->tgen);
    printf("tgen_enable = %d \n", a->tgen_enable);
    printf("mtl = %d \n", a->mtl);
    printf("light_enable = %d \n", a->light_enable);
    printf("shade_model = %d \n", a->shade_model);
    printf("transp_enable = %d \n", a->transp_enable);
    printf("transp_mode = %d \n", a->transp_mode);
    printf("alpha_func = %d \n", a->alpha_func);
    printf("alpha_ref = %d \n", a->alpha_ref);
    printf("bcolor  %f \t %f \t %f \t %f \n",  a->bcolor[0], a->bcolor[1], 
            a->bcolor[2],  a->bcolor[3] );
    printf("src_bfunc = %d \n", a->src_bfunc);
    printf("dst_bfunc = %d \n", a->dst_bfunc);
    printf("color_mask = %d \t %d \t %d \t %d \n", a->color_mask[0], 
            a->color_mask[1], a->color_mask[2], a->color_mask[3] );
    printf("depth_func = %d \n", a->depth_func);
    printf("depth_mask = %d \n", a->depth_mask);
    printf("fog_enable = %d \n", a->fog_enable);
    printf("poly_mode = %d \n", a->poly_mode);
    printf("line_stipple_pattern = %d \n", a->line_stipple_pattern);
    printf("line_stipple_factor = %d \n", a->line_stipple_factor);
    //float32 tex_transform[16]
    printf("back_mtl = %d \n", a->back_mtl);
    
}   // end print_appearance_data()

static void print_material( material_t *m )
{
    printf("amient[%f, %f, %f] \n", m->ambient[0], m->ambient[1], m->ambient[2] );
    printf("diffuse[%f, %f, %f] \n", m->diffuse[0], m->diffuse[1], m->diffuse[2] );
    printf("specular[%f, %f, %f] \n", m->specular[0], m->specular[1], m->specular[2] );
    printf("emissive[%f, %f, %f] \n", m->emissive[0],  m->emissive[1], m->emissive[2] );
    printf("shininess = %f \n", m->shininess );
    printf("transparency = %f \n", m->transparency);
    //printf("ambient_index = %d \n", m->ambient_index );
    //printf("diffuse_index = %d \n", m->diffuse_index );
    //printf("specular_index = %d \n", m->specular_index );

}   // end print_material()

static void print_lod( cslod_t *l )
{
   printf("CSLOD_DATA \n");
   printf("   offset = %d \n", l->offset );
   printf("   numRanges = %d \n", l->numRanges );
   printf("   CS_MAX_LOD_RANGES+1 = %d \n", CS_MAX_LOD_RANGES+1 );
   for( int i = 0; i < CS_MAX_LOD_RANGES; i++ )
   {
      printf("   ranges[%d] = %f \n", i, l->ranges[i] );
   }
   printf("center = %f %f %f \n", l->center[0], l->center[1], l->center[2] );
   printf("SWITCH_DATA \n");
   printf("   which_child = %d \n", l->which_child );
   printf("GROUP_DATA \n");
   printf("   num_children = %d \n", l->num_children );
   printf("NODE_DATA \n");
   printf("   bound_mode = %d \n", l->bound_mode );
   printf("   sphere_bound = %d \n", l->sphere_bound );
   printf("CONTAINER_DATA \n");
   printf("   name_size = %d \n", l->name_size );
   printf("   udata = %d \n", l->udata );
   printf("OBJECT_DATA is NULL define \n" );

}   // end print_lod()


//--------------------------------------------------------------------------------
//---------- Custom Cosmo Objects -----------------------------------------------
//--------------------------------------------------------------------------------
 


csdCustomObject::csdCustomObject(pfType *_type, const char *_name,
                        csdDescendCustomObjFuncType_csb _descend_func,
                        csdStoreCustomObjFuncType_csb _store_func,
                        csdNewCustomObjFuncType_csb _new_func,
                        csdLoadCustomObjFuncType_csb _load_func) 
: type(_type), 
  descend_func(_descend_func), store_func(_store_func),
  new_func(_new_func),load_func(_load_func)
{
     strcpy(name,(char *)_name), 
     next = NULL;
     
}   // end csdCustomObject::csdCustomObject()

void csdCustomObject::addCustomObject(csdCustomObject *obj)
{
    //Insert into list;
    csdCustomObject *tmp = this->next;
    this->next = obj;
    obj->next = tmp;

}   //end csdCustomObject::addCustomObject

csdCustomObject *csdCustomObject::findCustomObject(const char *name)
{
   csdCustomObject *list = headCustomList;
   while (list)
   {
	if (!strcmp(list->name,name))
	     return list;
	
	else 
	    list = list->next;
   }
   
   return NULL;
   
}   // end csdCustomObject::findCustomObject() by name

csdCustomObject *csdCustomObject::findCustomObject(pfType *_type)
{
   csdCustomObject *list = headCustomList;
   while (list)
   { 
	if (list->type == _type)
	{
	     return list;
	}
	else
	{
	    list = list->next;
	}
   }
   
   return NULL;
   
}   // end csdCustomObject::findCustomObject() by type

pfType *csdCustomObject::getType(void)
{
    return type;
}


/* 
 * Registering custom objects with Cosmo3D
 */
int csdAddCustomObj_csb(pfType *type, const char *name,
			csdDescendCustomObjFuncType_csb descend_func,
			csdStoreCustomObjFuncType_csb store_func,
			csdNewCustomObjFuncType_csb new_func,
			csdLoadCustomObjFuncType_csb load_func)
{

    csdCustomObject *customObj = new csdCustomObject(type,name,descend_func,
			store_func,new_func,load_func); 

    if (headCustomList)
    {
	csdCustomObject *oldObj; 
    	if (oldObj = headCustomList->findCustomObject(type))
	{
    	     // Check if type is already in list
    	     // If so, then user is overriding the default type
	     oldObj->descend_func 	= descend_func; 
	     oldObj->store_func 	= store_func; 
	     oldObj->new_func 		= new_func; 
	     oldObj->load_func 		= load_func; 

	     delete customObj;
	} else
	{
    	     headCustomList->addCustomObject(customObj);
	}

    } else
    {
	headCustomList = customObj;
    }
	
    return 0;
}


int csdDeleteCustomObj_csb(pfType *type)
{
    // XXX Remove type from list of custom objs 

    return -1;
}

//----------------------------------------------------------------------------
// Node loading functions
//----------------------------------------------------------------------------

// ********* Registering csGroup 

static pfGroup *pfGroup_new(void)
{
   return new pfGroup();
   
}   // end pfGroup_new()

static void csdLoadGroupInfo(void *obj, all_nodes_t *n, int structsize, csdFile_csb *csb)
{
    int32 *children;
    int32 num_children;
    int32 i;
    pfGroup *group = (pfGroup *)obj;
    pfNode *node_ptr;
    
#ifdef DEBUG_NODE
printf( "csdLoadGroupInfo \n");
#endif
    
    CSB_FREAD( n, structsize, 1, csb->fp);
    num_children = n->group.num_children;
    
#ifdef DEBUG_NODE
printf("group has %d children \n",  num_children );
#endif

    // Get buffer for children and read in indexes
    children = GET_BUF(num_children);
    CSB_FREAD(children, sizeof(int32), num_children, csb->fp);
    
    for (i = 0; i < num_children; i++)
    {
#ifdef DEBUG_NODE
printf("group adding child %d nod list id %d \n",  i,  children[i] );
#endif
	if (children[i] >= 0 && children[i] <= csb->curListLength)
	{
	    if (csb->rl_list[L_NODE][children[i]] != NULL)
		group->addChild((pfNode *)csb->rl_list[L_NODE][children[i]]);
	}
    } 
}

static int pfGroup_load(void *obj, csdFile_csb *csb)
{
    all_nodes_t n;
#ifdef DEBUG_NODE
printf("load group \n");
#endif
    csdLoadGroupInfo(obj,&n,sizeof(group_t),csb);
    load_node_name((pfNode *) obj, n.node.name_size, csb);

    return 0;

}   // end pfGroup_load()

// ********* Registering csTransform 
static pfDCS *pfDCS_new(void)
{
   return new pfDCS();
   
}   // end pfDCS_new()

static void csdLoadTransformInfo(void *obj, all_nodes_t *n,int structsize,csdFile_csb *csb)
{
   pfMatrix m;
   pfDCS *dcs_ptr;

#ifdef DEBUG_NODE
printf("csdLoadTransformInfo \n" );
#endif

   // Load base class info
   csdLoadGroupInfo( obj, n, structsize,csb);

   // Load csTransform info

   if (csb->version >= CSB_VERSION_TRANSFORM)
   {
	// M = -C * -SO * S * SO * R * C * T

	m.makeTrans(	n->transform.translation[0], 
			n->transform.translation[1], 
			n->transform.translation[2]);

	m.preTrans(	n->transform.center[0],
			n->transform.center[1], 
			n->transform.center[2], 
			m);

	if (n->transform.rotation[3] != 0.0f)
	    m.preRot(	PF_RAD2DEG(n->transform.rotation[3]),
			n->transform.rotation[0], 
			n->transform.rotation[1],
			n->transform.rotation[2], 
			m);

	if (n->transform.scaleOrientation[3] != 0.0f)
	    m.preRot(	PF_RAD2DEG(n->transform.scaleOrientation[3]),
			n->transform.scaleOrientation[0], 
			n->transform.scaleOrientation[1],
			n->transform.scaleOrientation[2], 
			m);

	m.preScale(	n->transform.scale[0],
			n->transform.scale[1], 
			n->transform.scale[2],
			m);

	if (n->transform.scaleOrientation[3] != 0.0f)
	    m.preRot(	PF_RAD2DEG(-n->transform.scaleOrientation[3]),
			n->transform.scaleOrientation[0], 
			n->transform.scaleOrientation[1],
			n->transform.scaleOrientation[2], 
			m);

	m.preTrans(	-n->transform.center[0],
			-n->transform.center[1], 
			-n->transform.center[2],
			m);
   }
   else
   {
	bcopy( n->transform_894.mat, m.mat, sizeof(m.mat));
   }

    dcs_ptr = (pfDCS *)obj;
    dcs_ptr->setMat(m);
   
}   // end csdLoadTransformInfo()

static int csTransform_load(void *obj, csdFile_csb *csb)
{
    all_nodes_t n;
    
    if (csb->version >= CSB_VERSION_TRANSFORM)
        csdLoadTransformInfo(obj,&n,sizeof(transform_t),csb);
    else
        csdLoadTransformInfo(obj,&n,sizeof(transform_894_t),csb);

    load_node_name((pfNode *) obj, n.node.name_size, csb);

    return 0;
    
}   // end csTransform_load()

// ******** Registering csSwitch 
static pfSwitch *pfSwitch_new(void)
{
   return new pfSwitch();
   
}   // end pfSwitch_new()

static void csdLoadSwitchInfo(void *node, all_nodes_t *n, int structsize,csdFile_csb *csb)
{
#ifdef DEBUG_NODE
printf("load switch info \n");
#endif
   
   // Load base class 
   csdLoadGroupInfo( (pfGroup *)node, n, structsize, csb);

   // Load csSwitch Info 
   if (n->swtch.which_child == CSB_SWITCH_NO_CHILDREN)
   {   
      ((pfSwitch *)node)->setVal(PFSWITCH_OFF);
   }
   else if (n->swtch.which_child == CSB_SWITCH_ALL_CHILDREN)
   {
      ((pfSwitch *)node)->setVal(PFSWITCH_ON);
   }
   else
   {
       if( n->swtch.which_child > n->group.num_children )
       {
          ((pfSwitch *)node)->setVal(PFSWITCH_ON);
       }
       else
       {
          ((pfSwitch *)node)->setVal(n->swtch.which_child);
       }
     
   }   // end else if which child 
   
}   // end csdLoadSwitchInfo()


static int csSwitch_load(void *obj, csdFile_csb *csb)
{
    all_nodes_t n;

    csdLoadSwitchInfo( obj, &n, sizeof(switch_t), csb);
    load_node_name((pfNode *)obj, n.node.name_size, csb);

    return 0;
    
}   // end csSwitch_load()

// ******** Registering csLOD 
static pfLOD *pfLOD_new(void)
{
    return new pfLOD();

}   // end pfLOD_new()

static void csdLoadLODInfo(void *node, all_nodes_t *n, int structsize,csdFile_csb *csb)
{
    // Load base class 
    csdLoadGroupInfo((pfGroup *)node,n,structsize,csb);

#ifdef DEBUG_NODE 
printf("load lod info \n");
print_lod( &n.cslod );
#endif
   
    // Load csLOD info
    pfVec3 center;
    int j;
    pfLOD *lod_ptr;
    
    lod_ptr = (pfLOD *)node;
   
    center[0] = n->cslod.center[0];
    center[1] = n->cslod.center[1];
    center[2] = n->cslod.center[2];

    lod_ptr->setCenter(center);

    for (j=0; j < n->cslod.num_children+1; j++)
    {
	//printf("setting LOD range %d = %f \n",  j, n->cslod.ranges[j] ); 
	lod_ptr->setRange(j, n->cslod.ranges[j]);
    }

}   // csdLoadLODInfo() 

static int csLOD_load(void *obj, csdFile_csb *csb)
{
    all_nodes_t n;

    csdLoadLODInfo(obj, &n, sizeof(cslod_t), csb);
    load_node_name((pfNode *) obj, n.node.name_size, csb);

    return 0;
}

// ***** Register csShape
static pfGeode *pfGeode_new(void)
{
    return new pfGeode;

}   // end pfGeode_new()

static void csdLoadShapeInfo(void *node, all_nodes_t *n, int structsize,csdFile_csb *csb)
{
    int32 *geoms;
    int i;
    int j;
    int count;
    int mode;
    int num_geometry;
    int color_bind;
    pfGeoSet *gset_ptr;
    pfGeoState *gstate_ptr;

#ifdef DEBUG_NODE
printf("load shape info \n" );
#endif
  
    pfGeode *shape = (pfGeode *)node;

    CSB_FREAD(n, structsize, 1, csb->fp);
    num_geometry = n->shape.num_geometry; 

#ifdef DEBUG_NODE
printf("geode has %d children \n", num_geometry );
#endif

    geoms = GET_BUF(num_geometry);
    CSB_FREAD(geoms, sizeof(int32), num_geometry, csb->fp);
    
    // In cosmo shape is assigned an apperance
    // which would mean in perf that geodes have geostates
    // but if we share GeoSets then we have to copy the 
    // GeoSets and then assign them GeoStates
    
    for (i = 0; i < num_geometry; i++)
    {
	if ( (geoms[i] != -1) &&
	      (csb->rl_list[L_GEOM][geoms[i]] != NULL) )
	{
	    if( n->shape.appearance != -1 )
	    {
	         if( csb->geo_ref[geoms[i]] == 0 )
		 {
		    // first use of this GeoSet don't need to clone
		    csb->geo_ref[geoms[i]] += 1;
#ifdef DEBUG_NODE		 
printf("geoset %d using geostate %d \n", geoms[i],  n.shape.appearance );
#endif
		    gset_ptr = (pfGeoSet *)csb->rl_list[L_GEOM][geoms[i]];
		    gstate_ptr = (pfGeoState *)csb->rl_list[L_APP][n->shape.appearance];
		   
		    mode = gstate_ptr->getMode( PFSTATE_SHADEMODEL);
		    if( mode == PFSM_FLAT )
		    {
			convert_to_flat_shade( gset_ptr, csb );
		    }
		    
		    shape->addGSet( gset_ptr );
		    gset_ptr->setGState( gstate_ptr );
		}
		else
		{
		     // geo set has been used before clone it
		     // so geo states don't collide
		     csb->geo_ref[geoms[i]] += 1;
#ifdef DEBUG_NODE		    
printf("REgeoset %d using geostate %d \n", geoms[i],  n.shape.appearance );
#endif
		     pfGeoSet *c_gset = new pfGeoSet();
	             gset_ptr = (pfGeoSet *)csb->rl_list[L_GEOM][geoms[i]];
		     gstate_ptr = (pfGeoState *)csb->rl_list[L_APP][n->shape.appearance];
	             pfCopy( c_gset, gset_ptr );
		     shape->addGSet( c_gset );
	             c_gset->setGState( gstate_ptr);

		     gset_ptr = c_gset;

		}   //end if ref_count == 0

		color_bind = gset_ptr->getAttrBind(PFGS_COLOR4);

    		if (csb->version < CSB_VERSION_ADDED_MATERIAL_MODE)
		{
		    if (color_bind == PFGS_OFF)
		    {
			pfMaterial *mtl = (pfMaterial *)gstate_ptr->getAttr(PFSTATE_FRONTMTL);
			if (mtl != NULL)
			    mtl->setColorMode(PFMTL_FRONT,  PFMTL_CMODE_OFF );
		    }
		}
		else  // csb->version >= CSB_VERSION_ADDED_MATERIAL_MODE
		{
		    // Remove color bindings if the appearance's 
		    // materialModeEnabled was NO_COLOR_MATERIAL.
		    // In cosmo, in this case the colorsets are ignored.

		    if (color_bind != PFGS_OFF &&
			csb->gstate_mtl_mode[n->shape.appearance] ==
			NO_COLOR_MATERIAL)
		    {
			gset_ptr->setAttr(PFGS_COLOR4, PFGS_OFF, NULL, NULL);
		    }

                    if ( csb->gstate_mtl_mode[n->shape.appearance] == NO_COLOR_MATERIAL )
                    {
                        pfMaterial *mtl = (pfMaterial *)gstate_ptr->getAttr(PFSTATE_FRONTMTL);
                        if (mtl != NULL)
                            mtl->setColorMode(PFMTL_FRONT,  PFMTL_CMODE_OFF );
                    }

		}

            }
	    else   // shape has no apperance
	    {
	       gset_ptr = (pfGeoSet *) csb->rl_list[L_GEOM][geoms[i]];
	       shape->addGSet( gset_ptr);
	       
	       if (csb->version >= CSB_VERSION_ADDED_MATERIAL_MODE)
	       {
		    // Remove color bindings since the default 
		    // materialModeEnabled for cosmo is NO_COLOR_MATERIAL.
		    // In cosmo, in this case the colorsets are ignored.

		    color_bind = gset_ptr->getAttrBind(PFGS_COLOR4);
		    if (color_bind != PFGS_OFF)
		    {
			gset_ptr->setAttr(PFGS_COLOR4, PFGS_OFF, NULL, NULL);
		    }
	       } 

	    }   // end if shape has apperance
	    
	 }   // end if index is valid
	 
    }   // end for num_geometry
    
}   // end csShape_load()

int csShape_load( void *obj, csdFile_csb *csb )
{
    all_nodes_t n;

    csdLoadShapeInfo(obj, &n, sizeof(shape_t), csb);
    load_node_name((pfNode *) obj, n.node.name_size, csb);

    return 0;
}


// ***** Register csBillboard
static void *pfBillboard_new(void)
{
    return new pfGroup();
}

static void csdLoadBillboardInfo(void *obj, all_nodes_t *n,int structsize,csdFile_csb *csb)
{
    float32 *pos;
    // pfBillboard *billboard = (pfBillboard *) obj;

    // Load base class info
    csdLoadGroupInfo(obj,n,structsize,csb);

    // billboard->position()->setCount(n->billboard.num_position);
    // pos = (float32*) billboard->position()->edit();
    pos = new float32[n->billboard.num_position * 3];
    CSB_FREAD(pos, sizeof(float32), n->billboard.num_position * 3, csb->fp);
    delete [] pos;
    // billboard->position()->editDone();

    // billboard->setAxis(n->billboard.axis[0], n->billboard.axis[1],
    //                    n->billboard.axis[2]);
    // billboard->setMode((csBillboard::ModeEnum)bbm_table[n->billboard.mode]);

    // if (csb->version >= CSB_VERSION_BILLBOARD_FORWARD_UP)
    // {
    //    billboard->setForward((csBillboard::VectorEnum)bbv_table[n->billboard.forward]);
    //    billboard->setUp((csBillboard::VectorEnum)bbv_table[n->billboard.up]);
    // }
}

static int csBillboard_load(void *obj, csdFile_csb *csb)
{
    all_nodes_t n;

    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csBillboard");

    if (csb->version >= CSB_VERSION_BILLBOARD_FORWARD_UP)
        csdLoadBillboardInfo(obj,&n,sizeof(billboard_t),csb);
    else
        csdLoadBillboardInfo(obj,&n,sizeof(billboard_t_893),csb);

    load_node_name((pfNode *)obj, n.node.name_size, csb);

    return 0;
}

// ***** Common logic for loading lights
static void csdLoadLightInfo(void */*obj*/, all_nodes_t *n, int structsize, csdFile_csb *csb)
{
    // csLight *light = (csLight*) obj;

    CSB_FREAD(n, structsize, 1, csb->fp);

    // light->setOn(n->light.on);
    // light->setIntensity(n->light.intensity);
    // light->setAmbientIntensity(n->light.ambientIntensity);
    // light->setColor(n->light.color[0], n->light.color[1], n->light.color[2]);
}

// ***** Register csDirectionalLight
static void *csDirectionalLight_new(void)
{
    // return new csDirectionalLight;
    return NULL;
}

static void csdLoadDirectionalLightInfo(void *obj, all_nodes_t *n, int structsize, csdFile_csb *csb)
{
    // csDirectionalLight *light = (csDirectionalLight*) obj;

    // Load base class info
    csdLoadLightInfo(obj,n,structsize,csb);

    // light->setDirection(n->directional_light.direction[0],
    //                    n->directional_light.direction[1],
    //                    n->directional_light.direction[2]);
}


static int csDirectionalLight_load(void *obj, csdFile_csb *csb)
{
    all_nodes_t n;

    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csDirectionalLight");

    csdLoadDirectionalLightInfo(obj, &n, sizeof(directional_light_t), csb);
    // XXX use load_node_name if directional light is derived from pfNode
    load_name(obj, n.node.name_size, csb);
    // load_node_name((pfNode *)obj, n.node.name_size, csb);

    return 0;
}

// ***** Register csPointLight
static void *csPointLight_new(void)
{
   // return new csPointLight;
   return NULL;
}


static void csdLoadPointLightInfo(void *obj, all_nodes_t *n, int structsize, csdFile_csb *csb)
{
    // csPointLight *light = (csPointLight*) obj;

    // Load base class info
    csdLoadLightInfo(obj,n,structsize,csb);

    // light->setRadius(n->point_light.radius);

    // light->setLocation(n->point_light.location[0],
    //                    n->point_light.location[1],
    //                    n->point_light.location[2]);

    // light->setAttenuation(n->point_light.attenuation[0],
    //                       n->point_light.attenuation[1],
    //                       n->point_light.attenuation[2]);
}

static int csPointLight_load(void *obj, csdFile_csb *csb)
{
    all_nodes_t n;

    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csPointLight");

    csdLoadPointLightInfo(obj, &n, sizeof(point_light_t), csb);
    // XXX use load_node_name if point light is derived from pfNode
    load_name(obj, n.node.name_size, csb);
    // load_node_name((pfNode *)obj, n.node.name_size, csb);

    return 0;
}

// ***** Register csSpotLight
static void *csSpotLight_new(void)
{
    // return new csSpotLight;
    return NULL;
}


static void csdLoadSpotLightInfo(void *obj, all_nodes_t *n, int structsize,
csdFile_csb *csb)
{
    // csSpotLight *light = (csSpotLight*) obj;

    // Load base class info
    csdLoadPointLightInfo(obj,n,structsize,csb);

    // light->setExponent(n->spot_light.exponent);
    // light->setCutOffAngle(n->spot_light.cutOffAngle);

    // light->setDirection(n->spot_light.direction[0],
    //                     n->spot_light.direction[1],
    //                     n->spot_light.direction[2]);
}


static int csSpotLight_load(void *obj, csdFile_csb *csb)
{
    all_nodes_t n;

    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csSpotLight");

    csdLoadSpotLightInfo(obj, &n, sizeof(spot_light_t), csb);
    // XXX use load_node_name if spot light is derived from pfNode
    load_name(obj, n.node.name_size, csb);
    // load_node_name((pfNode *)obj, n.node.name_size, csb);

    return 0;
}


// ***** Register csFog
static void *csFog_new(void)
{
   // return new csFog;
   return NULL;
}

static void csdLoadFogInfo(void */*obj*/, all_nodes_t *n, int structsize, csdFile_csb *csb)
{
    // csFog *fog = (csFog*) obj;

    CSB_FREAD(n, structsize, 1, csb->fp);

    // fog->setOn(n->fog.on);
    // fog->setMode((csFog::FogModeEnum)fgm_table[n->fog.mode]);
    // fog->setDensity(n->fog.density);
    // fog->setStart(n->fog.start);
    // fog->setEnd(n->fog.end);
    // fog->setIndex(n->fog.index);
    // fog->setColor(n->fog.color[0], n->fog.color[1],
    //               n->fog.color[2], n->fog.color[3]);
}


static int csFog_load(void *obj, csdFile_csb *csb)
{
    all_nodes_t n;

    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csFog");

    csdLoadFogInfo(obj, &n, sizeof(fog_t), csb);
    // XXX use load_node_name if directional light is derived from pfNode
    load_name(obj, n.node.name_size, csb);
    // load_node_name((pfNode *)obj, n.node.name_size, csb);

    return 0;
}
// ***** Register csEnvironment
static void *csEnvironment_new(void)
{
    return new pfGroup();
}

static void csdLoadEnvironmentInfo(void *obj, all_nodes_t *n, int structsize, csdFile_csb *csb)
{
    int *light, i;
    // csEnvironment *environment = (csEnvironment*) obj;

    // Load base class info
    csdLoadGroupInfo(obj,n,structsize,csb);

    // Set fog
    // if ((n->environment.fog >= 0) && (n->environment.fog <= csb->curListLength))        
    // 	environment->setFog((csFog*)csb->rl_list[L_NODE][n->environment.fog]);

    // Get buffer for lights and read in light info
    light = GET_BUF(n->environment.num_light);

    CSB_FREAD(light, sizeof(int), n->environment.num_light, csb->fp);
    // for (i = 0; i < n->environment.num_light; i++)
    // {
    //     if ((light[i] >= 0) && (light[i] <= csb->curListLength))
    //         environment->light()->set(i,
    //                     (csLight *)csb->rl_list[L_NODE][light[i]]);
    // }
}


static int csEnvironment_load(void *obj, csdFile_csb *csb)
{
    all_nodes_t n;

    pfNotify(PFNFY_WARN, PFNFY_PRINT,"Unsupported node: csEnvironment");

    csdLoadEnvironmentInfo(obj, &n, sizeof(environment_t), csb);
    load_node_name((pfNode *)obj, n.node.name_size, csb);

    return 0;
}



static void csRegisterTypes()
{
   pfType *type;

   // Register csGroup 
   type = pfGroup::getClassType();
   csdAddCustomObj_csb( type, type->getName(),
                        NULL,
                        NULL,
                        (csdNewCustomObjFuncType_csb)&pfGroup_new,
                        &pfGroup_load);

   // Register csTransform 
   type = pfDCS::getClassType();
   csdAddCustomObj_csb( type, type->getName(),
                        NULL,
                        NULL,
                        (csdNewCustomObjFuncType_csb)&pfDCS_new,
                        &csTransform_load);
   // Register csSwitch 
   type = pfSwitch::getClassType();
   csdAddCustomObj_csb( type, type->getName(),
                        NULL,
                        NULL,
                        (csdNewCustomObjFuncType_csb)&pfSwitch_new,
                        &csSwitch_load);

   // Register csLOD
   type = pfLOD::getClassType();
   csdAddCustomObj_csb( type, type->getName(),
                        NULL,
                        NULL,
                        (csdNewCustomObjFuncType_csb)&pfLOD_new,
                        &csLOD_load);

   // Register csShape
   type = pfGeode::getClassType();
   csdAddCustomObj_csb( type, type->getName(),
                        NULL,
                        NULL,
                        (csdNewCustomObjFuncType_csb)&pfGeode_new,
                        &csShape_load);

/* XXX load methods are called directly until a performer class is associated
       with these Cosmo3D types...

   // Register csBillboard
   type = pfBillboard::getClassType();
   csdAddCustomObj_csb( type, type->getName(),
			NULL,
			NULL,
                        (csdNewCustomObjFuncType_csb)&pfBillboard_new,
                        &csBillboard_load);

   // Register csEnvironment
   type = csEnvironment::getClassType();
   csdAddCustomObj_csb( type, type->getName(),
                        NULL,
                        NULL,
                        (csdNewCustomObjFuncType_csb)&csEnvironment_new,
                        &csEnvironment_load);

   // Register csSpotLight
   type = csSpotLight::getClassType();
   csdAddCustomObj_csb( type, type->getName(),
			NULL,
			NULL,
                        (csdNewCustomObjFuncType_csb)&csSpotLight_new,
                        &csSpotLight_load);

   // Register csDirectionalLight
   type = csDirectionalLight::getClassType();
   csdAddCustomObj_csb( type, type->getName(),
			NULL,
			NULL,
                        (csdNewCustomObjFuncType_csb)&csDirectionalLight_new,
                        &csDirectionalLight_load);

   // Register csPointLight
   type = csPointLight::getClassType();
   csdAddCustomObj_csb( type, type->getName(),
			NULL,
			NULL,
                        (csdNewCustomObjFuncType_csb)&csPointLight_new,
                        &csPointLight_load);

   // Register csFog
   type = csFog::getClassType();
   csdAddCustomObj_csb( type, type->getName(),
			NULL,
			NULL,
                        (csdNewCustomObjFuncType_csb)&csFog_new,
                        &csFog_load);
*/

}   // end csRegisterTypes()