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( &currentState );
366 			else*/
367 			{
368 				if(!globalMaterialList)
369 					globalMaterialList = new ssgSimpleStateList(3);
370 
371 				globalMaterialList->add(&currentState);
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