Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

ModelACM.cpp

Go to the documentation of this file.
00001 /*
00002  * ModelACM.cpp
00003  *
00004  * Part of Fly! Legacy project
00005  *
00006  * Copyright 2003 Chris Wallace
00007  *
00008  * Fly! Legacy is free software; you can redistribute it and/or modify
00009  *   it under the terms of the GNU General Public License as published by
00010  *   the Free Software Foundation; either version 2 of the License, or
00011  *   (at your option) any later version.
00012  *
00013  * Fly! Legacy is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *   GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  *   along with Fly! Legacy; if not, write to the Free Software
00020  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00027 #include "../Include/Globals.h"
00028 #include "../Include/FlyLegacy.h"
00029 #include "../Include/Utility.h"
00030 
00031 
00032 //
00033 // Single frame of keyframe animation data
00034 //
00035 typedef struct {
00036   float dx, dy, dz, p, b, h;
00037 } SAcmKeyframe;
00038 
00039 //
00040 // Vertex information in an ACM part
00041 //
00042 typedef struct {
00043   float x, y, z;      // Vertex coordinates
00044   float nx, ny, nz;   // Normal coordinates
00045   float u, v;       // Texture coordinates
00046 } SAcmVertex;
00047 
00048 
00049 
00050 CModelACM::CModelACM (const char* acmFilename)
00051 {
00052   top = new ssgTransform;
00053   top->setName (acmFilename);
00054 
00055   tifftexture = NULL;
00056 
00057   PODFILE *p = popen (&globals->pfs, acmFilename);
00058   if (p == NULL) {
00059     gtfo ("CModelACM : Could not open ACM model %s", acmFilename);
00060   }
00061 
00062   GLuint texid = 0;
00063   char texfilename[256];
00064 
00065   static const int LINE_LENGTH = 128;
00066   char s[LINE_LENGTH+1];
00067 
00068   // Object type, for aircraft this should be "CAircraftModel"
00069   pgets (s, LINE_LENGTH, p);
00070   if (strncmp (s, "CAircraftModel", strlen("CAircraftModel")) != 0) {
00071     // Warning
00072     globals->logWarning->Write ("CModelACM : Incorrect object type in %s", acmFilename);
00073   }
00074 
00075   // Version, always 1 (ignored)
00076   pgets (s, LINE_LENGTH, p);
00077 
00078   // Part count
00079   int nParts;
00080   pgets (s, LINE_LENGTH, p);
00081   if (sscanf (s, "%d", &nParts) != 1) {
00082     // Error
00083     gtfo ("CModelACM : Error parsing part count in %s", acmFilename);
00084   }
00085 
00086   // Before reading parts, create a table for storage of a reference
00087   //   to each part's ssg branch so that child parts are correctly linked
00088   ssgBranch **parentList = new ssgBranch*[nParts];
00089 
00090   // Part list
00091   for (int i=0; i<nParts; i++) {
00092     // Create a new ssg branch and transform for the part.  A branch is required
00093     //   since this part may be the parent of subsequent part(s)
00094     ssgKeyframeTransform *xform = new ssgKeyframeTransform (31, 0.0f, 1.0f);
00095 
00096     // Part name
00097     char name[LINE_LENGTH];
00098     pgets (s, LINE_LENGTH, p);
00099     TrimTrailingWhitespace (s);
00100     strcpy (name, s);
00101 
00102     // Part status (on/off)
00103     pgets (s, LINE_LENGTH, p);
00104 
00105     // Parent part index
00106     int parent_index = -1;
00107     pgets (s, LINE_LENGTH, p);
00108     if (sscanf (s, "%d", &parent_index) != 1) {
00109       // Error
00110       gtfo ("CModelACM : Error parsing parent index in %s", acmFilename);
00111     }
00112 
00113     // Get a reference to the parent's ssgEntity
00114     ssgBranch *parent = top;
00115     if (parent_index != -1) {
00116       parent = parentList[parent_index];
00117     }
00118 
00119     // Save a reference to this part in the parent table
00120     parentList[i] = xform;
00121 
00122     // Version, always 1
00123     pgets (s, LINE_LENGTH, p);
00124 
00125     // Vertex count, frame count, face count, unused value
00126     int nVerts, nFrames, nFaces, dummy;
00127     pgets (s, LINE_LENGTH, p);
00128     if (sscanf (s, "%d,%d,%d,%d", &nVerts, &nFrames, &nFaces, &dummy) != 4) {
00129       // Error
00130       gtfo ("CModelACM : Error parsing vertex and face counts in %s", acmFilename);
00131     }
00132 
00133     // Optional line "vl" ???
00134     bool v1flag = false;
00135     pgets (s, LINE_LENGTH, p);
00136     if (strncmp (s, "v1", 2) == 0) {
00137       //  ?? What does this mean?
00138       v1flag = true;
00139       //  Pre-read the next line
00140       pgets (s, LINE_LENGTH, p);
00141     }
00142 
00143     // Diffuse value, specular value, specular power, use transparency,
00144     //   use environment mapping, texture name
00145     int diffuse, specular, specpower, transparent, envmap;
00146     char texturename[LINE_LENGTH];
00147     if (sscanf (s, "%d,%d,%d,%d,%d,%s",
00148       &diffuse, &specular, &specpower, &transparent, &envmap, texturename) != 6) {
00149       // Error
00150       gtfo ("CModelACM : Error parsing material parameters in %s", acmFilename) ;
00151     }
00152 
00153     // Load TIFF texture
00154     if (texid == 0) {
00155       strcpy (texfilename, texturename);
00156       char texfullname[256];
00157       strcpy (texfullname, "Art\\");
00158       strcat (texfullname, texfilename);
00159       tifftexture = new CImageTIFF (texfullname);
00160       texid = tifftexture->CreateTexture (false);
00161       if (texid == 0) {
00162         gtfo ("CModelACM : Failed to create texture from %s in %s",
00163           texfullname, acmFilename);
00164       }
00165     } else {
00166       // Doublecheck that only one texture is used across all parts
00167       if (strcmp (texfilename, texturename) != 0) {
00168         gtfo ("CModelACM : More than one texture filename in %s", acmFilename);
00169       }
00170     }
00171 
00172     // Create state information about this part
00173     ssgSimpleState *state = new ssgSimpleState ();
00174 
00175     sgVec4 spec = { 0.0f, 0.0f, 0.0f, 1.0f };
00176     sgVec4 emis = { 0.0f, 0.0f, 0.0f, 1.0f } ;
00177     float  shi  = { 0.0f } ;
00178 
00179     state -> setMaterial ( GL_SPECULAR, spec ) ;
00180     state -> setMaterial ( GL_EMISSION, emis ) ;
00181     state -> setShininess ( shi ) ;
00182     state -> enable ( GL_COLOR_MATERIAL ) ;
00183     state -> setColourMaterial ( GL_AMBIENT_AND_DIFFUSE ) ;
00184     state -> enable  ( GL_LIGHTING ) ;
00185     state -> setShadeModel ( GL_SMOOTH ) ;
00186 
00187     if (texid != 0) {
00188       // Texture was loaded, attach it to the part
00189       state-> enable (GL_TEXTURE_2D);
00190       state-> setTexture (texid);
00191 
00192       // Set rendering states for transparent/opaque parts
00193       if (transparent) {
00194         state->enable (GL_BLEND);
00195         state->enable (GL_ALPHA_TEST);
00196         state->setTranslucent();
00197       } else {
00198         state->disable (GL_BLEND);
00199         state->disable (GL_ALPHA_TEST);
00200         state->setOpaque();
00201       }
00202     } else {
00203       state->disable (GL_TEXTURE_2D);
00204       state->disable (GL_BLEND);
00205     }
00206 
00207     // If the line before last was "v1" then skip the next line, which is
00208     //   always a blank string ""
00209     if (v1flag) {
00210       pgets (s, LINE_LENGTH, p);
00211     }
00212 
00213     // Before reading vertex list, allocate table of (temporary) structs
00214     //   to hold the vertex table until the face data is read
00215     SAcmVertex *vt = new SAcmVertex[nVerts];
00216 
00217     // Vertex list
00218     for (int j=0; j<nVerts; j++) {
00219       // x, y, z, nx, ny, nz, u, v
00220       float x, y, z, nx, ny, nz, u, v;
00221       pgets (s, LINE_LENGTH, p);
00222       if (sscanf (s, "%f,%f,%f,%f,%f,%f,%f,%f",
00223         &x, &y, &z, &nx, &ny, &nz, &u, &v) != 8) {
00224         // Error
00225         gtfo ("CModelACM : Error parsing vertex %d in %s", j, acmFilename) ;
00226       }
00227 
00228       // Assign values to (temporary) vertex table
00229       // The z-coordinate is negated to perform LHS-RHS system conversion
00230       SAcmVertex *pNext = &vt[j];
00231       pNext->x = x;
00232       pNext->y = z;
00233       pNext->z = y;
00234       pNext->nx = nx;
00235       pNext->ny = nz;
00236       pNext->nz = ny;
00237       pNext->u = u;
00238       pNext->v = v;
00239 //      pNext->v = 1.0f - v;      // For libtiff loaded TIF textures
00240     }
00241 
00242     // Before beginning to parse the vertex and face lists, create arrays
00243     //   for storage of the vertices, normals, texcoords and face indices
00244     ssgVertexArray *va = new ssgVertexArray(nFaces*3);
00245     ssgNormalArray *na = new ssgNormalArray(nFaces*3);
00246     ssgTexCoordArray *tca = new ssgTexCoordArray(nFaces*3);
00247 
00248     // Face list
00249     for (int k=0; k<nFaces; k++) {
00250       // i1, i2, i3 (vertex indices, clockwise)
00251       int i1, i2, i3;
00252       pgets (s, LINE_LENGTH, p);
00253       if (sscanf (s, "%d,%d,%d",
00254         &i1, &i2, &i3) != 3)
00255       {
00256         // Error
00257         gtfo ("CModelACM : Error parsing face %d in %s", k, acmFilename) ;
00258       }
00259 
00260       // NOTE: ACM meshes are use left-hand coordinate system.
00261       //  In order to convert to OpenGL's right-hand system:
00262       //    - all triangle vertices are reversed order (3, 2, 1)
00263 
00264       // Add vertex coordinates to vertex array
00265       sgVec3 v1, v2, v3;
00266       sgSetVec3 (v1, vt[i1].x, vt[i1].y, vt[i1].z);
00267       sgSetVec3 (v2, vt[i2].x, vt[i2].y, vt[i2].z);
00268       sgSetVec3 (v3, vt[i3].x, vt[i3].y, vt[i3].z);
00269       va->add (v3);
00270       va->add (v2);
00271       va->add (v1);
00272 
00273       // Add normal coordinates to normal array
00274       sgVec3 n1, n2, n3;
00275       sgSetVec3 (n1, vt[i1].nx, vt[i1].ny, vt[i1].nz);
00276       sgSetVec3 (n2, vt[i2].nx, vt[i2].ny, vt[i2].nz);
00277       sgSetVec3 (n3, vt[i3].nx, vt[i3].ny, vt[i3].nz);
00278       na->add (n3);
00279       na->add (n2);
00280       na->add (n1);
00281 
00282       // Add texture coordinates to texcoord array
00283       sgVec2 tc1, tc2, tc3;
00284       sgSetVec2 (tc1, vt[i1].u, vt[i1].v);
00285       sgSetVec2 (tc2, vt[i2].u, vt[i2].v);
00286       sgSetVec2 (tc3, vt[i3].u, vt[i3].v);
00287       tca->add (tc3);
00288       tca->add (tc2);
00289       tca->add (tc1);
00290     }
00291 
00292     // Clean up ACM vertex list
00293     delete vt;
00294 
00295     // 31 Animation frames, each interval is therefore 1/30
00296     static const float epsilon = (float)1e-3;
00297     float kfStep = 1.0f / 30.0f;
00298     for (int m=0; m<31; m++) {
00299       // dx, dy, dz, p, b, h (???)
00300       float dx, dy, dz, pitch, bank, hdg;
00301       pgets (s, LINE_LENGTH, p);
00302       if (sscanf (s, "%f,%f,%f,%f,%f,%f",
00303         &dx, &dy, &dz, &pitch, &bank, &hdg) != 6)
00304       {
00305         // Error
00306         gtfo ("CModelACM : Error parsing animation frame %d for part %d in %s",
00307           m, i, acmFilename) ;
00308       }
00309       
00310       // Eliminate small spurious translations and rotations
00311       if (fabs(dx) < epsilon) dx = 0.0f;
00312       if (fabs(dy) < epsilon) dy = 0.0f;
00313       if (fabs(dz) < epsilon) dz = 0.0f;
00314       if (fabs(pitch) < epsilon) pitch = 0.0f;
00315       if (fabs(bank) < epsilon) bank = 0.0f;
00316       if (fabs(hdg) < epsilon) hdg = 0.0f;
00317 
00318       pitch = WrapTwoPi (pitch);
00319       bank = WrapTwoPi (bank);
00320       hdg = WrapTwoPi (hdg);
00321 
00322       // Store keyframe data
00323       // Convert from LHS-RHS coordinate system
00325       // Elevator pitch = 
00326       sgCoord kf;
00327       sgSetCoord (&kf,
00328         dx,
00329         dz,
00330         dy,
00331         -hdg * SG_RADIANS_TO_DEGREES,
00332         -pitch * SG_RADIANS_TO_DEGREES,
00333         -bank * SG_RADIANS_TO_DEGREES
00334         );
00335 
00336       xform->addKeyframe (kfStep * (float)m, &kf);
00337     }
00338 
00339     // Initialize to first keyframe
00340     xform->setKeyframe (0.0f);
00341 
00342     // Create vertex table leaf for this part
00343     ssgVtxTable *vtab = new ssgVtxTable (GL_TRIANGLES, va, na, tca, NULL);
00344     vtab->setName (name);
00345     vtab->setState (state);
00346 
00347     xform->setName (name);
00348     xform->addKid (vtab);
00349 
00350     // Add the part to the appropriate parent
00351     parent->addKid (xform);
00352   }
00353 
00354   // Delete parent list
00355   delete parentList;
00356 
00357   // Close pod file
00358   pclose (p);
00359 }
00360 
00361 CModelACM::~CModelACM (void)
00362 {
00363   if (top->getRef() == 0) {
00364     top->removeAllKids();
00365     delete top;
00366   }
00367   if (tifftexture != NULL) delete tifftexture;
00368 }
00369 
00370 ssgEntity *CModelACM::GetSSGEntity (void)
00371 {
00372   return top;
00373 }
00374 
SourceForge.net Logo Documentation generated by doxygen