aselib.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 1999-2007 id Software, Inc. and contributors.
00008 For a list of contributors, see the accompanying CONTRIBUTORS file.
00009 
00010 This file is part of GtkRadiant.
00011 
00012 GtkRadiant is free software; you can redistribute it and/or modify
00013 it under the terms of the GNU General Public License as published by
00014 the Free Software Foundation; either version 2 of the License, or
00015 (at your option) any later version.
00016 
00017 GtkRadiant is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 GNU General Public License for more details.
00021 
00022 You should have received a copy of the GNU General Public License
00023 along with GtkRadiant; if not, write to the Free Software
00024 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00025 */
00026 
00027 #include "../bsp.h"
00028 #include "shared.h"
00029 #include "aselib.h"
00030 
00031 #define MAX_ASE_MATERIALS           32
00032 #define MAX_ASE_OBJECTS             64
00033 #define MAX_ASE_ANIMATIONS          32
00034 #define MAX_ASE_ANIMATION_FRAMES    512
00035 
00036 #define VERBOSE(x) { if (ase.verbose) { Com_Printf x; } }
00037 
00038 typedef struct {
00039     float x, y, z;
00040     float nx, ny, nz;
00041     float s, t;
00042 } aseVertex_t;
00043 
00044 typedef struct {
00045     float s, t;
00046 } aseTVertex_t;
00047 
00048 typedef int aseFace_t[3];
00049 
00050 typedef struct {
00051     int numFaces;
00052     int numVertexes;
00053     int numTVertexes;
00054 
00055     int timeValue;
00056 
00057     aseVertex_t *vertexes;
00058     aseTVertex_t *tvertexes;
00059     aseFace_t *faces, *tfaces;
00060 
00061     int currentFace, currentVertex;
00062 } aseMesh_t;
00063 
00064 typedef struct {
00065     int numFrames;
00066     aseMesh_t frames[MAX_ASE_ANIMATION_FRAMES];
00067 
00068     int currentFrame;
00069 } aseMeshAnimation_t;
00070 
00071 typedef struct {
00072     char name[MAX_QPATH];
00073 } aseMaterial_t;
00074 
00078 typedef struct {
00079     char name[MAX_QPATH];
00080 
00081     int materialRef;
00082     int numAnimations;
00083 
00084     aseMeshAnimation_t anim;
00085 } aseGeomObject_t;
00086 
00087 typedef struct {
00088     int numMaterials;
00089     aseMaterial_t materials[MAX_ASE_MATERIALS];
00090     aseGeomObject_t objects[MAX_ASE_OBJECTS];
00091 
00092     char *buffer;
00093     char *curpos;
00094     int len;
00095 
00096     int currentObject;
00097     qboolean verbose;
00098 } ase_t;
00099 
00100 static char s_token[1024];
00101 static ase_t ase;
00102 
00103 static void ASE_Process(void);
00104 static void ASE_FreeGeomObject(int ndx);
00105 
00106 void ASE_Load (const char *filename, qboolean verbose)
00107 {
00108     qFILE file;
00109 
00110     FS_OpenFile(filename, &file, FILE_READ);
00111     if (!file.f && !file.z)
00112         Sys_Error("File not found '%s'", filename);
00113 
00114     memset(&ase, 0, sizeof(ase));
00115 
00116     ase.verbose = verbose;
00117     ase.len = FS_FileLength(&file);
00118 
00119     ase.curpos = ase.buffer = Mem_Alloc(ase.len);
00120     if (!ase.curpos)
00121         Sys_Error("Could not allocate memory for ase loading");
00122 
00123     Verb_Printf(VERB_EXTRA, "Processing '%s'\n", filename);
00124 
00125     if (FS_Read(ase.buffer, ase.len, &file) != 1) {
00126         FS_CloseFile(&file);
00127         Sys_Error("fread() != -1 for '%s'", filename);
00128     }
00129 
00130     FS_CloseFile(&file);
00131 
00132     ASE_Process();
00133 }
00134 
00135 void ASE_Free (void)
00136 {
00137     int i;
00138 
00139     for (i = 0; i < ase.currentObject; i++)
00140         ASE_FreeGeomObject(i);
00141 }
00142 
00143 int ASE_GetNumSurfaces (void)
00144 {
00145     return ase.currentObject;
00146 }
00147 
00148 const char *ASE_GetSurfaceName (int which)
00149 {
00150     aseGeomObject_t *pObject = &ase.objects[which];
00151 
00152     if (!pObject->anim.numFrames)
00153         return 0;
00154 
00155     return pObject->name;
00156 }
00157 
00161 polyset_t *ASE_GetSurfaceAnimation (int whichSurface)
00162 {
00163     aseGeomObject_t *pObject = &ase.objects[whichSurface];
00164     polyset_t *psets;
00165     int numFramesInAnimation;
00166     int i, f;
00167 
00168     if (!pObject->anim.numFrames)
00169         return 0;
00170 
00171     numFramesInAnimation = pObject->anim.numFrames;
00172 
00173     psets = Mem_Alloc(sizeof(polyset_t) * numFramesInAnimation);
00174 
00175     for (f = 0, i = 0; i < numFramesInAnimation; i++) {
00176         int t;
00177         aseMesh_t *pMesh = &pObject->anim.frames[i];
00178 
00179         strcpy(psets[f].name, pObject->name);
00180         strcpy(psets[f].materialname, ase.materials[pObject->materialRef].name);
00181 
00182         psets[f].triangles = calloc(sizeof(triangle_t) * pObject->anim.frames[i].numFaces, 1);
00183         psets[f].numtriangles = pObject->anim.frames[i].numFaces;
00184 
00185         for (t = 0; t < pObject->anim.frames[i].numFaces; t++) {
00186             int k;
00187 
00188             for (k = 0; k < 3; k++) {
00189                 psets[f].triangles[t].verts[k][0] = pMesh->vertexes[pMesh->faces[t][k]].x;
00190                 psets[f].triangles[t].verts[k][1] = pMesh->vertexes[pMesh->faces[t][k]].y;
00191                 psets[f].triangles[t].verts[k][2] = pMesh->vertexes[pMesh->faces[t][k]].z;
00192 
00193                 if (pMesh->tvertexes && pMesh->tfaces) {
00194                     psets[f].triangles[t].texcoords[k][0] = pMesh->tvertexes[pMesh->tfaces[t][k]].s;
00195                     psets[f].triangles[t].texcoords[k][1] = pMesh->tvertexes[pMesh->tfaces[t][k]].t;
00196                 }
00197             }
00198         }
00199 
00200         f++;
00201     }
00202 
00203     return psets;
00204 }
00205 
00206 static void ASE_FreeGeomObject (int ndx)
00207 {
00208     aseGeomObject_t *pObject;
00209     int i;
00210 
00211     pObject = &ase.objects[ndx];
00212 
00213     for (i = 0; i < pObject->anim.numFrames; i++) {
00214         if (pObject->anim.frames[i].vertexes)
00215             Mem_Free(pObject->anim.frames[i].vertexes);
00216         if (pObject->anim.frames[i].tvertexes)
00217             Mem_Free(pObject->anim.frames[i].tvertexes);
00218         if (pObject->anim.frames[i].faces)
00219             Mem_Free(pObject->anim.frames[i].faces);
00220         if (pObject->anim.frames[i].tfaces)
00221             Mem_Free(pObject->anim.frames[i].tfaces);
00222     }
00223 
00224     memset(pObject, 0, sizeof(*pObject));
00225 }
00226 
00227 static aseMesh_t *ASE_GetCurrentMesh (void)
00228 {
00229     aseGeomObject_t *pObject;
00230 
00231     if (ase.currentObject >= MAX_ASE_OBJECTS)
00232         Sys_Error("Too many GEOMOBJECTs");
00233 
00234     pObject = &ase.objects[ase.currentObject];
00235 
00236     if (pObject->anim.currentFrame >= MAX_ASE_ANIMATION_FRAMES)
00237         Sys_Error("Too many MESHes");
00238 
00239     return &pObject->anim.frames[pObject->anim.currentFrame];
00240 }
00241 
00242 static inline int CharIsTokenDelimiter (int ch)
00243 {
00244     if (ch <= ' ')
00245         return 1;
00246     return 0;
00247 }
00248 
00249 static int ASE_GetToken (qboolean restOfLine)
00250 {
00251     int i = 0;
00252 
00253     if (ase.buffer == 0)
00254         return 0;
00255 
00256     if ((ase.curpos - ase.buffer) == ase.len)
00257         return 0;
00258 
00259     /* skip over crap */
00260     while (ase.curpos - ase.buffer < ase.len && *ase.curpos <= ' ') {
00261         ase.curpos++;
00262     }
00263 
00264     while ((ase.curpos - ase.buffer) < ase.len) {
00265         s_token[i] = *ase.curpos;
00266 
00267         ase.curpos++;
00268         i++;
00269 
00270         if ((CharIsTokenDelimiter(s_token[i - 1]) && !restOfLine) ||
00271             (s_token[i - 1] == '\n' || s_token[i - 1] == '\r')) {
00272             s_token[i - 1] = 0;
00273             break;
00274         }
00275     }
00276 
00277     s_token[i] = 0;
00278 
00279     return 1;
00280 }
00281 
00282 static void ASE_ParseBracedBlock (void (*parser)(const char *token))
00283 {
00284     int indent = 0;
00285 
00286     while (ASE_GetToken(qfalse)) {
00287         if (!strcmp(s_token, "{")) {
00288             indent++;
00289         } else if (!strcmp(s_token, "}")) {
00290             --indent;
00291             if (indent == 0)
00292                 break;
00293             else if (indent < 0)
00294                 Sys_Error("Unexpected '}'");
00295         } else {
00296             if (parser)
00297                 parser(s_token);
00298         }
00299     }
00300 }
00301 
00302 static void ASE_SkipEnclosingBraces (void)
00303 {
00304     int indent = 0;
00305 
00306     while (ASE_GetToken(qfalse)) {
00307         if (!strcmp(s_token, "{")) {
00308             indent++;
00309         } else if (!strcmp(s_token, "}")) {
00310             indent--;
00311             if (indent == 0)
00312                 break;
00313             else if (indent < 0)
00314                 Sys_Error("Unexpected '}'");
00315         }
00316     }
00317 }
00318 
00319 static void ASE_SkipRestOfLine (void)
00320 {
00321     ASE_GetToken(qtrue);
00322 }
00323 
00324 static void ASE_KeyMAP_DIFFUSE (const char *token)
00325 {
00326     if (!strcmp(token, "*BITMAP")) {
00327         const char *bitmap;
00328         size_t len;
00329 
00330         ASE_GetToken(qfalse);
00331 
00332         /* skip the " */
00333         bitmap = &s_token[1];
00334         len = strlen(bitmap) - 1;
00335         s_token[len] = '\0';
00336 
00337         Com_StripExtension(bitmap, ase.materials[ase.numMaterials].name, MAX_QPATH);
00338         Verb_Printf(VERB_EXTRA, "ase material name: \'%s\'\n", ase.materials[ase.numMaterials].name);
00339     }
00340 }
00341 
00342 static void ASE_KeyMATERIAL (const char *token)
00343 {
00344     if (!strcmp(token, "*MAP_DIFFUSE"))
00345         ASE_ParseBracedBlock(ASE_KeyMAP_DIFFUSE);
00346 }
00347 
00348 static void ASE_KeyMATERIAL_LIST (const char *token)
00349 {
00350     if (!strcmp(token, "*MATERIAL_COUNT")) {
00351         ASE_GetToken(qfalse);
00352         VERBOSE(("..num materials: %s\n", s_token));
00353         if (atoi(s_token) > MAX_ASE_MATERIALS) {
00354             Sys_Error("Too many materials!");
00355         }
00356         ase.numMaterials = 0;
00357     } else if (!strcmp(token, "*MATERIAL")) {
00358         VERBOSE(("..material %d ", ase.numMaterials));
00359         ASE_ParseBracedBlock(ASE_KeyMATERIAL);
00360         ase.numMaterials++;
00361     }
00362 }
00363 
00364 static void ASE_KeyMESH_VERTEX_LIST (const char *token)
00365 {
00366     aseMesh_t *pMesh = ASE_GetCurrentMesh();
00367 
00368     if (!strcmp(token, "*MESH_VERTEX")) {
00369         ASE_GetToken(qfalse);       /* skip number */
00370 
00371         ASE_GetToken(qfalse);
00372         pMesh->vertexes[pMesh->currentVertex].y = atof(s_token);
00373 
00374         ASE_GetToken(qfalse);
00375         pMesh->vertexes[pMesh->currentVertex].x = -atof(s_token);
00376 
00377         ASE_GetToken(qfalse);
00378         pMesh->vertexes[pMesh->currentVertex].z = atof(s_token);
00379 
00380         pMesh->currentVertex++;
00381 
00382         if (pMesh->currentVertex > pMesh->numVertexes)
00383             Sys_Error("pMesh->currentVertex >= pMesh->numVertexes");
00384     } else
00385         Sys_Error("Unknown token '%s' while parsing MESH_VERTEX_LIST", token);
00386 }
00387 
00388 static void ASE_KeyMESH_FACE_LIST (const char *token)
00389 {
00390     aseMesh_t *pMesh = ASE_GetCurrentMesh();
00391 
00392     if (!strcmp(token, "*MESH_FACE")) {
00393         ASE_GetToken(qfalse);   /* skip face number */
00394 
00395         ASE_GetToken(qfalse);   /* skip label */
00396         ASE_GetToken(qfalse);   /* first vertex */
00397         pMesh->faces[pMesh->currentFace][0] = atoi(s_token);
00398 
00399         ASE_GetToken(qfalse);   /* skip label */
00400         ASE_GetToken(qfalse);   /* second vertex */
00401         pMesh->faces[pMesh->currentFace][2] = atoi(s_token);
00402 
00403         ASE_GetToken(qfalse);   /* skip label */
00404         ASE_GetToken(qfalse);   /* third vertex */
00405         pMesh->faces[pMesh->currentFace][1] = atoi(s_token);
00406 
00407         ASE_GetToken(qtrue);
00408 
00409 #if 0
00410         if ((p = strstr(s_token, "*MESH_MTLID")) != 0) {
00411             p += strlen("*MESH_MTLID") + 1;
00412             mtlID = atoi(p);
00413         } else {
00414             Sys_Error("No *MESH_MTLID found for face!");
00415         }
00416 #endif
00417 
00418         pMesh->currentFace++;
00419     } else
00420         Sys_Error("Unknown token '%s' while parsing MESH_FACE_LIST", token);
00421 }
00422 
00423 static void ASE_KeyTFACE_LIST (const char *token)
00424 {
00425     aseMesh_t *pMesh = ASE_GetCurrentMesh();
00426 
00427     if (!strcmp(token, "*MESH_TFACE")) {
00428         int a, b, c;
00429 
00430         ASE_GetToken(qfalse);
00431 
00432         ASE_GetToken(qfalse);
00433         a = atoi(s_token);
00434         ASE_GetToken(qfalse);
00435         c = atoi(s_token);
00436         ASE_GetToken(qfalse);
00437         b = atoi(s_token);
00438 
00439         pMesh->tfaces[pMesh->currentFace][0] = a;
00440         pMesh->tfaces[pMesh->currentFace][1] = b;
00441         pMesh->tfaces[pMesh->currentFace][2] = c;
00442 
00443         pMesh->currentFace++;
00444     } else
00445         Sys_Error("Unknown token '%s' in MESH_TFACE", token);
00446 }
00447 
00448 static void ASE_KeyMESH_TVERTLIST (const char *token)
00449 {
00450     aseMesh_t *pMesh = ASE_GetCurrentMesh();
00451 
00452     if (!strcmp(token, "*MESH_TVERT")) {
00453         char u[80], v[80], w[80];
00454 
00455         ASE_GetToken(qfalse);
00456 
00457         ASE_GetToken(qfalse);
00458         strcpy(u, s_token);
00459 
00460         ASE_GetToken(qfalse);
00461         strcpy(v, s_token);
00462 
00463         ASE_GetToken(qfalse);
00464         strcpy(w, s_token);
00465 
00466         pMesh->tvertexes[pMesh->currentVertex].s = atof(u);
00467         pMesh->tvertexes[pMesh->currentVertex].t = 1.0f - atof(v);
00468 
00469         pMesh->currentVertex++;
00470 
00471         if (pMesh->currentVertex > pMesh->numTVertexes) {
00472             Sys_Error("pMesh->currentVertex > pMesh->numTVertexes");
00473         }
00474     } else
00475         Sys_Error("Unknown token '%s' while parsing MESH_TVERTLIST", token);
00476 }
00477 
00478 static void ASE_KeyMESH (const char *token)
00479 {
00480     aseMesh_t *pMesh = ASE_GetCurrentMesh();
00481 
00482     if (!strcmp(token, "*TIMEVALUE")) {
00483         ASE_GetToken(qfalse);
00484 
00485         pMesh->timeValue = atoi(s_token);
00486         VERBOSE((".....timevalue: %d\n", pMesh->timeValue));
00487     } else if (!strcmp(token, "*MESH_NUMVERTEX")) {
00488         ASE_GetToken(qfalse);
00489 
00490         pMesh->numVertexes = atoi(s_token);
00491         VERBOSE((".....TIMEVALUE: %d\n", pMesh->timeValue));
00492         VERBOSE((".....num vertexes: %d\n", pMesh->numVertexes));
00493     } else if (!strcmp(token, "*MESH_NUMFACES")) {
00494         ASE_GetToken(qfalse);
00495 
00496         pMesh->numFaces = atoi(s_token);
00497         VERBOSE((".....num faces: %d\n", pMesh->numFaces));
00498     } else if (!strcmp(token, "*MESH_NUMTVFACES")) {
00499         ASE_GetToken(qfalse);
00500 
00501         if (atoi(s_token) != pMesh->numFaces)
00502             Sys_Error("MESH_NUMTVFACES != MESH_NUMFACES");
00503     } else if (!strcmp(token, "*MESH_NUMTVERTEX")) {
00504         ASE_GetToken(qfalse);
00505 
00506         pMesh->numTVertexes = atoi(s_token);
00507         VERBOSE((".....num tvertexes: %d\n", pMesh->numTVertexes));
00508     } else if (!strcmp(token, "*MESH_VERTEX_LIST")) {
00509         pMesh->vertexes = calloc(sizeof(aseVertex_t) * pMesh->numVertexes, 1);
00510         pMesh->currentVertex = 0;
00511         VERBOSE((".....parsing MESH_VERTEX_LIST\n"));
00512         ASE_ParseBracedBlock(ASE_KeyMESH_VERTEX_LIST);
00513     } else if (!strcmp(token, "*MESH_TVERTLIST")) {
00514         pMesh->currentVertex = 0;
00515         pMesh->tvertexes = calloc(sizeof(aseTVertex_t) * pMesh->numTVertexes, 1);
00516         VERBOSE((".....parsing MESH_TVERTLIST\n"));
00517         ASE_ParseBracedBlock(ASE_KeyMESH_TVERTLIST);
00518     } else if (!strcmp(token, "*MESH_FACE_LIST")) {
00519         pMesh->faces = calloc(sizeof(aseFace_t) * pMesh->numFaces, 1);
00520         pMesh->currentFace = 0;
00521         VERBOSE((".....parsing MESH_FACE_LIST\n"));
00522         ASE_ParseBracedBlock(ASE_KeyMESH_FACE_LIST);
00523     } else if (!strcmp(token, "*MESH_TFACELIST")) {
00524         pMesh->tfaces = calloc(sizeof(aseFace_t) * pMesh->numFaces, 1);
00525         pMesh->currentFace = 0;
00526         VERBOSE((".....parsing MESH_TFACE_LIST\n"));
00527         ASE_ParseBracedBlock(ASE_KeyTFACE_LIST);
00528     } else if (!strcmp(token, "*MESH_NORMALS")) {
00529         ASE_ParseBracedBlock(0);
00530     }
00531 }
00532 
00533 static void ASE_KeyGEOMOBJECT (const char *token)
00534 {
00535     if (!strcmp(token, "*NODE_NAME")) {
00536         char *name = ase.objects[ase.currentObject].name;
00537 
00538         ASE_GetToken(qtrue);
00539         VERBOSE((" %s\n", s_token));
00540         strcpy(ase.objects[ase.currentObject].name, s_token + 1);
00541         if (strchr(ase.objects[ase.currentObject].name, '"'))
00542             *strchr(ase.objects[ase.currentObject].name, '"') = 0;
00543 
00544         if (strstr(name, "tag") == name) {
00545             while (strchr(name, '_') != strrchr(name, '_')) {
00546                 *strrchr(name, '_') = 0;
00547             }
00548             while (strrchr(name, ' ')) {
00549                 *strrchr(name, ' ') = 0;
00550             }
00551         }
00552     } else if (!strcmp(token, "*NODE_PARENT")) {
00553         ASE_SkipRestOfLine();
00554     }
00555     /* ignore unused data blocks */
00556     else if (!strcmp(token, "*NODE_TM") || !strcmp(token, "*TM_ANIMATION")) {
00557         ASE_ParseBracedBlock(0);
00558     }
00559     /* ignore regular meshes that aren't part of animation */
00560     else if (!strcmp(token, "*MESH")) {
00561 #if 0
00562         if (strstr(ase.objects[ase.currentObject].name, "tag_") == ase.objects[ase.currentObject].name) {
00563             s_forceStaticMesh = true;
00564             ASE_ParseBracedBlock(ASE_KeyMESH);
00565             s_forceStaticMesh = false;
00566         }
00567 #endif
00568         ASE_ParseBracedBlock(ASE_KeyMESH);
00569         if (++ase.objects[ase.currentObject].anim.currentFrame == MAX_ASE_ANIMATION_FRAMES) {
00570             Sys_Error("Too many animation frames");
00571         }
00572         ase.objects[ase.currentObject].anim.numFrames = ase.objects[ase.currentObject].anim.currentFrame;
00573         ase.objects[ase.currentObject].numAnimations++;
00574 #if 0
00575         /* ignore meshes that aren't part of animations if this object isn't a a tag */
00576         else {
00577             ASE_ParseBracedBlock(0);
00578         }
00579 #endif
00580     }
00581     /* according to spec these are obsolete */
00582     else if (!strcmp(token, "*MATERIAL_REF")) {
00583         ASE_GetToken(qfalse);
00584 
00585         ase.objects[ase.currentObject].materialRef = atoi(s_token);
00586     }
00587     /* ignore sequences of animation frames */
00588     else if (!strcmp(token, "*MESH_ANIMATION")) {
00589         ASE_SkipEnclosingBraces();
00590     }
00591     /* skip unused info */
00592     else if (!strcmp(token, "*PROP_MOTIONBLUR") || !strcmp(token, "*PROP_CASTSHADOW") || !strcmp(token, "*PROP_RECVSHADOW")) {
00593         ASE_SkipRestOfLine();
00594     }
00595 }
00596 
00597 static void ConcatenateObjects (aseGeomObject_t *pObjA, aseGeomObject_t *pObjB)
00598 {
00599 }
00600 
00601 static void CollapseObjects (void)
00602 {
00603     int i;
00604     int numObjects = ase.currentObject;
00605 
00606     for (i = 0; i < numObjects; i++) {
00607         int j;
00608 
00609         /* skip tags */
00610         if (strstr(ase.objects[i].name, "tag") == ase.objects[i].name)
00611             continue;
00612 
00613         if (!ase.objects[i].numAnimations)
00614             continue;
00615 
00616         for (j = i + 1; j < numObjects; j++) {
00617             if (strstr(ase.objects[j].name, "tag") == ase.objects[j].name)
00618                 continue;
00619 
00620             if (ase.objects[i].materialRef == ase.objects[j].materialRef)
00621                 if (ase.objects[j].numAnimations)
00622                     ConcatenateObjects(&ase.objects[i], &ase.objects[j]);
00623         }
00624     }
00625 }
00626 
00627 static void ASE_Process (void)
00628 {
00629     while (ASE_GetToken(qfalse)) {
00630         if (!strcmp(s_token, "*3DSMAX_ASCIIEXPORT") || !strcmp(s_token, "*COMMENT")) {
00631             ASE_SkipRestOfLine();
00632         } else if (!strcmp(s_token, "*SCENE"))
00633             ASE_SkipEnclosingBraces();
00634         else if (!strcmp(s_token, "*MATERIAL_LIST")) {
00635             VERBOSE(("MATERIAL_LIST\n"));
00636 
00637             ASE_ParseBracedBlock(ASE_KeyMATERIAL_LIST);
00638         } else if (!strcmp(s_token, "*GEOMOBJECT")) {
00639             VERBOSE(("GEOMOBJECT"));
00640 
00641             ASE_ParseBracedBlock(ASE_KeyGEOMOBJECT);
00642 
00643             if (strstr(ase.objects[ase.currentObject].name, "Bip") ||
00644                 strstr(ase.objects[ase.currentObject].name, "ignore_")) {
00645                 ASE_FreeGeomObject(ase.currentObject);
00646                 VERBOSE(("(discarding BIP/ignore object)\n"));
00647             } else {
00648                 if (++ase.currentObject == MAX_ASE_OBJECTS) {
00649                     Sys_Error("Too many GEOMOBJECTs");
00650                 }
00651             }
00652         } else if (s_token[0]) {
00653             Com_Printf("Unknown token '%s'\n", s_token);
00654         }
00655     }
00656 
00657     if (!ase.currentObject)
00658         Sys_Error("No animation data!");
00659 
00660     CollapseObjects();
00661 }

Generated by  doxygen 1.6.2