Back to index

extremetuxracer  0.5beta
model_ac.cpp
Go to the documentation of this file.
00001 /* 
00002  * Copyright (C) 2004-2005 Volker Stroebel <volker@planetpenguin.de>
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  * 
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  * 
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017  */
00018  
00019 /*
00020  * This code is based on the example loader from www.ac3d.org
00021  */
00022 
00023 
00024 #include "model_ac.h"
00025 
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <math.h>
00030 
00031 #ifdef _WIN32
00032        #include <WTypes.h>
00033 #endif
00034 
00035 #include <GL/gl.h>
00036 #include <GL/glu.h>
00037 
00038 #include "../textures.h"
00039 
00040 namespace pp{
00041        
00042 #define OBJECT_WORLD 999
00043 #define OBJECT_NORMAL 0
00044 #define OBJECT_GROUP 1
00045 #define OBJECT_LIGHT 2
00046 
00047 #define SURFACE_SHADED (1<<4)
00048 #define SURFACE_TWOSIDED (1<<5)
00049 
00050 #define SURFACE_TYPE_POLYGON (0)
00051 #define SURFACE_TYPE_CLOSEDLINE (1)
00052 #define SURFACE_TYPE_LINE (2)
00053 
00054 Surface::Surface()
00055  : uvs(NULL),
00056    flags(0),
00057    mat(0)
00058 {
00059 }
00060        
00061 Surface::~Surface()
00062 {
00063        //todo: check if we need to free something       
00064 }
00065 
00066 ModelObject::ModelObject()
00067 {
00068     loc.x = loc.y = loc.z = 0.0;
00069     vertices = NULL;
00070     num_vert = 0;
00071     surfaces = NULL;
00072     num_surf = 0;
00073     texture = -1;
00074     texture_repeat_x = texture_repeat_y = 1.0;
00075     texture_offset_x = texture_offset_y = 0.0;
00076     kids = NULL;
00077     num_kids = 0;
00078     matrix[0] = 1;
00079     matrix[1] = 0;
00080     matrix[2] = 0;
00081     matrix[3] = 0;
00082     matrix[4] = 1;
00083     matrix[5] = 0;
00084     matrix[6] = 0;
00085     matrix[7] = 0;
00086     matrix[8] = 1;
00087 }
00088        
00089 ModelObject::~ModelObject()
00090 {
00091        for (int i = 0; i < num_kids; i++){
00092               delete kids[i];
00093        }
00094 
00095        if (vertices)
00096               free(vertices);
00097 
00098        for (int i = 0; i < num_surf; i++){
00099               delete(surfaces[i].vertices);
00100               delete(surfaces[i].uvs);
00101        }
00102 
00103        if (surfaces)
00104               delete(surfaces);
00105 }
00106 
00107 ModelAC::ModelAC(const char *fileName)
00108  : mp_model(NULL),
00109    m_tokc(0),
00110    m_line(0),
00111    m_numPalette(0),
00112    m_startMatIndex(0)
00113 {
00114     FILE *f = fopen(fileName, "r");
00115    
00116     if (f == NULL){
00117               printf("can't open %s\n", fileName);
00118               return;
00119     }
00120 
00121     readLine(f);
00122 
00123     if (strncmp(ma_buff, "AC3D", 4)){
00124               printf("ac_load_ac '%s' is not a valid AC3D file.", fileName);
00125               fclose(f);
00126               return;
00127     }
00128     m_startMatIndex = m_numPalette;
00129     mp_model = loadObject(f, NULL);
00130     fclose(f);
00131     calculateVertexNormals(mp_model);     
00132 }
00133        
00134 int
00135 ModelAC::getDisplayList()
00136 {
00137        int list;
00138     list = glGenLists(1);
00139     glNewList(list,GL_COMPILE);
00140        render(mp_model);
00141     glEndList();
00142     return(list);
00143 }
00144 
00145 int
00146 ModelAC::loadTexture(const char *fileName)
00147 {
00148     GLuint texid;
00149        std::string binding("ac/");
00150        binding+=fileName;
00151        
00152        if(!get_texture_binding( binding.c_str(), &texid )){
00153               load_and_bind_texture(binding.c_str(),fileName);
00154               get_texture_binding( binding.c_str(), &texid );
00155        }
00156        
00157        return texid; 
00158 }
00159 
00160 void
00161 ModelAC::prepareRender()
00162 {
00163 
00164     glDepthFunc(GL_LESS);
00165     glEnable(GL_DEPTH_TEST);
00166     glShadeModel(GL_SMOOTH);
00167 
00168     glDisable( GL_COLOR_MATERIAL ); 
00169 
00170     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00171     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
00172     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00173     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
00174     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00175     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00176 
00177 }
00178 
00179 void
00180 ModelAC::render(ModelObject *ob)
00181 {
00182     int n, s, sr;
00183     int st;
00184 
00185     glPushMatrix();
00186 
00187     glTranslated(ob->loc.x, ob->loc.y, ob->loc.z);
00188 
00189     if (ob->texture != -1){
00190               static int lasttextureset = -1;
00191  
00192               glEnable(GL_TEXTURE_2D);
00193 
00194               if (ob->texture != lasttextureset){
00195                      glBindTexture(GL_TEXTURE_2D, ob->texture);
00196                      lasttextureset = ob->texture;
00197               }
00198        } else {
00199         glDisable(GL_TEXTURE_2D);
00200        }
00201 
00202     for (s = 0; s < ob->num_surf; s++){
00203               Surface *surf = &ob->surfaces[s];
00204 
00205               glNormal3dv((double*)&surf->normal);
00206 
00207               if (surf->flags & SURFACE_TWOSIDED){
00208                      glDisable(GL_CULL_FACE);
00209               } else {
00210                      glEnable(GL_CULL_FACE);
00211               }
00212               
00213               st = surf->flags & 0xf;
00214               if (st == SURFACE_TYPE_CLOSEDLINE){
00215                      glDisable(GL_LIGHTING);
00216 
00217                      glBegin(GL_LINE_LOOP);
00218                      setSimpleColor(surf->mat);
00219               } else if (st == SURFACE_TYPE_LINE){
00220                      glDisable(GL_LIGHTING);
00221 
00222                      glBegin(GL_LINE_STRIP);
00223                      setSimpleColor(surf->mat);
00224               } else {
00225                      glEnable(GL_LIGHTING);
00226                      setColor(surf->mat); 
00227                      if (surf->numVertices == 3){
00228                             glBegin(GL_TRIANGLE_STRIP);
00229                      } else {
00230                             glBegin(GL_POLYGON);
00231                      }
00232               }
00233 
00234               for (sr = 0; sr < surf->numVertices; sr++){
00235                      pp::Vertex *v = &ob->vertices[surf->vertices[sr]];
00236 
00237                      if (ob->texture > -1){
00238                             double tu = surf->uvs[sr].u;
00239                             double tv = surf->uvs[sr].v;
00240 
00241                             double tx = ob->texture_offset_x + tu * ob->texture_repeat_x;
00242                             double ty = ob->texture_offset_y + tv * ob->texture_repeat_y;
00243 
00244                             glTexCoord2f(tx, ty);
00245                      }
00246 
00247                      if (surf->flags & SURFACE_SHADED){
00248                             glNormal3dv((double *)&v->normal);
00249                      }
00250                      glVertex3dv((double *)v);
00251               }
00252               glEnd();
00253     }
00254 
00255     if (ob->num_kids){
00256               for (n = 0; n < ob->num_kids; n++){
00257               render(ob->kids[n]);
00258               }
00259        }
00260        
00261        glEnable(GL_TEXTURE_2D);
00262     glPopMatrix();
00263 }
00264 
00265 void
00266 ModelAC::setColor(long matno)
00267 {
00268     Material *m = getMaterialFromPalette(matno);
00269     float rgba[4];
00270     static int lastcolset = -1;
00271 
00272     if (lastcolset == matno)
00273               return;
00274     else
00275        lastcolset = matno;
00276 
00277     rgba[0] = m->diffuse.r;
00278        rgba[1] = m->diffuse.g;
00279        rgba[2] = m->diffuse.b;
00280     rgba[3] = 1.0-m->transparency;
00281     
00282        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, rgba);
00283        
00284     if ( (1.0-m->transparency) < 1.0)
00285            {
00286         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00287         glEnable(GL_BLEND);
00288               }
00289     else
00290         glDisable(GL_BLEND);
00291 }
00292 
00293 void
00294 ModelAC::setSimpleColor(long matno)
00295 {
00296     Material *m = getMaterialFromPalette(matno);
00297     glColor3dv((double*)&m->diffuse);
00298 }
00299 
00300 int
00301 ModelAC::stringToObjectType(std::string& string)
00302 {
00303     if (string=="world")
00304         return(OBJECT_WORLD);
00305     if (string=="poly")
00306         return(OBJECT_NORMAL);
00307     if (string=="group")
00308         return(OBJECT_GROUP);
00309     if (string=="light")
00310         return(OBJECT_LIGHT);
00311     return(OBJECT_NORMAL);
00312 }
00313 
00314 ModelObject*
00315 ModelAC::loadObject(FILE *f, ModelObject *parent)
00316 {
00317     char t[20];
00318        std::string type;
00319     ModelObject *ob = NULL;
00320 
00321     while (!feof(f))
00322     {
00323        readLine(f);
00324 
00325        sscanf(ma_buff, "%s", t);
00326        type = t;
00327 
00328        if (type=="MATERIAL"){
00329         double shi, tran;
00330         Material m;
00331            
00332               if (getTokens(ma_buff, &m_tokc, ma_tokv) != 22){
00333             printf("expected 21 params after \"MATERIAL\" - line %d\n", m_line);
00334            } else {
00335                      m.name = ma_tokv[1];
00336                      m.diffuse.r = atof(ma_tokv[3]);
00337                      m.diffuse.g = atof(ma_tokv[4]);
00338                      m.diffuse.b = atof(ma_tokv[5]);
00339 
00340                      m.ambient.r = atof(ma_tokv[7]);
00341                      m.ambient.g = atof(ma_tokv[8]);
00342                      m.ambient.b = atof(ma_tokv[9]);
00343 
00344                      m.emissive.r = atof(ma_tokv[11]);
00345                      m.emissive.g = atof(ma_tokv[12]);
00346                      m.emissive.b = atof(ma_tokv[13]);
00347 
00348                      m.specular.r = atof(ma_tokv[15]);
00349                      m.specular.g = atof(ma_tokv[16]);
00350                      m.specular.b = atof(ma_tokv[17]);
00351 
00352                      m.shininess = atof(ma_tokv[19]);
00353                      m.transparency = atof(ma_tokv[21]);
00354        
00355                      shi = atof(ma_tokv[6]);
00356                      tran = atof(ma_tokv[7]);
00357 
00358                      ma_palette[m_numPalette++] = m;
00359            }
00360        } else if (type=="OBJECT"){
00361               char type[20];
00362               char str[20];
00363               ob = new ModelObject;
00364 
00365               sscanf(ma_buff, "%s %s", str, type);
00366               
00367               std::string t(type);
00368               
00369               ob->type = stringToObjectType(t);
00370        } else if (type=="data"){
00371               if (getTokens(ma_buff, &m_tokc, ma_tokv) != 2){
00372                      printf("expected 'data <number>' at line %d\n", m_line);
00373               } else {
00374                      char *str;
00375                      int len;
00376 
00377                      len = atoi(ma_tokv[1]);
00378                      if (len > 0){
00379                          str = (char *)malloc(len+1);
00380                          fread(str, len, 1, f);
00381                          str[len] = 0;
00382                          fscanf(f, "\n"); m_line++;
00383                          ob->data = str;
00384                          free(str);
00385                      }
00386               }
00387        } else if (type=="name"){
00388               int numtok = getTokens(ma_buff, &m_tokc, ma_tokv);
00389               if (numtok != 2){
00390                      printf("expected quoted name at line %d (got %d tokens)\n", m_line, numtok);
00391               } else {
00392                      ob->name = ma_tokv[1];
00393               }
00394        } else if (type=="texture"){
00395               if (getTokens(ma_buff, &m_tokc, ma_tokv) != 2){
00396                      printf("expected quoted texture name at line %d\n", m_line);
00397               } else {
00398                      ob->texture = loadTexture(ma_tokv[1]);
00399               }
00400        } else if (type=="texrep"){
00401               if (getTokens(ma_buff, &m_tokc, ma_tokv) != 3){
00402                      printf("expected 'texrep <float> <float>' at line %d\n", m_line);
00403               } else {
00404                   ob->texture_repeat_x = atof(ma_tokv[1]);
00405                   ob->texture_repeat_y = atof(ma_tokv[2]);
00406               }
00407        } else if (type=="texoff"){
00408               if (getTokens(ma_buff, &m_tokc, ma_tokv) != 3){
00409                      printf("expected 'texoff <float> <float>' at line %d\n", m_line);
00410               } else {
00411                      ob->texture_offset_x = atof(ma_tokv[1]);
00412                      ob->texture_offset_y = atof(ma_tokv[2]);
00413               }
00414        } else if (type=="rot"){
00415               double r[9];
00416               char str2[5];
00417               int n;
00418 
00419               sscanf(ma_buff, "%s %lf %lf %lf %lf %lf %lf %lf %lf %lf", str2, 
00420                                    &r[0], &r[1], &r[2], &r[3], &r[4], &r[5], &r[6], &r[7], &r[8] );
00421 
00422               for (n = 0; n < 9; n++){
00423                      ob->matrix[n] = r[n];
00424               }
00425        } else if (type=="loc"){
00426               char str[5];
00427               sscanf(ma_buff, "%s %lf %lf %lf", str,
00428                         &ob->loc.x, &ob->loc.y, &ob->loc.z);                 
00429        } else if (type=="url"){
00430               if (getTokens(ma_buff, &m_tokc, ma_tokv) != 2){
00431                   printf("expected one arg to url at line %d (got %s)\n", m_line, ma_tokv[0]);
00432               } else {
00433                      ob->url = ma_tokv[1];
00434               }
00435        } else if (type=="numvert"){
00436               int num, n;
00437               char str[10];
00438 
00439               sscanf(ma_buff, "%s %d", str, &num);
00440 
00441               if (num > 0){
00442                      ob->num_vert = num;
00443                      ob->vertices = new pp::Vertex[num];
00444                      for (n = 0; n < num; n++){
00445                             pp::Vertex p;
00446                             fscanf(f, "%lf %lf %lf\n", &p.vec.x, &p.vec.y, &p.vec.z); m_line++;
00447                             ob->vertices[n] = p;
00448                      }
00449 
00450               }
00451        } else if (type=="numsurf"){
00452               int num, n;
00453               char str[10];
00454 
00455               sscanf(ma_buff, "%s %d", str, &num);
00456               if (num > 0){
00457                      ob->num_surf = num;
00458                      ob->surfaces = new Surface[num];
00459 
00460                      for (n = 0; n < num; n++){
00461                             Surface *news = readSurface(f, &ob->surfaces[n], ob);
00462                             if (news == NULL){
00463                                    printf("error whilst reading surface at line: %d\n", m_line);
00464                                    return(NULL);
00465                             }
00466                      }
00467               }
00468        } else if (type=="kids"){ 
00469               int num, n;
00470 
00471               sscanf(ma_buff, "%s %d", t, &num);
00472                      
00473               if (num != 0){
00474                      ob->kids = new ModelObject*[num];
00475                      ob->num_kids = num;
00476 
00477                      for (n = 0; n < num; n++){
00478                             ModelObject *k = loadObject(f, ob);
00479 
00480                             if (k == NULL){
00481                                    printf("error reading expected child object %d of %d at line: %d\n", n+1, num, m_line);
00482                                    return(ob);
00483                             } else {
00484                                    ob->kids[n] = k;
00485                             }
00486                      }
00487            }
00488            return(ob);
00489        }
00490 
00491     }
00492     return(ob);
00493 }
00494 
00495 void
00496 ModelAC::objectCalculateVertexNormals(ModelObject *ob)
00497 {
00498     int s, v, vr;
00499 
00501     for (v = 0; v < ob->num_vert; v++)
00502     {
00503        pp::Vec3d n;
00504        int found = 0;
00505 
00507        for (s = 0; s < ob->num_surf; s++)
00508        {
00509            Surface *surf = &ob->surfaces[s];
00510 
00513            for (vr = 0; vr < surf->numVertices; vr++)
00514               if (surf->vertices[vr] == v)
00515               {
00516                   n.x+=surf->normal.x;
00517                   n.y+=surf->normal.y;
00518                   n.z+=surf->normal.z;
00519                   found++;
00520               }
00521        }
00522        if (found > 0)
00523        {
00524            n.x /= found;
00525            n.y /= found;
00526            n.z /= found;
00527        }
00528        ob->vertices[v].normal = n;
00529     }
00530 }
00531 
00532 void
00533 ModelAC::calculateVertexNormals(ModelObject *ob)
00534 {
00535     int n;
00536     objectCalculateVertexNormals(ob);
00537     if (ob->num_kids)
00538        for (n = 0; n < ob->num_kids; n++)
00539            calculateVertexNormals(ob->kids[n]);
00540 }
00541 
00542 int
00543 ModelAC::getTokens(char *s, int *argc, char *argv[])
00546 {
00547     char *p = s;
00548     char *st;
00549     char c;
00550     //int n;
00551     int tc;
00552 
00553     tc = 0;
00554     while ((c=*p) != 0)
00555     {
00556        if ((c != ' ') && (c != '\t') && (c != '\n') && ( c != 13))
00557        {
00558            if (c == '"')
00559            {
00560               c = *p++;
00561               st = p;
00562               while ((c = *p) && ((c != '"')&&(c != '\n')&& ( c != 13)) )
00563               {
00564                   if (c == '\\')
00565                      strcpy(p, p+1);
00566                   p++;
00567               }
00568               *p=0;
00569               argv[tc++] = st;
00570            }
00571            else
00572            {
00573               st = p;
00574               while ((c = *p) && ((c != ' ') && (c != '\t') && (c != '\n') && ( c != 13)) )
00575                   p++;
00576               *p=0;
00577               argv[tc++] = st;
00578            }                
00579        }
00580        p++;
00581     }
00582 
00583     *argc = tc;
00584     return(tc);
00585 }
00586 
00587 pp::Material*
00588 ModelAC::getMaterialFromPalette(int id)
00589 {
00590     return(&ma_palette[id]);
00591 }
00592 
00593 bool
00594 ModelAC::readLine(FILE *f)
00595 {
00596     fgets(ma_buff, 255, f); m_line++;
00597     return(true);
00598 }
00599 
00600 Surface*
00601 ModelAC::readSurface(FILE *f, Surface *s, ModelObject *ob)
00602 {
00603     char t[20];
00604        std::string type;
00605        
00606     while (!feof(f))
00607     {
00608        readLine(f);
00609        sscanf(ma_buff, "%s", t);
00610        type = t;
00611               
00612        if (type=="SURF"){
00613            int flgs;
00614 
00615            if (getTokens(ma_buff, &m_tokc, ma_tokv) != 2){
00616                      printf("SURF should be followed by one flags argument\n");
00617         } else {
00618                      flgs = strtol(ma_tokv[1], NULL, 0);
00619                      s->flags = flgs;
00620               }
00621        } else if (type=="mat"){
00622               int mindx;
00623               sscanf(ma_buff, "%s %d", t, &mindx);
00624               s->mat = mindx + m_startMatIndex;
00625        } else if (type=="refs"){
00626               int num, n;
00627               int ind;
00628               double tx, ty;
00629   
00630               sscanf(ma_buff, "%s %d", t, &num);        
00631 
00632               s->numVertices = num;
00633               s->vertices = new int[num]; //(int *)malloc( num * sizeof(int));
00634               s->uvs = new pp::UV[num];
00635 
00636               for (n = 0; n < num; n++){
00637                      fscanf(f, "%d %lf %lf\n", &ind, &tx, &ty); m_line++;
00638                      s->vertices[n] = ind;
00639                      s->uvs[n].u = tx;
00640                      s->uvs[n].v = ty;
00641               }
00642 
00643               // calc surface normal
00644               if (s->numVertices >= 3)
00645               CalculateTriNormal(&ob->vertices[s->vertices[0]].vec, 
00646                             &ob->vertices[s->vertices[1]].vec, 
00647                             &ob->vertices[s->vertices[2]].vec,
00648                             &s->normal);
00649 
00650               return(s);
00651        } else {
00652               printf("ignoring %s\n", t);
00653        }
00654        
00655     }
00656     return(NULL);
00657 }
00658 
00659 void
00660 ModelAC::CalculateTriNormal(pp::Vec3d *v1, pp::Vec3d *v2, pp::Vec3d *v3, pp::Vec3d *n)
00661 {
00662     double len;
00663 
00664     n->x = (v2->y-v1->y)*(v3->z-v1->z)-(v3->y-v1->y)*(v2->z-v1->z);
00665     n->y = (v2->z-v1->z)*(v3->x-v1->x)-(v3->z-v1->z)*(v2->x-v1->x);
00666     n->z = (v2->x-v1->x)*(v3->y-v1->y)-(v3->x-v1->x)*(v2->y-v1->y);
00667     len = sqrt(n->x*n->x + n->y*n->y + n->z*n->z);
00668 
00669     if (len > 0)
00670     {
00671               n->x /= len;
00672               n->y /= len;
00673               n->z /= len;  
00674     }
00675 }
00676 
00677 } //namespace pp