1 /*
2 PLIB - A Suite of Portable Game Libraries
3 Copyright (C) 1998,2002 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: ssgLoadX.cxx 2065 2006-01-05 21:38:31Z fayjf $
22 */
23
24 //
25 // .X loader for SSG/PLIB
26 // .X is the 3D file format for Micro$ofts directX.
27 // Written by Wolfram Kuss (Wolfram.Kuss@t-online.de) in Oct/Nov of 2000
28 //
29 #include "ssgLocal.h"
30 #include "ssgLoaderWriterStuff.h"
31 #include "ssgParser.h"
32
33 #define u32 unsigned int
34
35 // These functions return TRUE on success
36 typedef int HandlerFunctionType(const char *sName, const char *firstToken);
37
38
39 static char *globEmpty="";
40
41 static ssgBranch *curr_branch_;
42
43 struct EntityType
44 {
45 const char * sName;
46 HandlerFunctionType *HandleEntity;
47 int bMayBeIgnored;
48 } ;
49
50
51
52 static /* const */ ssgLoaderOptions* current_options = NULL ;
53
54 static _ssgParserSpec parser_spec =
55 {
56 "\r\n\t ", // delim_chars_skipable
57 ",;", // delim_chars_non_skipable
58 NULL, // pre_processor
59 "{", // open_brace_chars
60 "}", // close_brace_chars
61 '"', // quote_char
62 '#', // comment_char
63 "//" // comment_string
64 } ;
65
66
67 static _ssgParser parser;
68 static ssgBranch* top_branch;
69
Ascii2Int(int & retVal,const char * token,const char * name)70 static int Ascii2Int(int &retVal, const char *token, const char* name )
71 // returns TRUE on success
72 {
73 char *endptr;
74 retVal = int(strtol( token, &endptr, 10));
75 if ( (endptr == NULL) || (*endptr == 0))
76 return TRUE;
77 else
78 { parser.error("The field %s should contain an integer number but contains %s",name, token) ;
79 return FALSE;
80 }
81 }
82
Ascii2UInt(unsigned int & retVal,const char * token,const char * name)83 static int Ascii2UInt(unsigned int &retVal, const char *token, const char* name )
84 // returns TRUE on success
85 {
86 char *endptr;
87 retVal = (unsigned int)(strtol( token, &endptr, 10));
88 if ( (endptr == NULL) || (*endptr == 0))
89 return TRUE;
90 else
91 { parser.error("The field %s should contain an integer number but contains %s",name, token) ;
92 return FALSE;
93 }
94 }
95
Ascii2Float(SGfloat & retVal,const char * token,const char * name)96 static int Ascii2Float(SGfloat &retVal, const char *token, const char* name )
97 // returns TRUE on success
98 {
99 char *endptr;
100 retVal = SGfloat(strtod( token, &endptr));
101 if ( (endptr == NULL) || (*endptr == 0))
102 return TRUE;
103 else
104 { parser.error("The field %s should contain an integer number but contains %s",name, token) ;
105 return FALSE;
106 }
107 }
108
HandleHeader(const char *,const char * firstToken)109 static int HandleHeader(const char * /* sName */, const char *firstToken)
110 {
111 //parser.expectNextToken("{");
112 int Dummy;
113 if (! Ascii2Int(Dummy, firstToken, "Header.major"))
114 return FALSE;
115
116 parser.expectNextToken(";");
117 if (!parser.getNextInt(Dummy, "Header.minor"))
118 return FALSE;
119 parser.expectNextToken(";");
120 if (!parser.getNextInt(Dummy, "Header.flags"))
121 return FALSE;
122 parser.expectNextToken(";");
123 parser.expectNextToken("}");
124 return TRUE;
125 }
126
IgnoreEntity(int startLevel)127 static void IgnoreEntity(int startLevel)
128 // startLevel should be 0 when you are "in front of the {" (normally)
129 // or 1 when you have already parsed the "{"
130 {
131 int Level = startLevel;
132 char *token;
133
134 while ( TRUE)
135 { token = parser.getNextToken(0);
136 if ( parser.eof )
137 { parser.error("unexpected end of file\n");
138 return ; //FALSE;
139 }
140
141 assert(token!=NULL);
142 if ( ulStrEqual (token,"{") )
143 Level++;
144 else if ( ulStrEqual (token,"}") )
145 { assert(Level>0); // Fixme, NIV14: Handle this gracefully.
146 if (Level==1)
147 return; // found THE closing brace of entitiy
148 Level--; // Found A closing brace
149 }
150 }
151 }
152
153 static int HandleMesh(const char *sName, const char *firstToken);
154 static int HandleMeshMaterialList(const char *sName, const char *firstToken);
155 static int HandleTextureCoords(const char *sName, const char *firstToken);
156 static int HandleMaterial(const char *sName, const char *firstToken);
157 static int HandleTextureFileName(const char *sName, const char *firstToken);
158
159
160 static EntityType aEntities[] =
161 {
162 { "Header", HandleHeader, FALSE},
163 { "Vector", NULL, FALSE},
164 { "Coords2d", NULL, FALSE},
165 { "Quaternion", NULL, FALSE},
166 { "Matrix4x4", NULL, FALSE},
167 { "ColorRGBA", NULL, FALSE},
168 { "ColorRGB", NULL, FALSE},
169 { "Indexed Color", NULL, FALSE},
170 { "Boolean", NULL, FALSE},
171 { "Boolean2d", NULL, FALSE},
172 { "Material", HandleMaterial, FALSE},
173 { "TextureFilename", HandleTextureFileName, FALSE},
174 { "MeshFace", NULL, FALSE},
175 { "MeshFaceWraps", NULL, FALSE},
176 { "MeshTextureCoords", HandleTextureCoords, FALSE},
177 { "MeshNormals", NULL, TRUE},
178 { "MeshVertexColors", NULL, FALSE},
179 { "MeshMaterialList", HandleMeshMaterialList, FALSE},
180 { "Mesh", HandleMesh, FALSE},
181 { "FrameTransformMatrix", NULL, FALSE},
182 { "Frame", NULL, FALSE},
183 { "FloatKeys", NULL, FALSE},
184 { "TimedFloatKeys", NULL, FALSE},
185 { "AnimationKey", NULL, FALSE},
186 { "AnimationOptions", NULL, FALSE},
187 { "Animation", NULL, FALSE},
188 { "AnimationSet", NULL, FALSE},
189 { "template", NULL, TRUE},
190 { NULL, NULL, FALSE}
191 };
192
193
ParseEntity(char * token)194 static int ParseEntity(char *token)
195 // called recursively
196 { int i=0;
197
198 while(aEntities[i].sName!=NULL)
199 { if (ulStrEqual (token,aEntities[i].sName))
200 { if (aEntities[i].HandleEntity)
201 { char *sNextToken, *sName=globEmpty;
202 sNextToken=parser.getNextToken(0);
203 if ( parser.eof )
204 { parser.error("unexpected end of file\n");
205 return FALSE;
206 }
207 // if entity is named, read the name. skip "{":
208 sName = NULL;
209 if (0 != strcmp(sNextToken, "{"))
210 { sName = new char[ strlen(sNextToken) + 1 ];
211 assert ( sName );
212 strcpy(sName, sNextToken);
213 sNextToken = parser.getNextToken(0);
214 if (0 != strcmp(sNextToken, "{"))
215 parser.error("\"{\" expected\n");
216 }
217 sNextToken = parser.getNextToken(0);
218
219 if(sNextToken[0] == '<') // UUID
220 sNextToken = parser.getNextToken(0);
221 if ( parser.eof )
222 { parser.error("unexpected end of file\n");
223 return FALSE;
224 }
225
226 if (!aEntities[i].HandleEntity(sName, sNextToken))
227 return FALSE;
228 if ( sName )
229 delete [] sName;
230 }
231 else
232 if (aEntities[i].bMayBeIgnored)
233 IgnoreEntity ( 0 );
234 else
235 {
236 parser.error("I am sorry, but Entity-type '%s' is not yet implemented.", aEntities[i].sName);
237 return FALSE ;
238 }
239
240 break;
241 }
242 i++;
243 }
244 if (aEntities[i].sName==NULL)
245 {
246 parser.error("unexpected token %s", token);
247 return FALSE ;
248 }
249 return TRUE;
250 }
251
252
253
254 #define MAX_NO_VERTICES_PER_FACE 1000
255
256 static class ssgLoaderWriterMesh currentMesh;
257
258 static ssgSimpleState *currentState;
259 extern sgVec4 currentDiffuse;
260
HandleTextureFileName(const char *,const char * firstToken)261 static int HandleTextureFileName(const char * /*sName*/, const char *firstToken)
262 {/*
263 TextureFilename {
264 "../image/box_top.gif";
265 } #TextureFilename
266 */
267 char *filename_ptr, *filename = new char [ strlen(firstToken)+1 ] ;
268 assert(filename!=NULL);
269 strcpy ( filename, firstToken ) ;
270 filename_ptr = filename ;
271
272 if ( filename_ptr[0] == '"' )
273 filename_ptr++;
274 if (filename_ptr[strlen(filename_ptr)-1] == '"')
275 filename_ptr[strlen(filename_ptr)-1] = 0;
276 currentState -> setTexture( current_options -> createTexture( filename_ptr ) );
277 currentState -> enable( GL_TEXTURE_2D );
278
279
280 parser.expectNextToken(";");
281 parser.expectNextToken("}");
282 delete [] filename;
283 return TRUE;
284 }
285
286 static class ssgSimpleStateList *globalMaterialList;
HandleMaterial(const char *,const char * firstToken)287 static int HandleMaterial(const char * /*sName*/, const char *firstToken)
288 // return TRUE on success
289 { SGfloat power;
290 int bFoundTextureFileName = FALSE;
291 sgVec4 specularColour, EmissiveColour;
292
293 // read body
294 if (! Ascii2Float(currentDiffuse[0], firstToken, "Facecolour R"))
295 return FALSE;
296
297 parser.expectNextToken(";");
298 if (!parser.getNextFloat(currentDiffuse[1], "Facecolour G")) return FALSE;
299 parser.expectNextToken(";");
300 if (!parser.getNextFloat(currentDiffuse[2], "Facecolour B")) return FALSE;
301 parser.expectNextToken(";");
302 if (!parser.getNextFloat(currentDiffuse[3], "Facecolour A")) return FALSE;
303 parser.expectNextToken(";");
304 parser.expectNextToken(";");
305 if (!parser.getNextFloat(power, "power")) return FALSE;
306 parser.expectNextToken(";");
307 if (!parser.getNextFloat(specularColour[0], "Specular R")) return FALSE;
308 parser.expectNextToken(";");
309 if (!parser.getNextFloat(specularColour[1], "Specular G")) return FALSE;
310 parser.expectNextToken(";");
311 if (!parser.getNextFloat(specularColour[2], "Specular B")) return FALSE;
312 specularColour[3] = 0.0;
313 parser.expectNextToken(";");
314 parser.expectNextToken(";");
315 if (!parser.getNextFloat(EmissiveColour[0], "Emissive R")) return FALSE;
316 parser.expectNextToken(";");
317 if (!parser.getNextFloat(EmissiveColour[1], "Emissive G")) return FALSE;
318 parser.expectNextToken(";");
319 if (!parser.getNextFloat(EmissiveColour[2], "Emissive B")) return FALSE;
320 EmissiveColour[3] = 0.0;
321 parser.expectNextToken(";");
322 parser.expectNextToken(";");
323
324 // create SimpleState
325
326 currentState = new ssgSimpleState () ;
327
328 // currentState -> setMaterial ( GL_AMBIENT, mat -> amb ) ;
329 currentState -> setMaterial ( GL_DIFFUSE, currentDiffuse) ;
330 currentState -> setMaterial ( GL_SPECULAR, specularColour) ;
331 currentState -> setMaterial ( GL_SPECULAR, specularColour[0],
332 specularColour[1], specularColour[2], currentDiffuse[3] ) ;
333 currentState -> setMaterial ( GL_EMISSION, EmissiveColour[0],
334 EmissiveColour[1], EmissiveColour[2], currentDiffuse[3] ) ;
335
336 currentState -> setShininess ( power ) ; // Fixme, NIV14: Is that correct?
337
338 currentState -> enable ( GL_COLOR_MATERIAL ) ;
339 currentState -> setColourMaterial ( GL_AMBIENT_AND_DIFFUSE ) ;
340
341 currentState -> enable ( GL_LIGHTING ) ;
342 currentState -> setShadeModel ( GL_SMOOTH ) ;
343
344 if ( currentDiffuse[3] > 0.0f )
345 {
346 currentState -> disable ( GL_ALPHA_TEST ) ;
347 currentState -> enable ( GL_BLEND ) ;
348 currentState -> setTranslucent () ;
349 }
350 else
351 {
352 currentState -> disable ( GL_BLEND ) ;
353 currentState -> setOpaque () ;
354 }
355 currentState -> disable( GL_TEXTURE_2D );
356
357
358
359 while(TRUE)
360 { char *nextToken =parser.getNextToken(0);
361 if (0==strcmp("}", nextToken))
362 {
363
364 /*if(currentMesh.theMaterialsExists())
365 currentMesh.addMaterial( ¤tState );
366 else*/
367 {
368 if(!globalMaterialList)
369 globalMaterialList = new ssgSimpleStateList(3);
370
371 globalMaterialList->add(¤tState);
372 }
373 return TRUE; // Material is finished. success
374 }
375
376 if (! ulStrEqual ( "TextureFilename", nextToken) )
377 { parser.error("TextureFilename expected!\n");
378 return FALSE;
379 }
380 if ( bFoundTextureFileName )
381 { parser.error("Only one TextureFileName per Material please!\n");
382 return FALSE;
383 }
384 if (!ParseEntity(nextToken)) // read "TextureFileName"
385 return FALSE;
386 bFoundTextureFileName = TRUE;
387 }
388 return TRUE; //lint !e527
389 }
390
HandleTextureCoords(const char *,const char * firstToken)391 static int HandleTextureCoords(const char * /* sName */, const char *firstToken)
392 {
393 u32 nNoOfVertices, i;
394
395
396 if (! Ascii2UInt(nNoOfVertices, firstToken, "nNoOfVertices"))
397 return FALSE;
398
399 if ( nNoOfVertices != currentMesh.getNumVertices())
400 { parser.error("No of vertices of mesh (%d) and no "
401 "of texture coordinates (%d) do not match!\n"
402 "Therefore the texture coordinates are ignored!",
403 ( int ) currentMesh.getNumVertices(), ( int ) nNoOfVertices );
404 IgnoreEntity ( 1 ); // ignores TC.
405 return FALSE;
406 }
407 currentMesh.createPerVertexTextureCoordinates2( nNoOfVertices ) ;
408
409 parser.expectNextToken(";");
410 for(i=0;i<nNoOfVertices;i++)
411 {
412 sgVec2 tv;
413
414 if (!parser.getNextFloat(tv[0], "x"))
415 return FALSE;
416 parser.expectNextToken(";");
417 if (!parser.getNextFloat(tv[1], "y"))
418 return FALSE;
419 parser.expectNextToken(";");
420 if(i==nNoOfVertices-1)
421 parser.expectNextToken(";");
422 // Commented out by J. Reucker 2005-12-16
423 // Some .x export plugins forget to add the ",", but the
424 // parser will work with and without "," if it doesn't expect it
425 //~ else
426 //~ parser.expectNextToken(",");
427
428 currentMesh.addPerVertexTextureCoordinate2( tv ) ;
429 }
430 parser.expectNextToken("}");
431 return TRUE;
432 }
433
HandleMeshMaterialList(const char *,const char * firstToken)434 static int HandleMeshMaterialList(const char * /* sName */, const char *firstToken)
435 {
436 u32 i, nFaceIndexes, nMaterialsRead = 0, nMaterials;
437
438 if (! Ascii2UInt(nMaterials, firstToken, "nMaterials"))
439 return FALSE;
440
441 parser.expectNextToken(";");
442 currentMesh.createMaterials( nMaterials );
443 if (!parser.getNextUInt(nFaceIndexes, "number of Face Indexes"))
444 return FALSE;
445 currentMesh.createMaterialIndices( nFaceIndexes ) ;
446 parser.expectNextToken(";");
447
448
449 if ( nFaceIndexes > currentMesh.getNumFaces())
450 { parser.error("No of face indexes of materiallist (%d) is greater than then no "
451 "of faces (%d)!\n"
452 "Therefore the material list is ignored!",
453 ( int ) nFaceIndexes, ( int ) currentMesh.getNumFaces());
454 IgnoreEntity ( 1 ); // ignores TC.
455 return TRUE; // go on parsing
456 }
457 if ( nFaceIndexes > currentMesh.getNumFaces())
458 parser.message("Informational: No of face indexes of materiallist (%d) is less than then no "
459 "of faces (%d)\n" ,
460 ( int ) nFaceIndexes, ( int ) currentMesh.getNumFaces());
461 for ( i=0 ; i<nFaceIndexes ; i++ )
462 {
463 int iIndex, j;
464 char *ptr;
465 if (!parser.getNextInt(iIndex, "Face index"))
466 return FALSE;
467 currentMesh.addMaterialIndex ( iIndex ) ;
468 // I don't quite know why, but different .X files I have have a
469 // different syntax here, some have one ";" and some two.
470 // Therefore, the following code
471 for (j=0;j<2;j++)
472 { ptr = parser.peekAtNextToken( "," );
473 if ( strlen(ptr) == 1)
474 if ( (ptr[0]==',') || (ptr[0]==';') )
475 { ptr = parser.getNextToken( "," ); // ignore this token
476 }
477
478 }
479 }
480 while(TRUE)
481 {
482 char *nextToken =parser.getNextToken(0);
483 if (0==strcmp("}", nextToken))
484 { if ( nMaterialsRead < nMaterials )
485 parser.error("Too few Materials!\n");
486 //else parser.error("Success! MeshMaterialList!\n");
487 for (int i = 0; i < globalMaterialList->getNum(); i++)
488 {
489 currentMesh.addMaterial(globalMaterialList->get(i));
490 }
491 return TRUE; // Mesh is finished. success
492 }
493 if(ulStrEqual ("{", nextToken) )
494 { // reference to global material
495 nextToken =parser.getNextToken(0); // name of material
496 parser.expectNextToken("}");
497 // search for "name" in global list
498 if(globalMaterialList == NULL)
499 {
500 parser.error("No global materials defined, but used!\n");
501 return FALSE;
502 }
503 for(int i=0; i<globalMaterialList->getNum(); i++)
504 {
505 ssgSimpleState * ss = *(globalMaterialList->get(i));
506 if(ulStrEqual(nextToken, ss->getName()))
507 break;
508 }
509 }
510 else
511 {
512 if ( !ulStrEqual ("Material", nextToken) )
513 { parser.error("Material expected!\n");
514 return FALSE;
515 }
516 if ( nMaterialsRead >= nMaterials )
517 { parser.error("Too many Materials!\n");
518 return FALSE;
519 }
520 if (!ParseEntity(nextToken)) // read "Material"
521 return FALSE;
522 }
523 nMaterialsRead++;
524 }
525 return TRUE; //lint !e527
526 }
527
528
HandleMesh(const char * sName,const char * firstToken)529 static int HandleMesh(const char * sName, const char *firstToken)
530 { u32 i, j, nNoOfVertices, nNoOfVerticesForThisFace, nNoOfFaces;
531 int iVertex, aiVertices[MAX_NO_VERTICES_PER_FACE];
532
533 //char *sMeshName = parser.getNextToken("Mesh name");
534 //parser.expectNextToken("{");
535 if (! Ascii2UInt(nNoOfVertices, firstToken, "nNoOfVertices"))
536 return FALSE;
537
538 //parser.getNextInt("number of vertices");
539
540 currentMesh.reInit ();
541 currentMesh.setName( sName );
542 currentMesh.createVertices( nNoOfVertices );
543
544 parser.expectNextToken(";");
545 for(i=0;i<nNoOfVertices;i++)
546 {
547 sgVec3 vert;
548
549 if (!parser.getNextFloat(vert[0], "x"))
550 return FALSE;
551 parser.expectNextToken(";");
552 if (!parser.getNextFloat(vert[1], "y"))
553 return FALSE;
554 parser.expectNextToken(";");
555 if (!parser.getNextFloat(vert[2], "z"))
556 return FALSE;
557 parser.expectNextToken(";");
558 if(i==nNoOfVertices-1)
559 parser.expectNextToken(";");
560 else
561 parser.expectNextToken(",");
562
563 currentMesh.addVertex(vert);
564 }
565 if (!parser.getNextUInt(nNoOfFaces, "number of faces"))
566 return FALSE;
567 currentMesh.createFaces( nNoOfFaces );
568
569
570
571 parser.expectNextToken(";");
572 for(i=0;i<nNoOfFaces;i++)
573 { if (!parser.getNextUInt(nNoOfVerticesForThisFace , "number of vertices for this face"))
574 return FALSE;
575 assert(nNoOfVerticesForThisFace<MAX_NO_VERTICES_PER_FACE);
576
577 // parse faces and put the info into the array aiVertices
578
579 parser.expectNextToken(";");
580 for(j=0;j<nNoOfVerticesForThisFace;j++)
581 { if (!parser.getNextInt(iVertex, "Vertex index"))
582 return FALSE;
583
584 aiVertices[j]=iVertex;
585
586 if(j==nNoOfVerticesForThisFace-1)
587 parser.expectNextToken(";");
588 else
589 parser.expectNextToken(",");
590 }
591 if(i==nNoOfFaces-1)
592 parser.expectNextToken(";");
593 else
594 parser.expectNextToken(",");
595
596 // use array aiVertices
597 #ifdef NOT_PLIB
598 CreateFaceInMdi_Edit(vl, nNoOfVerticesForThisFace, aiVertices); // This line is for the "Mdi" 3D Editor, NOT for plib
599 #else
600 currentMesh.addFaceFromIntegerArray(nNoOfVerticesForThisFace, aiVertices);
601 #endif
602 }
603 while(TRUE)
604 { char *nextToken =parser.getNextToken(0);
605 if ( parser.eof )
606 { parser.error("unexpected end of file\n");
607 return FALSE;
608 }
609
610 if (0==strcmp("}", nextToken))
611 break; // Mesh is finished
612 if (!ParseEntity(nextToken))
613 return FALSE;
614 }
615
616 //
617 if ( currentState == NULL )
618 { currentState = new ssgSimpleState();
619 currentState->setOpaque();
620 currentState->disable(GL_BLEND);
621 currentState->disable(GL_ALPHA_TEST);
622 currentState->disable(GL_TEXTURE_2D);
623 currentState->enable(GL_COLOR_MATERIAL);
624 currentState->enable(GL_LIGHTING);
625 currentState->setShadeModel(GL_SMOOTH);
626 currentState->setMaterial(GL_AMBIENT , 0.7f, 0.7f, 0.7f, 1.0f);
627 currentState->setMaterial(GL_DIFFUSE , 0.7f, 0.7f, 0.7f, 1.0f);
628 currentState->setMaterial(GL_SPECULAR, 1.0f, 1.0f, 1.0f, 1.0f);
629 currentState->setMaterial(GL_EMISSION, 0.0f, 0.0f, 0.0f, 1.0f);
630 currentState->setShininess(50);
631 /*
632 currentState -> setMaterial ( GL_AMBIENT, 0.5, 0.5, 0.5);
633 currentState -> setMaterial ( GL_DIFFUSE, 0.7, 0.7, 0.7); // light grey
634 currentState -> setMaterial ( GL_SPECULAR, 1.0, 1.0, 1.0);
635 currentState -> setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0);
636
637 currentState -> setShininess ( 3 ) ;
638
639 //currentState -> enable ( GL_COLOR_MATERIAL ) ;
640 //currentState -> setColourMaterial ( GL_AMBIENT_AND_DIFFUSE ) ;
641
642 currentState -> enable ( GL_LIGHTING ) ;
643 currentState -> setShadeModel ( GL_SMOOTH ) ;
644
645 currentState -> disable ( GL_BLEND ) ;
646 currentState -> setOpaque () ;
647 currentState -> disable( GL_TEXTURE_2D );
648 */
649 }
650
651 currentMesh.addToSSG(
652 currentState // Pfusch, kludge. NIV135
653 ,
654 current_options,
655 curr_branch_);
656 return TRUE;
657 }
658
TwoCharsToInt(char char1,char char2)659 inline int TwoCharsToInt(char char1, char char2)
660 {
661 return ((int)(char1-'0'))*256+char2-'0';
662 }
663
HeaderIsValid(char * firstToken)664 static int HeaderIsValid(char *firstToken)
665 { // xof 0302txt 0064
666 if (!ulStrEqual (firstToken,"xof"))
667 {
668 parser.error("not X format, invalid Header");
669 return FALSE ;
670 }
671 char* token = parser.getNextToken("2nd Header field");
672 if (strlen(token)!=7)
673 {
674 parser.error("not X format, invalid Header");
675 return FALSE ;
676 }
677 char *sp=&(token[4]);
678 if (!ulStrEqual (sp,"txt"))
679 {
680 if (!ulStrEqual (sp,"bin"))
681 parser.error("not X format, invalid Header");
682 else
683 parser.error("Binary X format files are not supported. If you have access to Windows, "
684 "please use Microsofts conversion-utility convx from the directX-SDK "
685 "to convert to ascii.");
686 return FALSE ;
687 }
688 if (strncmp(token, "0302", 4))
689 parser.message("This loader is written for X-file-format version 3.2.\n"
690 "AFAIK this is the only documented version.\n"
691 "Your file has version %d.%d\n"
692 "Use the file at your own risk\n",
693 TwoCharsToInt(token[0], token[1]),
694 TwoCharsToInt(token[2], token[3]));
695 token = parser.getNextToken("3rd Header field");
696 if (!ulStrEqual(token,"0032") && !ulStrEqual (token,"0064"))
697 {
698 parser.error("not X format, invalid Header");
699 return FALSE ;
700 }
701 return TRUE;
702 }
703
parse()704 static int parse()
705 {
706 int firsttime = TRUE;
707 char* token;
708 //int startLevel = parser.level;
709 token = parser.getNextToken(0);
710 while (! parser.eof )
711 {
712 if (firsttime)
713 {
714 if(!HeaderIsValid(token))
715 return FALSE;
716 firsttime = FALSE;
717 }
718 else
719 { if (!ParseEntity(token))
720 return FALSE;
721 }
722 token = parser.getNextToken(0);
723 }
724 return TRUE ;
725 }
726
727
ssgLoadX(const char * fname,const ssgLoaderOptions * options)728 ssgEntity *ssgLoadX ( const char *fname, const ssgLoaderOptions* options )
729 {
730 ssgSetCurrentOptions ( (ssgLoaderOptions*)options ) ;
731 current_options = ssgGetCurrentOptions () ;
732
733 currentState = NULL;
734 globalMaterialList = NULL;
735 top_branch = new ssgBranch ;
736 curr_branch_ = top_branch;
737 if ( !parser.openFile( fname, &parser_spec ))
738 {
739 delete top_branch ;
740 return 0;
741 }
742 if ( !parse() )
743 {
744 delete top_branch ;
745 top_branch = 0 ;
746 }
747 // parse_free();
748 parser.closeFile();
749
750 delete globalMaterialList;
751 return top_branch ;
752 }
753