1 /*
2      PLIB - A Suite of Portable Game Libraries
3      Copyright (C) 1998,2003  Steve Baker
4 
5      This library is free software; you can redistribute it and/or
6      modify it under the terms of the GNU Library General Public
7      License as published by the Free Software Foundation; either
8      version 2 of the License, or (at your option) any later version.
9 
10      This library is distributed in the hope that it will be useful,
11      but WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      Library General Public License for more details.
14 
15      You should have received a copy of the GNU Library General Public
16      License along with this library; if not, write to the Free Software
17      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 
19      For further information visit http://plib.sourceforge.net
20 
21      $Id: ssgLoadDOF.cxx 1748 2003-01-29 19:33:41Z sjbaker $
22 */
23 
24 
25 #include "ssgLocal.h"
26 
27 static ssgLoaderOptions* current_options = NULL ;
28 
29 struct _NameValuePair
30 {
31   char *name ;
32   int  value ;
33 } ;
34 
35 #define TOKEN_DOF1 1
36 #define TOKEN_EDOF 2
37 #define TOKEN_MATS 3
38 #define TOKEN_GEOB 4
39 #define TOKEN_MAT0 5
40 #define TOKEN_GOB1 6
41 #define TOKEN_MHDR 7
42 #define TOKEN_MCOL 8
43 #define TOKEN_MUVW 9
44 #define TOKEN_MTRA 10
45 #define TOKEN_MTEX 11
46 #define TOKEN_MSUB 12
47 #define TOKEN_MEND 13
48 #define TOKEN_GHDR 14
49 #define TOKEN_INDI 15
50 #define TOKEN_VERT 16
51 #define TOKEN_TVER 17
52 #define TOKEN_NORM 18
53 #define TOKEN_BRST 19
54 #define TOKEN_GEND 20
55 #define TOKEN_ILLEGAL  998
56 #define TOKEN_EOF      999
57 
58 
59 static _NameValuePair tags [] =
60 {
61   { "DOF1", TOKEN_DOF1 },
62   { "EDOF", TOKEN_EDOF },
63   { "MATS", TOKEN_MATS },
64   { "GEOB", TOKEN_GEOB },
65   { "MAT0", TOKEN_MAT0 },
66   { "GOB1", TOKEN_GOB1 },
67   { "MHDR", TOKEN_MHDR },
68   { "MCOL", TOKEN_MCOL },
69   { "MUVW", TOKEN_MUVW },
70   { "MTRA", TOKEN_MTRA },
71   { "MTEX", TOKEN_MTEX },
72   { "MSUB", TOKEN_MSUB },
73   { "MEND", TOKEN_MEND },
74   { "GHDR", TOKEN_GHDR },
75   { "INDI", TOKEN_INDI },
76   { "VERT", TOKEN_VERT },
77   { "TVER", TOKEN_TVER },
78   { "NORM", TOKEN_NORM },
79   { "BRST", TOKEN_BRST },
80   { "GEND", TOKEN_GEND },
81   { NULL, 0 }
82 } ;
83 
84 
85 struct dofMaterial
86 {
87   char *name      ;
88   char *className ;
89 
90   sgVec4 ambient  ;
91   sgVec4 diffuse  ;
92   sgVec4 specular ;
93   sgVec4 emission ;
94   float shininess ;
95 
96   float uvwUoffset ;
97   float uvwVoffset ;
98   float uvwUtiling ;
99   float uvwVtiling ;
100   float uvwAngle   ;
101   float uvwBlur    ;
102   float uvwBlurOffset ;
103 
104   float transparency ;  /* Unused */
105   int blendMode ;       /* 0 == No blend,
106                            1 == BLEND_SRC_ALPHA,
107                            2 == BLEND_CONST (unused) */
108 
109   int   textures ;
110   char **mapName ;
111 
112   int subMaterials ;    /* Should be zero */
113   dofMaterial *MAT0 ;   /* Should be unused */
114 
115   ssgSimpleState *ssg_material ;
116 } ;
117 
118 
119 static ulList *materials ;
120 
121 
getToken(FILE * fd)122 static int getToken ( FILE *fd )
123 {
124   char s [ 5 ] ;
125 
126   if ( fread ( s, 1, 4, fd ) != 4 )
127     return TOKEN_EOF ;
128 
129   s [ 4 ] = '\0' ;
130 
131   for ( int i = 0 ; tags [ i ] . name != 0 ; i++ )
132     if ( strcmp ( tags[i].name, s ) == 0 )
133       return tags[i].value ;
134 
135   ulSetError ( UL_WARNING, "Illegal token '%s'", s ) ;
136   return TOKEN_ILLEGAL ;
137 }
138 
139 
getShort(FILE * fd)140 static short getShort ( FILE *fd )
141 {
142   short val ;
143 
144   if ( fread ( & val, sizeof(short), 1, fd ) != 1 )
145     return 0 ;
146 
147   val = ulEndianLittle16 ( (unsigned short) val ) ;
148   return val ;
149 }
150 
151 
getColour(FILE * fd,float * colour)152 static void getColour ( FILE *fd, float *colour )
153 {
154   if ( fread ( colour, sizeof(float), 4, fd ) != 4 )
155     return ;
156 
157   ulEndianLittleArrayFloat ( colour, 4 ) ;
158 }
159 
160 
getFloat(FILE * fd)161 static float getFloat ( FILE *fd )
162 {
163   float val ;
164 
165   if ( fread ( & val, sizeof(float), 1, fd ) != 1 )
166     return 0 ;
167 
168   val = ulEndianLittleFloat ( val ) ;
169   return val ;
170 }
171 
172 
getInteger(FILE * fd)173 static int getInteger ( FILE *fd )
174 {
175   int val ;
176 
177   if ( fread ( & val, sizeof(int), 1, fd ) != 1 )
178     return 0 ;
179 
180   val = ulEndianLittle32 ( (unsigned int) val ) ;
181   return val ;
182 }
183 
184 
getLength(FILE * fd)185 static int getLength ( FILE *fd )
186 {
187   return getInteger ( fd ) ;
188 }
189 
190 
getTokenAndLength(FILE * fd,int * len)191 static int getTokenAndLength ( FILE *fd, int *len )
192 {
193   int tok = getToken ( fd ) ;
194 
195   if ( tok == TOKEN_EOF )
196   {
197     *len = 0 ;
198     return tok ;
199   }
200 
201   *len = getLength ( fd ) ;
202   return tok ;
203 }
204 
205 
getQString(FILE * fd,int * l)206 static char *getQString ( FILE *fd, int *l )
207 {
208   short len = getShort ( fd ) ;
209 
210   (*l) -= len + sizeof ( short ) ;
211 
212   char *res = new char [ len + 1 ] ;
213 
214   fread ( res, sizeof(char), len, fd ) ;
215   res [ len ] = '\0' ;
216 
217   return res ;
218 }
219 
220 
getMAT0(FILE * fd)221 static void getMAT0 ( FILE *fd )
222 {
223   dofMaterial *mat = new dofMaterial ;
224 
225   mat -> ssg_material = new ssgSimpleState () ;
226 
227   materials -> addEntity ( mat ) ;
228 
229   while ( 1 )
230   {
231     int len ;
232 
233     switch ( getToken ( fd ) )
234     {
235       case TOKEN_MHDR :
236         {
237           len = getLength ( fd ) ;
238           mat -> name = getQString ( fd, &len ) ;
239           mat -> className = getQString ( fd, &len ) ;
240 fprintf ( stderr, "MAT0:  Name='%s', className='%s'\n",
241                    mat -> name, mat -> className ) ;
242 
243         }
244         break ;
245 
246       case TOKEN_MTEX :
247         {
248           len = getLength ( fd ) ;
249           mat -> textures = getInteger ( fd ) ;
250           len -= sizeof ( int ) ;
251           mat -> mapName = new char * [ mat -> textures ] ;
252           for ( int i = 0 ; i < mat -> textures ; i++ )
253             mat -> mapName [ i ] = getQString ( fd, & len ) ;
254         }
255         break ;
256 
257       case TOKEN_MCOL :
258         {
259           len = getLength ( fd ) ;
260           getColour ( fd, mat -> ambient  ) ;
261           getColour ( fd, mat -> diffuse  ) ;
262           getColour ( fd, mat -> specular ) ;
263           getColour ( fd, mat -> emission ) ;
264           mat -> shininess = getFloat ( fd ) ;
265           len -= 17 * sizeof(float) ;
266         }
267         break ;
268 
269       case TOKEN_MUVW :
270         len = getLength ( fd ) ;
271         mat -> uvwUoffset    = getFloat ( fd ) ;
272         mat -> uvwVoffset    = getFloat ( fd ) ;
273         mat -> uvwUtiling    = getFloat ( fd ) ;
274         mat -> uvwVtiling    = getFloat ( fd ) ;
275         mat -> uvwAngle      = getFloat ( fd ) ;
276         mat -> uvwBlur       = getFloat ( fd ) ;
277         mat -> uvwBlurOffset = getFloat ( fd ) ;
278         len -= 7 * sizeof(float) ;
279         break ;
280 
281       case TOKEN_MTRA :
282         len = getLength ( fd ) ;
283         mat -> transparency = getFloat   ( fd ) ;
284         mat -> blendMode    = getInteger ( fd ) ;
285         len -= sizeof(float) + sizeof(int) ;
286         break ;
287 
288       case TOKEN_MSUB :
289         {
290           len = getLength ( fd ) ;
291 
292           mat -> subMaterials = getInteger ( fd ) ;
293 
294           if ( mat -> subMaterials != 0 )
295             ulSetError ( UL_WARNING,
296                "ssgLoadDOF: Sub-Materials are not supported." ) ;
297 
298           len -= sizeof ( int ) ;
299         }
300         break ;
301 
302       case TOKEN_MEND :
303         {
304           ssgSimpleState *m = mat -> ssg_material ;
305 
306           if ( mat -> textures > 0 )
307           {
308             m -> enable ( GL_TEXTURE_2D ) ;
309             m -> setTexture ( mat -> mapName[0] ) ;
310           }
311           else
312             m -> disable ( GL_TEXTURE_2D ) ;
313 
314           m -> disable ( GL_COLOR_MATERIAL ) ;
315           m -> setMaterial ( GL_AMBIENT , mat -> ambient  ) ;
316           m -> setMaterial ( GL_DIFFUSE , mat -> diffuse  ) ;
317           m -> setMaterial ( GL_SPECULAR, mat -> specular ) ;
318           m -> setMaterial ( GL_EMISSION, mat -> emission ) ;
319           m -> setShininess ( mat -> shininess ) ;
320         }
321         return ;
322 
323       case TOKEN_EOF : return ;
324 
325       default :
326         {
327           ulSetError ( UL_WARNING,
328                  "ssgLoadDOF: Material contains an unrecognised token?!?" ) ;
329 
330           len = getLength ( fd ) ;
331         }
332         break ;
333     }
334 
335     for ( int i = 0 ; i < len ; i++ ) getc ( fd ) ;
336   }
337 }
338 
339 
getMaterials(FILE * fd,int howMany)340 static void getMaterials ( FILE *fd, int howMany )
341 {
342 ulSetError ( UL_WARNING, "Getting %d materials", howMany ) ;
343 
344   for ( int i = 0 ; i < howMany ; i++ )
345   {
346     int len ;
347 
348     switch ( getToken ( fd ) )
349     {
350       case TOKEN_MAT0 :
351         len = getLength ( fd ) ;
352         getMAT0 ( fd ) ;
353         break ;
354 
355 
356       case TOKEN_EOF  : return ;
357 
358       default :
359         {
360           ulSetError ( UL_WARNING,
361                  "ssgLoadDOF: Material contains an unrecognised token?!?" ) ;
362 
363           len = getLength ( fd ) ;
364 
365           for ( int i = 0 ; i < len ; i++ )
366             getc ( fd ) ;
367         }
368         return ;
369     }
370   }
371 }
372 
373 
getGOB1(FILE * fd)374 static ssgEntity *getGOB1 ( FILE *fd )
375 {
376   int flags       = 0 ;
377   int paintflags  = 0 ;
378   int materialRef = 0 ;
379   int indices     = 0 ; short *index   = NULL ;
380   int vertices    = 0 ; float *vertex  = NULL ;
381   int tvertices   = 0 ; float *tvertex = NULL ;
382   int normals     = 0 ; float *normal  = NULL ;
383   int bursts      = 0 ;
384   int *burstStart = NULL ;
385   int *burstCount = NULL ;
386   int *burstMtlID = NULL ;
387   int *burstVperP = NULL ;
388 
389   while ( 1 )
390   {
391     int len ;
392 
393     switch ( getToken ( fd ) )
394     {
395       case TOKEN_GHDR :
396         {
397           len = getLength ( fd ) ;
398 
399           flags       = getInteger ( fd ) ;
400           paintflags  = getInteger ( fd ) ;
401           materialRef = getInteger ( fd ) ;
402 
403           len -= 3 * sizeof ( int ) ;
404         }
405         break ;
406 
407       case TOKEN_INDI :
408         {
409           len = getLength ( fd ) ;
410           indices = getInteger ( fd ) ;
411           index = new short [ indices ] ;
412           fread ( index, sizeof(short), indices, fd ) ;
413           ulEndianLittleArray16 ( (unsigned short *) index, indices ) ;
414           len -= sizeof(int) + sizeof(short) * indices ;
415         }
416         break ;
417 
418       case TOKEN_VERT :
419         {
420           len = getLength ( fd ) ;
421           vertices = getInteger ( fd ) ;
422           vertex = new float [ vertices * 3 ] ;
423           fread ( vertex, sizeof(float), vertices * 3, fd ) ;
424           ulEndianLittleArrayFloat ( vertex, vertices * 3 ) ;
425           len -= sizeof(int) + sizeof(float) * vertices * 3 ;
426         }
427         break ;
428 
429       case TOKEN_TVER :
430         {
431           len = getLength ( fd ) ;
432           tvertices = getInteger ( fd ) ;
433           tvertex = new float [ tvertices * 2 ] ;
434           fread ( tvertex, sizeof(float), tvertices * 2, fd ) ;
435           ulEndianLittleArrayFloat ( tvertex, tvertices * 2 ) ;
436           len -= sizeof(int) + sizeof(float) * tvertices * 2 ;
437         }
438         break ;
439 
440       case TOKEN_NORM :
441         {
442           len = getLength ( fd ) ;
443           normals = getInteger ( fd ) ;
444           normal = new float [ normals * 3 ] ;
445           fread ( normal, sizeof(float), normals * 3, fd ) ;
446           ulEndianLittleArrayFloat ( normal, normals * 3 ) ;
447           len -= sizeof(int) + sizeof(float) * normals * 3 ;
448         }
449         break ;
450 
451       case TOKEN_BRST :
452         {
453           len = getLength ( fd ) ;
454           bursts = getInteger ( fd ) ;
455           burstStart = new int [ bursts ] ;
456           burstCount = new int [ bursts ] ;
457           burstMtlID = new int [ bursts ] ;
458           burstVperP = new int [ bursts ] ;
459           fread ( burstStart, sizeof(int), bursts, fd ) ;
460           fread ( burstCount, sizeof(int), bursts, fd ) ;
461           fread ( burstMtlID, sizeof(int), bursts, fd ) ;
462           fread ( burstVperP, sizeof(int), bursts, fd ) ;
463           ulEndianLittleArray32 ( (unsigned int *) burstStart, bursts ) ;
464           ulEndianLittleArray32 ( (unsigned int *) burstCount, bursts ) ;
465           ulEndianLittleArray32 ( (unsigned int *) burstMtlID, bursts ) ;
466           ulEndianLittleArray32 ( (unsigned int *) burstVperP, bursts ) ;
467 
468           len -= sizeof(int) + sizeof(int) * bursts * 4 ;
469         }
470         break ;
471 
472       case TOKEN_GEND :
473         {
474           float *colours = new float [ vertices * 4 ] ;
475 
476           for ( int i = 0 ; i < vertices ; i++ )
477           {
478             colours [ i*4 + 0 ] = 0.5f ;
479             colours [ i*4 + 1 ] = 0.5f ;
480             colours [ i*4 + 2 ] = 0.5f ;
481             colours [ i*4 + 3 ] = 1.0f ;
482 
483             float tmp ;
484             tmp                =  vertex [ i*3 + 1 ] ;
485             vertex [ i*3 + 1 ] = -vertex [ i*3 + 2 ] ;
486             vertex [ i*3 + 2 ] =  tmp ;
487             tmp                =  normal [ i*3 + 1 ] ;
488             normal [ i*3 + 1 ] = -normal [ i*3 + 2 ] ;
489             normal [ i*3 + 2 ] =  tmp ;
490           }
491           ssgVertexArray    *vx = new ssgVertexArray   ( vertices , (sgVec3 *) vertex  ) ;
492           ssgColourArray    *co = new ssgColourArray   ( vertices , (sgVec4 *) colours ) ;
493           ssgNormalArray    *nm = new ssgNormalArray   ( normals  , (sgVec3 *) normal  ) ;
494           ssgTexCoordArray *tx = new ssgTexCoordArray ( tvertices, (sgVec2 *) tvertex ) ;
495           ssgIndexArray     *ix = new ssgIndexArray    ( indices  , index ) ;
496 
497           ssgVtxArray *va = new ssgVtxArray ( GL_TRIANGLES,
498                                  vx, nm, tx, co, ix ) ;
499 
500           va -> setState ( ( (dofMaterial *)
501                              ( materials -> getEntity ( materialRef ) )
502                            ) -> ssg_material ) ;
503           delete [] burstStart ;
504           delete [] burstCount ;
505           delete [] burstMtlID ;
506           delete [] burstVperP ;
507 
508           return va ;
509         }
510 
511       case TOKEN_EOF  : return NULL ;
512 
513       default :
514         {
515           ulSetError ( UL_WARNING,
516                  "ssgLoadDOF: GOB1 contains an unrecognised token?!?" ) ;
517 
518           len = getLength ( fd ) ;
519         }
520         break ;
521     }
522 
523     for ( int i = 0 ; i < len ; i++ ) getc ( fd ) ;
524   }
525 }
526 
527 
528 
getGeode(FILE * fd,int howMany)529 static ssgBranch *getGeode ( FILE *fd, int howMany )
530 {
531   ssgBranch *br = new ssgBranch () ;
532 
533 ulSetError ( UL_WARNING, "Getting %d geodes", howMany ) ;
534 
535   for ( int i = 0 ; i < howMany ; i++ )
536   {
537     int len ;
538 
539     switch ( getToken ( fd ) )
540     {
541       case TOKEN_GOB1 :
542         len = getLength ( fd ) ;
543 
544         br -> addKid ( getGOB1 ( fd ) ) ;
545 
546         break ;
547 
548       case TOKEN_EOF  : return br ;
549 
550       default :
551         {
552           ulSetError ( UL_WARNING,
553                  "ssgLoadDOF: Geode contains an unrecognised token?!?" ) ;
554 
555           len = getLength ( fd ) ;
556 
557           for ( int i = 0 ; i < len ; i++ )
558             getc ( fd ) ;
559         }
560         return br ;
561     }
562   }
563 
564   return br ;
565 }
566 
567 
cleanUp()568 static void cleanUp ()
569 {
570   for ( int i = 0 ; i < materials -> getNumEntities () ; i++ )
571     delete (dofMaterial *) ( materials -> getEntity ( i ) ) ;
572   delete materials ;
573 }
574 
575 
ssgLoadDOF(const char * fname,const ssgLoaderOptions * options)576 ssgEntity *ssgLoadDOF ( const char *fname, const ssgLoaderOptions* options )
577 {
578   ssgBranch *model ;
579 
580   ssgSetCurrentOptions ( (ssgLoaderOptions*)options ) ;
581   current_options = ssgGetCurrentOptions () ;
582 
583   char filename [ 1024 ] ;
584   current_options -> makeModelPath ( filename, fname ) ;
585 
586   FILE *fd = fopen ( filename, "ra" ) ;
587 
588   if ( fd == NULL )
589   {
590     ulSetError ( UL_WARNING,
591                  "ssgLoadDOF: Failed to open '%s' for reading", filename ) ;
592     return NULL ;
593   }
594 
595   int len ;
596 
597   if ( getTokenAndLength ( fd, &len ) != TOKEN_DOF1 )
598   {
599     ulSetError ( UL_WARNING,
600                  "ssgLoadDOF: '%s' does not start with 'DOF1'?!?", filename ) ;
601     return NULL ;
602   }
603 
604   materials = new ulList () ;
605   model = new ssgBranch () ;
606 
607   while ( 1 )
608   {
609     switch ( getToken ( fd ) )
610     {
611       case TOKEN_MATS :
612         getLength    ( fd ) ;
613         getMaterials ( fd, getInteger ( fd ) ) ;
614         break ;
615 
616       case TOKEN_GEOB :
617         getLength ( fd ) ;
618         model -> addKid ( getGeode  ( fd, getInteger ( fd ) ) ) ;
619         break ;
620 
621       case TOKEN_EDOF :
622         cleanUp () ;
623         return model ;
624 
625       case TOKEN_EOF  :
626         cleanUp () ;
627         return NULL ;
628 
629       default :
630         ulSetError ( UL_WARNING,
631                  "ssgLoadDOF: '%s' contains an unrecognised token?!?", filename ) ;
632         cleanUp () ;
633         return NULL ;
634     }
635   }
636 }
637 
638 
639