#include #if defined(__WIN32__) || defined(_WIN32) # define WIN32_LEAN_AND_MEAN # include # undef WIN32_LEAN_AND_MEAN #endif #include #include #include #include #include "load3ds.h" #include "tkogl.h" /*---------------------------------------------------------------------------* * * The following are data structures corresponding to the * chunk/chunktype overall format of 3DStudio files * *---------------------------------------------------------------------------*/ typedef unsigned char byte; typedef unsigned short word; typedef unsigned long dword; typedef struct { word id; dword len; } TChunkHeader, *PChunkHeader; enum { CHUNK_RGBF = 0x0010, CHUNK_RGBB = 0x0011, CHUNK_PERCI = 0x0030, CHUNK_PERCF = 0x0031, CHUNK_MAIN = 0x4D4D, CHUNK_OBJMESH = 0x3D3D, CHUNK_BKGCOLOR = 0x1200, CHUNK_AMBCOLOR = 0x2100, CHUNK_OBJBLOCK = 0x4000, CHUNK_TRIMESH = 0x4100, CHUNK_VERTLIST = 0x4110, CHUNK_FACELIST = 0x4120, CHUNK_FACEMAT = 0x4130, CHUNK_MAPLIST = 0x4140, CHUNK_SMOOLIST = 0x4150, CHUNK_TRMATRIX = 0x4160, CHUNK_LIGHT = 0x4600, CHUNK_SPOTLIGHT = 0x4610, CHUNK_CAMERA = 0x4700, CHUNK_MATERIAL = 0xAFFF, CHUNK_MATNAME = 0xA000, CHUNK_AMBIENT = 0xA010, CHUNK_DIFFUSE = 0xA020, CHUNK_SPECULAR = 0xA030, CHUNK_SHININESS = 0xA040, CHUNK_SHININESS1= 0xA041, CHUNK_SHININESS2= 0xA042, CHUNK_TEXTURE = 0xA200, CHUNK_BUMPMAP = 0xA230, CHUNK_MAPFILE = 0xA300, CHUNK_KEYFRAMER = 0xB000, CHUNK_FRAMES = 0xB008, }; /*--------------------------------------------------------------------------- * * The following are forward declarations for * procedures for reading each chunk type * *---------------------------------------------------------------------------*/ typedef void ChunkReadProc (Tcl_DString* desc, FILE *f, long p); static ChunkReadProc ChunkReader, TriMeshReader, RGBFReader, RGBBReader, PercentIReader, PercentFReader, ObjBlockReader, VertListReader, FaceListReader, FaceMatReader, MapListReader, SmooListReader, TrMatrixReader, LightReader, SpotLightReader, CameraReader, MatNameReader, MapFileReader, FramesReader; /*--------------------------------------------------------------------------- * * The following is a table that associates each chunk type with the proper * chunk reader function and a string to be used in the property list * to be returned in a Tcl result * *---------------------------------------------------------------------------*/ struct { word id; char *name; ChunkReadProc* func; } ChunkNames[] = { {CHUNK_RGBF, "rgb", RGBFReader}, {CHUNK_RGBB, "rgb", RGBBReader}, {CHUNK_PERCI, "percent", PercentIReader}, {CHUNK_PERCF, "percent", PercentFReader}, {CHUNK_MAIN, "main", NULL}, {CHUNK_OBJMESH, "object-mesh", NULL}, {CHUNK_BKGCOLOR, "background", NULL}, {CHUNK_AMBCOLOR, "ambient", NULL}, {CHUNK_OBJBLOCK, "object-block", ObjBlockReader}, {CHUNK_TRIMESH, "tri-mesh", TriMeshReader}, {CHUNK_VERTLIST, "vertex-list", VertListReader}, {CHUNK_FACELIST, "face-list", FaceListReader}, {CHUNK_FACEMAT, "face-material", FaceMatReader}, {CHUNK_MAPLIST, "mappings-list", MapListReader}, {CHUNK_SMOOLIST, "smoothings", SmooListReader}, {CHUNK_TRMATRIX, "matrix", TrMatrixReader}, {CHUNK_LIGHT, "light", LightReader}, {CHUNK_SPOTLIGHT, "spotlight", SpotLightReader}, {CHUNK_CAMERA, "camera", CameraReader}, {CHUNK_MATERIAL, "material", NULL}, {CHUNK_MATNAME, "name", MatNameReader}, {CHUNK_AMBIENT, "ambient", NULL}, {CHUNK_DIFFUSE, "diffuse", NULL}, {CHUNK_SPECULAR, "specular", NULL}, {CHUNK_SHININESS, "shininess", NULL}, {CHUNK_SHININESS1, "shininess1", NULL}, {CHUNK_SHININESS2, "shininess2", NULL}, {CHUNK_TEXTURE, "texture-map", NULL}, {CHUNK_BUMPMAP, "bump-map", NULL}, {CHUNK_MAPFILE, "name", MapFileReader}, {CHUNK_KEYFRAMER, "keyframer-data", NULL}, {CHUNK_FRAMES, "frames", FramesReader}, }; /*--------------------------------------------------------------------------- * * The following are data structures for storing the geometry of a * Tri-Mesh object * *---------------------------------------------------------------------------*/ typedef GLfloat Vector [3]; typedef struct { int ivtx [3]; Vector normal; dword group; word flags; } FaceInfo; typedef struct SmoothInfoNode { Vector normal; dword group; struct SmoothInfoNode *next; } *SmoothList; typedef struct { Vector coord; char texFlag; GLfloat texCoord [2]; SmoothList smoothList; } VertexInfo; typedef struct FaceListNode { int idx; struct FaceListNode* next; } *FaceList; typedef struct { char name [80]; int displayList; FaceList faceList; int n; } MaterialFaceInfo; static int nmat = 0; static int nvtx = 0; static int nface = 0; static VertexInfo * vtx = NULL; static FaceInfo * face = NULL; static MaterialFaceInfo * matface = NULL; /*--------------------------------------------------------------------------- * * The following are procedures to search and modify some of the lists * used in keeping track of faces, vertices, materials, and smoothing groups * *---------------------------------------------------------------------------*/ static void AllocMatFace () { /* Allocate and initialize vector matface */ int i; assert (nmat >= 0); assert (matface == NULL); matface = (MaterialFaceInfo*) malloc (sizeof (MaterialFaceInfo) * nmat); assert (matface != NULL); for (i = 0; i < nmat; ++i) { matface [i].name [0] = '\0'; matface [i].displayList = -1; matface [i].n = 0; matface [i].faceList = (FaceList) NULL; } } static void FreeMatFace () { /* Frees the matface table */ int i, j; FaceList flist, tmp; if (matface == NULL) return; for (i = 0; i < nmat; ++i) { flist = matface [i].faceList; for (j = 0; j < matface [i].n; ++j) { assert (flist != NULL); tmp = flist->next; free (flist); flist = tmp; } assert (flist == NULL); } free (matface); matface = NULL; } static void AllocFace () { /* Allocates and initializes the face table */ int i; assert (face == NULL); assert (nface > 0); face = (FaceInfo*) malloc (sizeof (FaceInfo) * nface); assert (face != NULL); } static void FreeFace () { /* Frees memory associated with the face table */ free (face); face = NULL; nface = 0; } static void AllocVtx () { /* Allocates and initializes the vtx table */ int i; assert (vtx == NULL); assert (nvtx > 0); vtx = (VertexInfo*) malloc (sizeof (VertexInfo) * nvtx); assert (vtx != NULL); for (i = 0; i < nvtx; i++) { vtx [i].smoothList = (SmoothList) NULL; } } static void FreeVtx () { /* Deallocates heap space associated with the vtx array */ int i; for (i = 0; i < nvtx; i++) { SmoothList ptr = vtx [i].smoothList, aux; while (ptr != NULL) { aux = ptr->next; free (ptr); ptr = aux; } } free (vtx); vtx = NULL; nvtx = 0; } static int FindMatFace () { /* Finds an unused matface entry in 'matface' and returns its index */ int i; if (matface == NULL) { AllocMatFace (); } for (i = 0; i < nmat; i++) { if (matface [i].faceList == NULL) return i; } return -1; } static void FindSmooth (int ivtx, dword group) { /* Finds the in the list of normals/smoothing groups of vertex ivtx * the entry corresponding to 'group'. If it does not exist yet, one * is created. The entry is moved to the head of the list in order * to speed up new searches */ SmoothList *ptr; assert (vtx != NULL); assert (ivtx < nvtx); ptr = &(vtx [ivtx].smoothList); while (*ptr != NULL) { if ((*ptr)->group == group) break; ptr = &((*ptr)->next); } if (*ptr == NULL) { *ptr = (SmoothList) malloc (sizeof (struct SmoothInfoNode)); (*ptr)->group = group; (*ptr)->normal [0] = (*ptr)->normal [1] = (*ptr)->normal [2] = 0.0; (*ptr)->next = (SmoothList) NULL; } if (ptr != &(vtx [ivtx].smoothList)) { /* Move to front */ SmoothList aux = *ptr; *ptr = aux->next; aux->next = vtx [ivtx].smoothList; vtx [ivtx].smoothList = aux; } } static void SmoothVertices () { /* Average all vertex normals */ int i; SmoothList ptr; assert (vtx != NULL); for (i = 0; i < nvtx; i++) { for (ptr = vtx [i].smoothList; ptr != NULL; ptr = ptr->next) { float hyp = sqrt (ptr->normal [0]*ptr->normal [0]+ ptr->normal [1]*ptr->normal [1]+ ptr->normal [2]*ptr->normal [2]); if (hyp == 0.0) continue; ptr->normal [0] /= hyp; ptr->normal [1] /= hyp; ptr->normal [2] /= hyp; } } } static int RenderFaceList (FaceList ptr) { /* Renders all triangular faces in list 'ptr'. Returns * the number of the display list used. */ int disp = glGenLists (1); assert (disp >= 0); glNewList (disp, GL_COMPILE); glBegin (GL_TRIANGLES); for (;ptr != NULL; ptr = ptr->next) { int iface = ptr->idx; dword group = face [iface].group; int i; for (i = 0; i < 3; i++) { int ivtx = face [iface].ivtx [i]; FindSmooth (ivtx, group); glNormal3fv (vtx [ivtx].smoothList->normal); if (vtx [ivtx].texFlag) { glTexCoord2fv (vtx [ivtx].texCoord); } glVertex3fv (vtx [ivtx].coord); } } glEnd (); glEndList(); return disp; } static void RenderAllFaces (Tcl_DString* desc) { int imatface, iface, ivtx; char buf [80]; SmoothVertices (); if (matface == NULL) { /* No material/face list was given: render all faces with * flat normals and material = {} */ int disp = glGenLists(1); assert (disp >= 0); Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "material-face"); Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "material"); Tcl_DStringAppendElement (desc, ""); Tcl_DStringEndSublist (desc); Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "nfaces"); sprintf (buf, "%d", nface); Tcl_DStringAppendElement (desc, buf); Tcl_DStringEndSublist (desc); Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "displaylist"); sprintf (buf, "%d", disp); Tcl_DStringAppendElement (desc, buf); Tcl_DStringEndSublist (desc); Tcl_DStringEndSublist (desc); glNewList (disp, GL_COMPILE); glBegin (GL_TRIANGLES); for (iface = 0; iface < nface; iface++) { int i; glNormal3fv (face [iface].normal); for (i = 0; i < 3; i++) { int ivtx = face [iface].ivtx [i]; glVertex3fv (vtx [ivtx].coord); if (vtx [ivtx].texFlag) { glTexCoord2fv (vtx [ivtx].texCoord); } } } glEnd (); glEndList(); } else { /* Render faces in separate display lists according to matface */ for (imatface = 0; imatface < nmat; imatface++) { FaceList flist = matface [imatface].faceList; if (flist == NULL) continue; matface [imatface].displayList = RenderFaceList (flist); Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "material-face"); Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "material"); Tcl_DStringAppendElement (desc, matface [imatface].name); Tcl_DStringEndSublist (desc); Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "nfaces"); sprintf (buf, "%d", matface [imatface].n); Tcl_DStringAppendElement (desc, buf); Tcl_DStringEndSublist (desc); Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "displaylist"); sprintf (buf, "%d", matface [imatface].displayList); Tcl_DStringAppendElement (desc, buf); Tcl_DStringEndSublist (desc); Tcl_DStringEndSublist (desc); } } } /*--------------------------------------------------------------------------- * * The following are procedures for reading simple types from * a file stream. They require a fair amount of byte swapping in order * to cope with the different way Intel microprocessors store ints, floats, * etc. All procs return 1 on success and 0 if fail. * *---------------------------------------------------------------------------*/ static int ReadWord (FILE *f, word *wptr) { unsigned char b [2], tmp; if (fread (b, 2, 1, f) != 1) return 0; #if defined(__WIN32__) || defined(_WIN32) || defined(LINUX) #else printf ("Swapped\n"); fflush (stdout); tmp = b [0]; b [0] = b [1]; b [1] = tmp; #endif memcpy ((char*) wptr, b, 2); return 1; } static int ReadWords (FILE *f, word *wptr, int nwords) { while (nwords--) { if (ReadWord (f, wptr++) != 1) return 0; } return 1; } static int ReadDWord (FILE *f, dword *wptr) { word b [2], tmp; if (ReadWords (f, b, 2) != 1) return 0; #if defined(__WIN32__) || defined(_WIN32) || defined(LINUX) #else tmp = b [0]; b [0] = b [1]; b [1] = tmp; #endif memcpy ((char*) wptr, (char*) b, 4); return 1; } static int ReadFloat (FILE *f, float* fptr) { word b [2], tmp; if (ReadWords (f, b, 2) != 1) return 0; #if defined(__WIN32__) || defined(_WIN32) || defined(LINUX) #else tmp = b [0]; b [0] = b [1]; b [1] = tmp; #endif memcpy ((char*) fptr, b, 4); return 1; } static int ReadFloats (FILE *f, float *fptr, int nfloats) { while (nfloats--) { if (ReadFloat (f, fptr++) != 1) return 0; } return 1; } /*--------------------------------------------------------------------------- * * These are the various procedures for reading each chnk type. The * default behaviour is to read the chunk and * store the appropriate information * about the chunk in the Tcl Desc result string * *---------------------------------------------------------------------------*/ static int FindChunk(word id) { int i; for (i = 0; i < sizeof(ChunkNames)/sizeof(ChunkNames[0]); i++) if (id == ChunkNames[i].id) return i; return -1; } static void ChunkReader(Tcl_DString* desc, FILE *f, long p) { TChunkHeader h; int n; long pc; char buf [80]; while (ftell(f) < p) { pc = ftell(f); if (ReadWord (f, &h.id) != 1 || ReadDWord (f, &h.len) != 1) return; /* printf ("Chunk %x len = %d\n", h.id, h.len); fflush (stdout); */ n = FindChunk(h.id); if (n < 0) { /* printf ("Unknown id\n"); fflush (stdout); sprintf (buf, "unknown {id 0x%04X} {offset 0x%lX} {size %d}", h.id, pc, h.len); Tcl_DStringAppendElement (desc, buf); */ if (h.len == 0) return; fseek(f, pc + h.len, SEEK_SET); } else { Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, ChunkNames[n].name); pc = pc + h.len; if (ChunkNames[n].func != NULL) ChunkNames[n].func(desc, f, pc); else ChunkReader(desc, f, pc); Tcl_DStringEndSublist (desc); fseek(f, pc, SEEK_SET); } if (ferror(f)) break; } } static void TriMeshReader(Tcl_DString* desc, FILE *f, long p) { TChunkHeader h; int n; long pc; while (ftell(f) < p) { pc = ftell(f); if (ReadWord (f, &h.id) != 1 || ReadDWord (f, &h.len) != 1) return; n = FindChunk(h.id); if (n < 0) { fseek(f, pc + h.len, SEEK_SET); } else { Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, ChunkNames[n].name); pc = pc + h.len; if (ChunkNames[n].func != NULL) ChunkNames[n].func(desc, f, pc); else ChunkReader(desc, f, pc); Tcl_DStringEndSublist (desc); fseek(f, pc, SEEK_SET); } if (ferror(f)) break; } RenderAllFaces (desc); FreeVtx (); FreeMatFace (); FreeFace (); } static void RGBFReader (Tcl_DString* desc, FILE *f, long p) { float c[3]; char buf [80]; int i; if (ReadFloats (f, c, 3) != 1) return; for (i = 0; i < 3; ++i) { sprintf (buf, "%f", c[i]); Tcl_DStringAppendElement (desc, buf); } } static void RGBBReader (Tcl_DString* desc, FILE *f, long p) { byte c[3]; char buf [80]; int i; if (fread(&c, sizeof(c), 1, f) != 1) return; for (i = 0; i < 3; ++i) { sprintf (buf, "%f", c[i]/255.0); Tcl_DStringAppendElement (desc, buf); } } static void PercentIReader (Tcl_DString* desc, FILE *f, long p) { word perc; char buf [80]; int i; if (ReadWord (f, &perc) != 1) return; sprintf (buf, "%d", perc); Tcl_DStringAppendElement (desc, buf); } static void PercentFReader (Tcl_DString* desc, FILE *f, long p) { float perc; char buf [80]; int i; if (ReadFloat (f, &perc) != 1) return; sprintf (buf, "%f", perc); Tcl_DStringAppendElement (desc, buf); } static void ObjBlockReader (Tcl_DString* desc, FILE *f, long p) { int i, c; char buf [80]; /* Read ASCIIZ object name */ for (i = 0; i < 80; i++) { c = fgetc(f); if (c == EOF || c == '\0') break; buf [i] = c; } buf [i] = '\0'; Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "name"); Tcl_DStringAppendElement (desc, buf); Tcl_DStringEndSublist (desc); /* Read rest of chunks inside this one. */ ChunkReader(desc, f, p); } static void VertListReader (Tcl_DString* desc, FILE *f, long p) { word ivtx, nv, i; float c[3]; char buf [80]; Vector max = {-99e99, -99e99, -99e99}; Vector min = {99e99, 99e99, 99e99}; if (ReadWord (f, &nv) != 1) return; sprintf (buf, "%d", nv); Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "vertices"); Tcl_DStringAppendElement (desc, buf); Tcl_DStringEndSublist (desc); nvtx = nv; AllocVtx (); for (ivtx = 0; ivtx < nv; ivtx++) { if (ReadFloats (f, c, 3) != 1) assert (0); vtx [ivtx].texFlag = 0; for (i = 0; i < 3; i++) { vtx [ivtx].coord [i] = c [i]; if (c [i] > max [i]) max [i] = c [i]; if (c [i] < min [i]) min [i] = c [i]; } } Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "min"); for (i = 0; i < 3; i++) { sprintf (buf, "%f", min [i]); Tcl_DStringAppendElement (desc, buf); } Tcl_DStringEndSublist (desc); Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "max"); for (i = 0; i < 3; i++) { sprintf (buf, "%f", max [i]); Tcl_DStringAppendElement (desc, buf); } Tcl_DStringEndSublist (desc); } static void FaceListReader (Tcl_DString* desc, FILE *f, long p) { word iface, nv; word c[4]; char buf [80]; if (ReadWord (f, &nv) != 1) return; sprintf (buf, "%d", nv); Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "faces"); Tcl_DStringAppendElement (desc, buf); Tcl_DStringEndSublist (desc); nface = nv; AllocFace (); for (iface = 0; iface < nface; iface++) { Vector e1, e2; float hypot; if (ReadWords (f, c, 4) != 1) assert(0); face [iface].ivtx [0] = c[0]; face [iface].ivtx [1] = c[1]; face [iface].ivtx [2] = c[2]; e1 [0] = vtx[c[1]].coord[0]-vtx[c[0]].coord[0]; e1 [1] = vtx[c[1]].coord[1]-vtx[c[0]].coord[1]; e1 [2] = vtx[c[1]].coord[2]-vtx[c[0]].coord[2]; e2 [0] = vtx[c[2]].coord[0]-vtx[c[1]].coord[0]; e2 [1] = vtx[c[2]].coord[1]-vtx[c[1]].coord[1]; e2 [2] = vtx[c[2]].coord[2]-vtx[c[1]].coord[2]; face [iface].normal [0] = e1[1]*e2[2]-e1[2]*e2[1]; face [iface].normal [1] = e2[0]*e1[2]-e2[2]*e1[0]; face [iface].normal [2] = e1[0]*e2[1]-e1[1]*e2[0]; hypot = sqrt (face [iface].normal [0] * face [iface].normal [0] + face [iface].normal [1] * face [iface].normal [1] + face [iface].normal [2] * face [iface].normal [2]); if (hypot != 0.0) { face [iface].normal [0] /= hypot; face [iface].normal [1] /= hypot; face [iface].normal [2] /= hypot; } face [iface].flags = c[3]; face [iface].group = 0; } /* Read rest of chunks inside this one. */ ChunkReader(desc, f, p); } static void FaceMatReader (Tcl_DString* desc, FILE *f, long p) { int c, i, imat; word n, nf; FaceList *ptr; char buf[80]; /* Read ASCIIZ object name */ for (i = 0; i < 80; i++) { c = fgetc(f); if (c == EOF || c == '\0') break; buf [i] = c; } assert (i < 80); buf [i] = '\0'; imat = FindMatFace (buf); assert (imat >= 0 && imat < nmat); strcpy (matface [imat].name, buf); if (ReadWord (f, &n) != 1) assert (0); matface [imat].n = n; ptr = &matface [imat].faceList; while (n-- > 0) { if (ReadWord (f, &nf) != 1) assert (0); *ptr = (FaceList) malloc (sizeof (struct FaceListNode)); assert (*ptr != NULL); (*ptr)->next = NULL; (*ptr)->idx = nf; ptr = &(*ptr)->next; } } static void MapListReader (Tcl_DString* desc, FILE *f, long p) { word ivtx, nv; float c[2]; char buf[80]; if (ReadWord (f, &nv) != 1) return; Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "vertexmap"); sprintf (buf, "%d", nv); Tcl_DStringAppendElement (desc, buf); Tcl_DStringEndSublist (desc); for (ivtx = 0; ivtx < nv; ivtx++) { if (ReadFloats (f, c, 2) != 1) return; vtx [ivtx].texFlag = 1; vtx [ivtx].texCoord [0] = c [0]; vtx [ivtx].texCoord [1] = c [1]; } } static void SmooListReader (Tcl_DString* desc, FILE *f, long p) { dword s; int i, j, n, ivtx; char buf [80]; n = 0; while (ftell(f) < p) { if (ReadDWord (f, &s) != 1) assert(0); assert (n <= nface); face [n].group = s; for (i = 0; i < 3; i++) { ivtx = face [n].ivtx[i]; FindSmooth (ivtx, s); for (j = 0; j < 3; j++) { vtx [ivtx].smoothList->normal[j] += face [n].normal[j]; } } n++; } assert (n == nface); } static void TrMatrixReader(Tcl_DString* desc, FILE *f, long p) { float rot[12]; int i; char buf [80]; if (ReadFloats (f, rot, 12) != 1) return; for (i = 0; i < 12; ++i) { sprintf (buf, "%f", rot [i]); Tcl_DStringAppendElement (desc, buf); } } static void LightReader(Tcl_DString* desc, FILE *f, long p) { float c[3]; int i; char buf [80]; if (ReadFloats (f, c, 3) != 1) return; Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "position"); for (i = 0; i < 3; ++i) { sprintf (buf, "%f", c[i]); Tcl_DStringAppendElement (desc, buf); } Tcl_DStringEndSublist (desc); /* Read rest of chunks inside this one. */ ChunkReader(desc, f, p); } static void SpotLightReader(Tcl_DString* desc, FILE *f, long p) { float c[5]; char buf [80]; int i; if (ReadFloats (f, c, 5) != 1) return; Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "target"); for (i = 0; i < 3; i++) { sprintf (buf, "%f", c[i]); Tcl_DStringAppendElement (desc, buf); } Tcl_DStringAppend (desc, "} {hotspot", -1); sprintf (buf, "%f", c[3]); Tcl_DStringAppendElement (desc, buf); Tcl_DStringAppend (desc, "} {falloff", -1); sprintf (buf, "%f", c[4]); Tcl_DStringAppendElement (desc, buf); Tcl_DStringEndSublist (desc); } static void CameraReader(Tcl_DString* desc, FILE *f, long p) { float c[8]; char buf [80]; int i; if (ReadFloats (f, c, 8) != 1) return; Tcl_DStringStartSublist (desc); Tcl_DStringAppendElement (desc, "position"); for (i = 0; i < 3; i++) { sprintf (buf, "%f", c[i]); Tcl_DStringAppendElement (desc, buf); } Tcl_DStringAppend (desc, "} {target", -1); for (i = 3; i < 6; i++) { sprintf (buf, "%f", c[i]); Tcl_DStringAppendElement (desc, buf); } Tcl_DStringAppend (desc, "} {bank", -1); sprintf (buf, "%f", c[6]); Tcl_DStringAppendElement (desc, buf); Tcl_DStringAppend (desc, "} {lens", -1); sprintf (buf, "%f", c[7]); Tcl_DStringAppendElement (desc, buf); Tcl_DStringEndSublist (desc); } static void MatNameReader (Tcl_DString* desc, FILE *f, long p) { int i, c; char buf [80]; /* Read ASCIIZ object name */ for (i = 0; i < 80; i++) { c = fgetc(f); if (c == EOF || c == '\0') break; buf [i] = c; } buf [i] = '\0'; nmat++; Tcl_DStringAppendElement (desc, buf); } static void MapFileReader (Tcl_DString* desc, FILE *f, long p) { int i, c; char buf [80]; /* Read ASCIIZ object name */ for (i = 0; i < 80; i++) { c = fgetc(f); if (c == EOF || c == '\0') break; buf [i] = c; } buf [i] = '\0'; Tcl_DStringAppendElement (desc, buf); } static void FramesReader (Tcl_DString* desc, FILE *f, long p) { dword c[2]; char buf[80]; if (ReadDWord (f, &c[0]) != 1 || ReadDWord (f, &c[1]) != 1) return; Tcl_DStringStartSublist (desc); Tcl_DStringAppend (desc, "start", -1); sprintf (buf, "%d", c[0]); Tcl_DStringAppendElement (desc, buf); Tcl_DStringAppend (desc, "} {end", -1); sprintf (buf, "%d", c[1]); Tcl_DStringAppendElement (desc, buf); Tcl_DStringEndSublist (desc); } /* *--------------------------------------------------------------------------- * * This procedure loads a 3ds file created by the 3D-Studio software * package and pipes any triangles it may find into the GL pipeline * * The syntax is: * * "load3ds" * * where * is the name of an ASC file * * Result: If OK, a list where each element is a property list of * objects described in the file. Otherwise, an error message. * *--------------------------------------------------------------------------- */ int glLoad3DStudio (interp, argc, argv) Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Arg count */ char *argv []; /* Argument strings. */ { int result = TCL_OK; long p; FILE * file3D; Tcl_DString desclist; char* filename; if (argc != 3) { Tcl_AppendResult (interp, "wrong # args", (char*) NULL); return TCL_ERROR; } filename = argv [2]; #if defined(__WIN32__) || defined(_WIN32) file3D = fopen (filename, "rb"); #else file3D = fopen (filename, "r"); #endif if (file3D == NULL) { Tcl_AppendResult (interp, "Could not read ", filename, (char*) NULL); return TCL_ERROR; } /* Find file size. */ fseek(file3D, 0, SEEK_END); p = ftell(file3D); fseek(file3D, 0, SEEK_SET); /* Allocate a dynamic string to hold the result */ Tcl_DStringInit (&desclist); /* Go! */ ChunkReader(&desclist, file3D, p); fclose (file3D); Tcl_DStringResult (interp, &desclist); Tcl_DStringFree (&desclist); return result; }