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