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