1 /*
2      PLIB - A Suite of Portable Game Libraries
3      Copyright (C) 1998,2002 William Lachance, 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 
22 #include "ssgLocal.h"
23 #include "ssgParser.h"
24 #include "ssgLoaderWriterStuff.h"
25 
26 #include "ssgLoadVRML.h"
27 
28 static _ssgParserSpec parser_spec =
29 {
30    "\r\n\t, ",  // delim_chars_skipable
31      0,          // delim_chars_non_skipable
32     NULL,      // pre_processor
33      "{[",        // open_brace_chars
34      "}]",        // close_brace_chars
35      '"',        // quote_char
36      '#',          // comment_char
37      0           // comment_string
38 };
39 
40 static ssgLoaderOptions* currentOptions = NULL ;
41 static _nodeIndex *definedNodes = NULL;
42 
43 static bool iv_parseSeparator( ssgBranch *parentBranch, _traversalState *parentData, char *defName );
44 static bool iv_parseSwitch( ssgBranch *parentBranch, _traversalState *parentData, char *defName );
45 static bool iv_parseIndexedFaceSet( ssgBranch *parentBranch, _traversalState *parentData, char *defName );
46 static bool iv_parseTexture2( ssgBranch *parentBranch, _traversalState *currentData, char *defName );
47 
48 static _parseTag ivTags [] =
49 {
50      { "Separator", iv_parseSeparator },
51      { "Switch", iv_parseSwitch },
52      { "IndexedFaceSet", iv_parseIndexedFaceSet },
53      { "Coordinate3", vrml1_parseCoordinate3 },
54      { "TextureCoordinate2", vrml1_parseTextureCoordinate2 },
55      { "Texture2", iv_parseTexture2 },
56      { "ShapeHints", vrml1_parseShapeHints },
57      { "MatrixTransform", vrml1_parseMatrixTransform },
58      { "Scale", vrml1_parseScale },
59      { "Rotation", vrml1_parseRotation },
60      { "Translation", vrml1_parseTranslation },
61      { NULL, NULL },
62 };
63 
ssgLoadIV(const char * fname,const ssgLoaderOptions * options)64 ssgEntity *ssgLoadIV( const char *fname, const ssgLoaderOptions* options )
65 {
66   ssgSetCurrentOptions ( (ssgLoaderOptions*)options ) ;
67   currentOptions = ssgGetCurrentOptions () ;
68 
69    if ( !vrmlParser.openFile( fname, &parser_spec ) ) {
70     ulSetError ( UL_WARNING, "ssgLoadIV: Failed to open '%s' for reading", fname ) ;
71     return 0;
72   }
73 
74    definedNodes = new _nodeIndex();
75 
76    // check for a valid header header
77    char *token;
78    if( !(token =  vrmlParser.getRawLine()) )
79      return 0;
80      if( strstr( token, "#Inventor V2.1 ascii" ) == NULL ) // should we handle different flavours of inventor?
81        {
82 	  ulSetError ( UL_WARNING, "ssgLoadIV: valid iv header not found" );
83 	  return 0;
84        }
85 
86    // creating a root node..
87    ssgBranch *rootBranch = new ssgBranch();
88 
89    vrmlParser.expectNextToken( "Separator" );
90 
91    if( !iv_parseSeparator( rootBranch, NULL, NULL ) )
92      {
93 	ulSetError ( UL_WARNING, "ssgLoadVRML: Failed to extract valid object(s) from %s", fname ) ;
94 	delete( rootBranch );
95 	delete( definedNodes );
96 	return NULL ;
97      }
98 
99    vrmlParser.closeFile();
100    delete( definedNodes );
101 
102    return rootBranch ;
103 }
104 
iv_parseSeparator(ssgBranch * parentBranch,_traversalState * parentData,char * defName)105 static bool iv_parseSeparator( ssgBranch *parentBranch, _traversalState *parentData, char *defName )
106 {
107    char *childDefName = NULL;
108 
109    char *token;
110 
111    vrmlParser.expectNextToken( "{" );
112 
113    // create a branch for this node
114    ssgBranch *currentBranch = new ssgBranch();
115 
116    if( defName != NULL )
117      {
118 	currentBranch->setName( defName );
119 	definedNodes->insert( currentBranch );
120      }
121 
122    _traversalState *currentData;
123    if( parentData == NULL )
124      currentData = new _traversalState();
125    else
126      currentData = parentData->clone();
127 
128    token = vrmlParser.getNextToken( NULL );
129    while( strcmp( token, "}" ) )
130      {
131 	int i=0; bool tokenFound = FALSE;
132 	while( ivTags[i].token != NULL && !tokenFound )
133 	  {
134 	     if( !strcmp( token, ivTags[i].token ) )
135 	       {
136 		  if( !(ivTags[i].func( currentBranch, currentData, childDefName ) ) )
137 		    {
138 		       delete( currentBranch );
139 		       delete( currentData );
140 		       return FALSE;
141 		    }
142 		  tokenFound = TRUE;
143 	       }
144 
145 	     i++;
146 	  }
147 	if( !tokenFound )
148 	  parseUnidentified();
149 
150 	token = vrmlParser.getNextToken( NULL );
151      }
152 
153    parentBranch->addKid( currentBranch );
154 
155    delete( currentData ); // delete the currentData structure (we may use its content, but not its form)
156 
157    return TRUE;
158 }
159 
iv_parseSwitch(ssgBranch * parentBranch,_traversalState * parentData,char * defName)160 static bool iv_parseSwitch( ssgBranch *parentBranch, _traversalState *parentData, char *defName )
161 // UNSUPPORTED BEHAVIOUR: does not do a check for a whichChild parameter. Assumes that a switch
162 // "hides" all of its children.
163 {
164    char *childDefName = NULL;
165 
166    char *token;
167 
168    vrmlParser.expectNextToken( "{" );
169 
170    // create a branch for this node
171    ssgBranch *currentBranch = new ssgSelector();
172    ((ssgSelector *)currentBranch)->select( 0 ); // fixme: allow for children to be traversed
173 
174 
175    if( defName != NULL )
176      {
177 	currentBranch->setName( defName );
178 	definedNodes->insert( currentBranch );
179       }
180 
181    _traversalState *currentData;
182    if( parentData == NULL )
183      currentData = new _traversalState();
184    else
185      currentData = parentData->clone();
186 
187    token = vrmlParser.getNextToken( NULL );
188 
189    while( strcmp( token, "}" ) )
190      {
191 	int i=0; bool tokenFound = FALSE;
192 	while( ivTags[i].token != NULL && !tokenFound )
193 	  {
194 	     if( !strcmp( token, ivTags[i].token ) )
195 	       {
196 		  if( !(ivTags[i].func( currentBranch, currentData, childDefName ) ) )
197 		    {
198 		       delete( currentBranch );
199 		       delete( currentData );
200 		       return FALSE;
201 		    }
202 
203 		  tokenFound = TRUE;
204 	       }
205 	     i++;
206 	  }
207 	if( !tokenFound )
208 	  parseUnidentified();
209 
210 	token = vrmlParser.getNextToken( NULL );
211      }
212 
213    parentBranch->addKid( currentBranch );
214 
215    delete( currentData ); // delete the currentData structure (we may use its content, but not its form)
216 
217    return TRUE;
218 }
219 
iv_parseIndexedFaceSet(ssgBranch * parentBranch,_traversalState * currentData,char * defName)220 static bool iv_parseIndexedFaceSet( ssgBranch *parentBranch, _traversalState *currentData, char *defName )
221 {
222    char *token;
223    bool texCoordIndexGiven = FALSE;
224 
225    ssgBranch *currentBranch = new ssgBranch();
226    if( defName != NULL )
227      {
228 	currentBranch->setName( defName );
229 	definedNodes->insert( currentBranch );
230      }
231 
232    ssgLoaderWriterMesh *loaderMesh = new ssgLoaderWriterMesh();
233    loaderMesh->createFaces();
234    loaderMesh->setVertices( currentData->getVertices() );
235    if( currentData->getTexture() != NULL && currentData->getTextureCoordinates() != NULL )
236      loaderMesh->createPerFaceAndVertexTextureCoordinates2();
237 
238    vrmlParser.expectNextToken("{");
239 
240    token = vrmlParser.peekAtNextToken( NULL );
241    while( strcmp( token, "}" ) )
242      {
243 	if( !strcmp( token, "coordIndex" ) )
244 	  {
245 	     vrmlParser.expectNextToken("coordIndex");
246 	     if( !vrml1_parseCoordIndex( loaderMesh, currentData ) )
247 	       {
248 		  delete( loaderMesh );
249 		  return FALSE;
250 	       }
251 	  }
252 
253 	else if( !strcmp( token, "textureCoordIndex" ) )
254 	  {
255 	     texCoordIndexGiven = TRUE;
256 	     vrmlParser.expectNextToken("textureCoordIndex");
257 	     if( !vrml1_parseTextureCoordIndex( loaderMesh, currentData ) )
258 	       {
259 		  delete( loaderMesh );
260 		  return FALSE;
261 	       }
262 	  }
263 	else
264 	  token = vrmlParser.getNextToken( NULL );
265 
266 	token = vrmlParser.peekAtNextToken( NULL );
267      }
268 
269    //ulSetError(UL_DEBUG, "Level: %i. Found %i faces here.\n", vrmlParser.level, numFaces);
270 
271    vrmlParser.expectNextToken( "}" );
272 
273    // -------------------------------------------------------
274    // add the face set to ssg
275    // -------------------------------------------------------
276 
277    // kludge. We need a state for addToSSG:
278    ssgSimpleState * ss = new ssgSimpleState () ; // (0) ?
279    ss -> setMaterial ( GL_AMBIENT, 0.5, 0.5, 0.5, 1.0);
280    ss -> setMaterial ( GL_DIFFUSE, 1.0, 1.0, 1.0, 1.0) ; // 0.8, 0.8, 1.0, 1.0f
281    ss -> setMaterial ( GL_SPECULAR, 1.0, 1.0, 1.0, 1.0);
282    ss -> setMaterial ( GL_EMISSION, 0.0, 0.0, 0.0, 1.0);
283    ss -> setShininess ( 20 ) ; // Fixme, NIV14: Is that correct?
284 
285    // -------------------------------------------------------
286    // texturing stuff
287    // -------------------------------------------------------
288    // todo: give an implicit mapping if texture coordinates are not given
289    // todo: add support for per-vertex texturing
290    if( currentData->getTexture() != NULL && currentData->getTextureCoordinates() != NULL && texCoordIndexGiven )
291      {
292 	ss -> setTexture ( currentData->getTexture() );
293 	ss -> enable( GL_TEXTURE_2D );
294      }
295    else
296 	ss -> disable( GL_TEXTURE_2D );
297 
298    ss -> disable ( GL_COLOR_MATERIAL ) ;
299    //ss -> enable ( GL_COLOR_MATERIAL ) ;
300    //ss -> setColourMaterial ( GL_AMBIENT_AND_DIFFUSE ) ;
301 
302    ss -> enable  ( GL_LIGHTING       ) ;
303    ss -> setShadeModel ( GL_SMOOTH ) ;
304 
305    ss  ->disable(GL_ALPHA_TEST); //needed?
306 
307    ss -> disable ( GL_BLEND ) ;
308 
309    ss -> setOpaque () ;
310 
311    if( !currentData->getEnableCullFace() )
312      ss->disable( GL_CULL_FACE );
313 
314    if( !loaderMesh->checkMe() )
315      {
316 	delete( loaderMesh );
317 	return FALSE;
318      }
319 
320    if( currentData->getTransform() != NULL )
321      {
322 	currentBranch->addKid( currentData->getTransform() ); // FIXME: in case we're reusing transforms, perhaps they should be reinstanced? (currently we don't allow this)
323  	loaderMesh->addToSSG( ss, currentOptions, currentData->getTransform() );
324      }
325    else
326  	loaderMesh->addToSSG( ss, currentOptions, currentBranch );
327 
328    parentBranch->addKid( currentBranch );
329 
330    return TRUE;
331 }
332 
iv_parseTexture2(ssgBranch * parentBranch,_traversalState * currentData,char * defName)333 static bool iv_parseTexture2( ssgBranch *parentBranch, _traversalState *currentData, char *defName )
334 {
335    char *token;
336    char *fileName = NULL; bool wrapU = FALSE, wrapV = FALSE;
337 
338    vrmlParser.expectNextToken("{");
339 
340    token = vrmlParser.peekAtNextToken( NULL );
341    while( strcmp( token, "}" ) )
342      {
343 	if( !strcmp( token, "filename") )
344 	  {
345 	     vrmlParser.expectNextToken("filename");
346 	     if( !vrmlParser.getNextString( token, NULL ) )
347 	       return FALSE;
348              fileName = ulStrDup ( token ) ;
349 	  }
350 	else if( !strcmp( token, "wrapS") )
351 	  {
352 	     vrmlParser.expectNextToken("wrapS");
353 	     token = vrmlParser.getNextToken( NULL );
354 	     if( !strcmp( token, "REPEAT") )
355 	       wrapU = TRUE;
356 	  }
357 	else if( !strcmp( token, "wrapT") )
358 	  {
359 	     vrmlParser.expectNextToken("wrapT");
360 	     token = vrmlParser.getNextToken( NULL );
361 	     if( !strcmp( token, "REPEAT") )
362 	       wrapV = TRUE;
363 	  }
364 	else
365 	  token = vrmlParser.getNextToken( NULL );
366 
367 	token = vrmlParser.peekAtNextToken( NULL );
368      }
369 
370    if( fileName == NULL )
371      return FALSE;
372 
373    //ssgTexture *currentTexture = new ssgTexture( fileName, wrapU, wrapV );
374    ssgTexture *currentTexture = currentOptions -> createTexture ( fileName, wrapU, wrapV );
375    currentData->setTexture( currentTexture );
376    vrmlParser.expectNextToken("}");
377 
378    delete [] fileName;
379 
380    return TRUE;
381 }
382