1 /* -----------------------------------------------------------------------------
5 Copyright (c) 2002, Randy Reddig & seaw0lf
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
11 Redistributions of source code must retain the above copyright notice, this list
12 of conditions and the following disclaimer.
14 Redistributions in binary form must reproduce the above copyright notice, this
15 list of conditions and the following disclaimer in the documentation and/or
16 other materials provided with the distribution.
18 Neither the names of the copyright holders nor the names of its contributors may
19 be used to endorse or promote products derived from this software without
20 specific prior written permission.
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 ----------------------------------------------------------------------------- */
41 #include "picointernal.h"
43 /* disable warnings */
45 #pragma warning( disable:4100 ) /* unref param */
49 * - '_obj_load' code crashes in a weird way after
50 * '_obj_mtl_load' for a few .mtl files
51 * - process 'mtllib' rather than using <model>.mtl
52 * - handle 'usemtl' statements
54 /* uncomment when debugging this module */
55 /* #define DEBUG_PM_OBJ */
56 /* #define DEBUG_PM_OBJ_EX */
58 /* this holds temporary vertex data read by parser */
59 typedef struct SObjVertexData
61 picoVec3_t v; /* geometric vertices */
62 picoVec2_t vt; /* texture vertices */
63 picoVec3_t vn; /* vertex normals (optional) */
68 * validates a wavefront obj model file.
70 static int _obj_canload( PM_PARAMS_CANLOAD )
74 /* check data length */
76 return PICO_PMV_ERROR_SIZE;
78 /* first check file extension. we have to do this for objs */
79 /* cause there is no good way to identify the contents */
80 if (_pico_stristr(fileName,".obj") != NULL ||
81 _pico_stristr(fileName,".wf" ) != NULL)
85 /* if the extension check failed we parse through the first */
86 /* few lines in file and look for common keywords often */
87 /* appearing at the beginning of wavefront objects */
89 /* alllocate a new pico parser */
90 p = _pico_new_parser( (picoByte_t *)buffer,bufSize );
92 return PICO_PMV_ERROR_MEMORY;
94 /* parse obj head line by line for type check */
97 /* get first token on line */
98 if (_pico_parse_first( p ) == NULL)
101 /* we only parse the first few lines, say 80 */
105 /* skip empty lines */
106 if (p->token == NULL || !strlen( p->token ))
109 /* material library keywords are teh good */
110 if (!_pico_stricmp(p->token,"usemtl") ||
111 !_pico_stricmp(p->token,"mtllib") ||
112 !_pico_stricmp(p->token,"g") ||
113 !_pico_stricmp(p->token,"v")) /* v,g bit fishy, but uh... */
115 /* free the pico parser thing */
116 _pico_free_parser( p );
118 /* seems to be a valid wavefront obj */
121 /* skip rest of line */
122 _pico_parse_skip_rest( p );
124 /* free the pico parser thing */
125 _pico_free_parser( p );
127 /* doesn't really look like an obj to us */
128 return PICO_PMV_ERROR;
131 /* SizeObjVertexData:
132 * This pretty piece of 'alloc ahead' code dynamically
133 * allocates - and reallocates as soon as required -
134 * my vertex data array in even steps.
136 #define SIZE_OBJ_STEP 4096
138 static TObjVertexData *SizeObjVertexData(
139 TObjVertexData *vertexData, int reqEntries,
140 int *entries, int *allocated)
147 if (entries == NULL || allocated == NULL)
148 return NULL; /* must have */
150 /* no need to grow yet */
151 if (vertexData && (reqEntries < *allocated))
153 *entries = reqEntries;
156 /* given vertex data ptr not allocated yet */
157 if (vertexData == NULL)
159 /* how many entries to allocate */
160 newAllocated = (reqEntries > SIZE_OBJ_STEP) ?
161 reqEntries : SIZE_OBJ_STEP;
163 /* throw out an extended debug message */
164 #ifdef DEBUG_PM_OBJ_EX
165 printf("SizeObjVertexData: allocate (%d entries)\n",
168 /* first time allocation */
169 vertexData = (TObjVertexData *)
170 _pico_alloc( sizeof(TObjVertexData) * newAllocated );
172 /* allocation failed */
173 if (vertexData == NULL)
176 /* allocation succeeded */
177 *allocated = newAllocated;
178 *entries = reqEntries;
181 /* given vertex data ptr needs to be resized */
182 if (reqEntries == *allocated)
184 newAllocated = (*allocated + SIZE_OBJ_STEP);
186 /* throw out an extended debug message */
187 #ifdef DEBUG_PM_OBJ_EX
188 printf("SizeObjVertexData: reallocate (%d entries)\n",
191 /* try to reallocate */
192 vertexData = (TObjVertexData *)
193 _pico_realloc( (void *)&vertexData,
194 sizeof(TObjVertexData) * (*allocated),
195 sizeof(TObjVertexData) * (newAllocated));
197 /* reallocation failed */
198 if (vertexData == NULL)
201 /* reallocation succeeded */
202 *allocated = newAllocated;
203 *entries = reqEntries;
206 /* we're b0rked when we reach this */
210 static void FreeObjVertexData( TObjVertexData *vertexData )
212 if (vertexData != NULL)
214 free( (TObjVertexData *)vertexData );
218 static int _obj_mtl_load( picoModel_t *model )
220 picoShader_t *curShader = NULL;
222 picoByte_t *mtlBuffer;
227 if( model == NULL || model->fileName == NULL )
230 /* skip if we have a zero length model file name */
231 if (!strlen( model->fileName ))
235 #define _obj_mtl_error_return \
237 _pico_free_parser( p ); \
238 _pico_free_file( mtlBuffer ); \
239 _pico_free( fileName ); \
242 /* alloc copy of model file name */
243 fileName = _pico_clone_alloc( model->fileName );
244 if (fileName == NULL)
247 /* change extension of model file to .mtl */
248 _pico_setfext( fileName, "mtl" );
250 /* load .mtl file contents */
251 _pico_load_file( fileName,&mtlBuffer,&mtlBufSize );
254 if (mtlBufSize == 0) return 1; /* file is empty: no error */
255 if (mtlBufSize < 0) return 0; /* load failed: error */
257 /* create a new pico parser */
258 p = _pico_new_parser( mtlBuffer, mtlBufSize );
260 _obj_mtl_error_return;
262 /* doo teh .mtl parse */
265 /* get next token in material file */
266 if (_pico_parse( p,1 ) == NULL)
270 /* skip empty lines */
271 if (p->token == NULL || !strlen( p->token ))
274 /* skip comment lines */
275 if (p->token[0] == '#')
277 _pico_parse_skip_rest( p );
281 if (!_pico_stricmp(p->token,"newmtl"))
283 picoShader_t *shader;
286 /* get material name */
287 name = _pico_parse( p,0 );
289 /* validate material name */
290 if (name == NULL || !strlen(name))
292 _pico_printf( PICO_ERROR,"Missing material name in MTL, line %d.",p->curLine);
293 _obj_mtl_error_return;
295 /* create a new pico shader */
296 shader = PicoNewShader( model );
298 _obj_mtl_error_return;
300 /* set shader name */
301 PicoSetShaderName( shader,name );
303 /* assign pointer to current shader */
306 /* diffuse map name */
307 else if (!_pico_stricmp(p->token,"map_kd"))
310 picoShader_t *shader;
312 /* pointer to current shader must be valid */
313 if (curShader == NULL)
314 _obj_mtl_error_return;
316 /* get material's diffuse map name */
317 mapName = _pico_parse( p,0 );
319 /* validate map name */
320 if (mapName == NULL || !strlen(mapName))
322 _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine);
323 _obj_mtl_error_return;
325 /* create a new pico shader */
326 shader = PicoNewShader( model );
328 _obj_mtl_error_return;
329 /* set shader map name */
330 PicoSetShaderMapName( shader,mapName );
332 /* dissolve factor (pseudo transparency 0..1) */
333 /* where 0 means 100% transparent and 1 means opaque */
334 else if (!_pico_stricmp(p->token,"d"))
340 /* get dissolve factor */
341 if (!_pico_parse_float( p,&value ))
342 _obj_mtl_error_return;
344 /* set shader transparency */
345 PicoSetShaderTransparency( curShader,value );
347 /* get shader's diffuse color */
348 diffuse = PicoGetShaderDiffuseColor( curShader );
350 /* set diffuse alpha to transparency */
351 diffuse[ 3 ] = (picoByte_t)( value * 255.0 );
353 /* set shader's new diffuse color */
354 PicoSetShaderDiffuseColor( curShader,diffuse );
356 /* shininess (phong specular component) */
357 else if (!_pico_stricmp(p->token,"ns"))
360 * - well, this is some major obj spec fuckup once again. some
361 * apps store this in 0..1 range, others use 0..100 range,
362 * even others use 0..2048 range, and again others use the
363 * range 0..128, some even use 0..1000, 0..200, 400..700,
364 * honestly, what's up with the 3d app coders? happens when
365 * you smoke too much weed i guess. -sea
369 /* pointer to current shader must be valid */
370 if (curShader == NULL)
371 _obj_mtl_error_return;
373 /* get totally screwed up shininess (a random value in fact ;) */
374 if (!_pico_parse_float( p,&value ))
375 _obj_mtl_error_return;
377 /* okay, there is no way to set this correctly, so we simply */
378 /* try to guess a few ranges (most common ones i have seen) */
380 /* assume 0..2048 range */
382 value = 128.0 * (value / 2048.0);
383 /* assume 0..1000 range */
384 else if (value > 200)
385 value = 128.0 * (value / 1000.0);
386 /* assume 0..200 range */
387 else if (value > 100)
388 value = 128.0 * (value / 200.0);
389 /* assume 0..100 range */
391 value = 128.0 * (value / 100.0);
392 /* assume 0..1 range */
396 /* negative shininess is bad (yes, i have seen it...) */
397 if (value < 0.0) value = 0.0;
399 /* set the pico shininess value in range 0..127 */
400 /* geez, .obj is such a mess... */
401 PicoSetShaderShininess( curShader,value );
403 /* kol0r ambient (wut teh fuk does "ka" stand for?) */
404 else if (!_pico_stricmp(p->token,"ka"))
409 /* pointer to current shader must be valid */
410 if (curShader == NULL)
411 _obj_mtl_error_return;
413 /* get color vector */
414 if (!_pico_parse_vec( p,v ))
415 _obj_mtl_error_return;
417 /* scale to byte range */
418 color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 );
419 color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 );
420 color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 );
421 color[ 3 ] = (picoByte_t)( 255 );
423 /* set ambient color */
424 PicoSetShaderAmbientColor( curShader,color );
427 else if (!_pico_stricmp(p->token,"kd"))
432 /* pointer to current shader must be valid */
433 if (curShader == NULL)
434 _obj_mtl_error_return;
436 /* get color vector */
437 if (!_pico_parse_vec( p,v ))
438 _obj_mtl_error_return;
440 /* scale to byte range */
441 color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 );
442 color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 );
443 color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 );
444 color[ 3 ] = (picoByte_t)( 255 );
446 /* set diffuse color */
447 PicoSetShaderDiffuseColor( curShader,color );
450 else if (!_pico_stricmp(p->token,"ks"))
455 /* pointer to current shader must be valid */
456 if (curShader == NULL)
457 _obj_mtl_error_return;
459 /* get color vector */
460 if (!_pico_parse_vec( p,v ))
461 _obj_mtl_error_return;
463 /* scale to byte range */
464 color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 );
465 color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 );
466 color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 );
467 color[ 3 ] = (picoByte_t)( 255 );
469 /* set specular color */
470 PicoSetShaderSpecularColor( curShader,color );
473 /* skip rest of line */
474 _pico_parse_skip_rest( p );
477 /* free parser, file buffer, and file name */
478 _pico_free_parser( p );
479 _pico_free_file( mtlBuffer );
480 _pico_free( fileName );
482 /* return with success */
487 * loads a wavefront obj model file.
489 static picoModel_t *_obj_load( PM_PARAMS_LOAD )
491 TObjVertexData *vertexData = NULL;
493 picoSurface_t *curSurface = NULL;
504 #define _obj_error_return(m) \
506 _pico_printf( PICO_ERROR,"%s in OBJ, line %d.",m,p->curLine); \
507 _pico_free_parser( p ); \
508 FreeObjVertexData( vertexData ); \
509 PicoFreeModel( model ); \
512 /* alllocate a new pico parser */
513 p = _pico_new_parser( (picoByte_t *)buffer,bufSize );
514 if (p == NULL) return NULL;
516 /* create a new pico model */
517 model = PicoNewModel();
520 _pico_free_parser( p );
524 PicoSetModelFrameNum( model,frameNum );
525 PicoSetModelName( model,fileName );
526 PicoSetModelFileName( model,fileName );
528 /* try loading the materials; we don't handle the result */
530 _obj_mtl_load( model );
533 /* parse obj line by line */
536 /* get first token on line */
537 if (_pico_parse_first( p ) == NULL)
540 /* skip empty lines */
541 if (p->token == NULL || !strlen( p->token ))
544 /* skip comment lines */
545 if (p->token[0] == '#')
547 _pico_parse_skip_rest( p );
551 if (!_pico_stricmp(p->token,"v"))
553 TObjVertexData *data;
556 vertexData = SizeObjVertexData( vertexData,numVerts+1,&entries,&allocated );
557 if (vertexData == NULL)
558 _obj_error_return("Realloc of vertex data failed (1)");
560 data = &vertexData[ numVerts++ ];
562 /* get and copy vertex */
563 if (!_pico_parse_vec( p,v ))
564 _obj_error_return("Vertex parse error");
566 _pico_copy_vec( v,data->v );
568 #ifdef DEBUG_PM_OBJ_EX
569 printf("Vertex: x: %f y: %f z: %f\n",v[0],v[1],v[2]);
573 else if (!_pico_stricmp(p->token,"vt"))
575 TObjVertexData *data;
578 vertexData = SizeObjVertexData( vertexData,numUVs+1,&entries,&allocated );
579 if (vertexData == NULL)
580 _obj_error_return("Realloc of vertex data failed (2)");
582 data = &vertexData[ numUVs++ ];
584 /* get and copy tex coord */
585 if (!_pico_parse_vec2( p,coord ))
586 _obj_error_return("UV coord parse error");
588 _pico_copy_vec2( coord,data->vt );
590 #ifdef DEBUG_PM_OBJ_EX
591 printf("TexCoord: u: %f v: %f\n",coord[0],coord[1]);
595 else if (!_pico_stricmp(p->token,"vn"))
597 TObjVertexData *data;
600 vertexData = SizeObjVertexData( vertexData,numNormals+1,&entries,&allocated );
601 if (vertexData == NULL)
602 _obj_error_return("Realloc of vertex data failed (3)");
604 data = &vertexData[ numNormals++ ];
606 /* get and copy vertex normal */
607 if (!_pico_parse_vec( p,n ))
608 _obj_error_return("Vertex normal parse error");
610 _pico_copy_vec( n,data->vn );
612 #ifdef DEBUG_PM_OBJ_EX
613 printf("Normal: x: %f y: %f z: %f\n",n[0],n[1],n[2]);
616 /* new group (for us this means a new surface) */
617 else if (!_pico_stricmp(p->token,"g"))
619 picoSurface_t *newSurface;
622 /* get first group name (ignore 2nd,3rd,etc.) */
623 groupName = _pico_parse( p,0 );
624 if (groupName == NULL || !strlen(groupName))
626 /* some obj exporters feel like they don't need to */
627 /* supply a group name. so we gotta handle it here */
629 strcpy( p->token,"default" );
630 groupName = p->token;
632 _obj_error_return("Invalid or missing group name");
635 /* allocate a pico surface */
636 newSurface = PicoNewSurface( model );
637 if (newSurface == NULL)
638 _obj_error_return("Error allocating surface");
640 /* reset face index for surface */
643 /* set ptr to current surface */
644 curSurface = newSurface;
646 /* we use triangle meshes */
647 PicoSetSurfaceType( newSurface,PICO_TRIANGLES );
649 /* set surface name */
650 PicoSetSurfaceName( newSurface,groupName );
652 #ifdef DEBUG_PM_OBJ_EX
653 printf("Group: '%s'\n",groupName);
656 /* face (oh jesus, hopefully this will do the job right ;) */
657 else if (!_pico_stricmp(p->token,"f"))
659 /* okay, this is a mess. some 3d apps seem to try being unique, */
660 /* hello cinema4d & 3d exploration, feel good today?, and save */
661 /* this crap in tons of different formats. gah, those screwed */
662 /* coders. tho the wavefront obj standard defines exactly two */
663 /* ways of storing face information. so, i really won't support */
664 /* such stupid extravaganza here! */
666 picoVec3_t verts [ 4 ];
667 picoVec3_t normals[ 4 ];
668 picoVec2_t coords [ 4 ];
671 int ivt[ 4 ], has_vt = 0;
672 int ivn[ 4 ], has_vn = 0;
678 /* group defs *must* come before faces */
679 if (curSurface == NULL)
680 _obj_error_return("No group defined for faces");
682 #ifdef DEBUG_PM_OBJ_EX
685 /* read vertex/uv/normal indices for the first three face */
686 /* vertices (cause we only support triangles) into 'i*[]' */
687 /* store the actual vertex/uv/normal data in three arrays */
688 /* called 'verts','coords' and 'normals'. */
693 /* get next vertex index string (different */
694 /* formats are handled below) */
695 str = _pico_parse( p,0 );
698 /* just break for quads */
701 /* error otherwise */
702 _obj_error_return("Face parse error");
704 /* if this is the fourth index string we're */
705 /* parsing we assume that we have a quad */
709 /* get slash count once */
712 slashcount = _pico_strchcount( str,'/' );
713 doubleslash = strstr(str,"//") != NULL;
715 /* handle format 'v//vn' */
716 if (doubleslash && (slashcount == 2))
719 sscanf( str,"%d//%d",&iv[ i ],&ivn[ i ] );
721 /* handle format 'v/vt/vn' */
722 else if (!doubleslash && (slashcount == 2))
724 has_v = has_vt = has_vn = 1;
725 sscanf( str,"%d/%d/%d",&iv[ i ],&ivt[ i ],&ivn[ i ] );
727 /* handle format 'v/vt' (non-standard fuckage) */
728 else if (!doubleslash && (slashcount == 1))
731 sscanf( str,"%d/%d",&iv[ i ],&ivt[ i ] );
733 /* else assume face format 'v' */
734 /* (must have been invented by some bored granny) */
736 /* get single vertex index */
738 iv[ i ] = atoi( str );
740 /* either invalid face format or out of range */
742 _obj_error_return("Invalid face format");
744 /* fix useless back references */
745 /* todo: check if this works as it is supposed to */
747 /* assign new indices */
748 if (iv [ i ] < 0) iv [ i ] = (numVerts - iv [ i ]);
749 if (ivt[ i ] < 0) ivt[ i ] = (numUVs - ivt[ i ]);
750 if (ivn[ i ] < 0) ivn[ i ] = (numNormals - ivn[ i ]);
752 /* validate indices */
753 /* - commented out. index range checks will trigger
754 if (iv [ i ] < 1) iv [ i ] = 1;
755 if (ivt[ i ] < 1) ivt[ i ] = 1;
756 if (ivn[ i ] < 1) ivn[ i ] = 1;
758 /* set vertex origin */
761 /* check vertex index range */
762 if (iv[ i ] < 1 || iv[ i ] > numVerts)
763 _obj_error_return("Vertex index out of range");
765 /* get vertex data */
766 verts[ i ][ 0 ] = vertexData[ iv[ i ] - 1 ].v[ 0 ];
767 verts[ i ][ 1 ] = vertexData[ iv[ i ] - 1 ].v[ 1 ];
768 verts[ i ][ 2 ] = vertexData[ iv[ i ] - 1 ].v[ 2 ];
770 /* set vertex normal */
773 /* check normal index range */
774 if (ivn[ i ] < 1 || ivn[ i ] > numNormals)
775 _obj_error_return("Normal index out of range");
777 /* get normal data */
778 normals[ i ][ 0 ] = vertexData[ ivn[ i ] - 1 ].vn[ 0 ];
779 normals[ i ][ 1 ] = vertexData[ ivn[ i ] - 1 ].vn[ 1 ];
780 normals[ i ][ 2 ] = vertexData[ ivn[ i ] - 1 ].vn[ 2 ];
782 /* set texture coordinate */
785 /* check uv index range */
786 if (ivt[ i ] < 1 || ivt[ i ] > numUVs)
787 _obj_error_return("UV coord index out of range");
789 /* get uv coord data */
790 coords[ i ][ 0 ] = vertexData[ ivt[ i ] - 1 ].vt[ 0 ];
791 coords[ i ][ 1 ] = vertexData[ ivt[ i ] - 1 ].vt[ 1 ];
792 coords[ i ][ 1 ] = -coords[ i ][ 1 ];
794 #ifdef DEBUG_PM_OBJ_EX
795 printf("(%4d",iv[ i ]);
796 if (has_vt) printf(" %4d",ivt[ i ]);
797 if (has_vn) printf(" %4d",ivn[ i ]);
801 #ifdef DEBUG_PM_OBJ_EX
804 /* now that we have extracted all the indices and have */
805 /* read the actual data we need to assign all the crap */
806 /* to our current pico surface */
810 if (have_quad) max = 4;
812 /* assign all surface information */
813 for (i=0; i<max; i++)
815 /*if( has_v )*/ PicoSetSurfaceXYZ ( curSurface, (curVertex + i), verts [ i ] );
816 /*if( has_vt )*/ PicoSetSurfaceST ( curSurface,0,(curVertex + i), coords [ i ] );
817 /*if( has_vn )*/ PicoSetSurfaceNormal( curSurface, (curVertex + i), normals[ i ] );
819 /* add our triangle (A B C) */
820 PicoSetSurfaceIndex( curSurface,(curFace * 3 + 2),(picoIndex_t)( curVertex + 0 ) );
821 PicoSetSurfaceIndex( curSurface,(curFace * 3 + 1),(picoIndex_t)( curVertex + 1 ) );
822 PicoSetSurfaceIndex( curSurface,(curFace * 3 + 0),(picoIndex_t)( curVertex + 2 ) );
825 /* if we don't have a simple triangle, but a quad... */
828 /* we have to add another triangle (2nd half of quad which is A C D) */
829 PicoSetSurfaceIndex( curSurface,(curFace * 3 + 2),(picoIndex_t)( curVertex + 0 ) );
830 PicoSetSurfaceIndex( curSurface,(curFace * 3 + 1),(picoIndex_t)( curVertex + 2 ) );
831 PicoSetSurfaceIndex( curSurface,(curFace * 3 + 0),(picoIndex_t)( curVertex + 3 ) );
834 /* increase vertex count */
838 else if (!_pico_stricmp(p->token,"usemtl"))
840 picoShader_t *shader;
843 /* get material name */
844 name = _pico_parse( p,0 );
846 /* validate material name */
847 if (name == NULL || !strlen(name))
849 _pico_printf( PICO_ERROR,"Missing material name in OBJ, line %d.",p->curLine);
853 shader = PicoFindShader( model, name, 1 );
856 _pico_printf( PICO_ERROR,"Undefined material name in OBJ, line %d. Making a default shader.",p->curLine);
858 /* create a new pico shader */
859 shader = PicoNewShader( model );
862 PicoSetShaderName( shader,name );
863 PicoSetShaderMapName( shader,name );
864 PicoSetSurfaceShader( curSurface, shader );
869 PicoSetSurfaceShader( curSurface, shader );
873 /* skip unparsed rest of line and continue */
874 _pico_parse_skip_rest( p );
876 /* free memory used by temporary vertexdata */
877 FreeObjVertexData( vertexData );
879 /* return allocated pico model */
884 /* pico file format module definition */
885 const picoModule_t picoModuleOBJ =
887 "0.6-b", /* module version string */
888 "Wavefront ASCII", /* module display name */
889 "seaw0lf", /* author's name */
890 "2002 seaw0lf", /* module copyright */
892 "obj",NULL,NULL,NULL /* default extensions to use */
894 _obj_canload, /* validation routine */
895 _obj_load, /* load routine */
896 NULL, /* save validation routine */
897 NULL /* save routine */