+++ /dev/null
-/* -----------------------------------------------------------------------------
-
-PicoModel Library
-
-Copyright (c) 2002, Randy Reddig & seaw0lf
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list
-of conditions and the following disclaimer.
-
-Redistributions in binary form must reproduce the above copyright notice, this
-list of conditions and the following disclaimer in the documentation and/or
-other materials provided with the distribution.
-
-Neither the names of the copyright holders nor the names of its contributors may
-be used to endorse or promote products derived from this software without
-specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
------------------------------------------------------------------------------ */
-
-
-
-/* marker */
-#define PM_OBJ_C
-
-/* dependencies */
-#include "picointernal.h"
-
-/* disable warnings */
-#ifdef WIN32
-#pragma warning( disable:4100 ) /* unref param */
-#endif
-
-/* todo:
- * - '_obj_load' code crashes in a weird way after
- * '_obj_mtl_load' for a few .mtl files
- * - process 'mtllib' rather than using <model>.mtl
- * - handle 'usemtl' statements
- */
-/* uncomment when debugging this module */
-/* #define DEBUG_PM_OBJ */
-/* #define DEBUG_PM_OBJ_EX */
-
-/* this holds temporary vertex data read by parser */
-typedef struct SObjVertexData
-{
- picoVec3_t v; /* geometric vertices */
- picoVec2_t vt; /* texture vertices */
- picoVec3_t vn; /* vertex normals (optional) */
-}
-TObjVertexData;
-
-/* _obj_canload:
- * validates a wavefront obj model file.
- */
-static int _obj_canload( PM_PARAMS_CANLOAD )
-{
- picoParser_t *p;
-
- /* check data length */
- if (bufSize < 30)
- return PICO_PMV_ERROR_SIZE;
-
- /* first check file extension. we have to do this for objs */
- /* cause there is no good way to identify the contents */
- if (_pico_stristr(fileName,".obj") != NULL ||
- _pico_stristr(fileName,".wf" ) != NULL)
- {
- return PICO_PMV_OK;
- }
- /* if the extension check failed we parse through the first */
- /* few lines in file and look for common keywords often */
- /* appearing at the beginning of wavefront objects */
-
- /* alllocate a new pico parser */
- p = _pico_new_parser( (const picoByte_t *)buffer,bufSize );
- if (p == NULL)
- return PICO_PMV_ERROR_MEMORY;
-
- /* parse obj head line by line for type check */
- while( 1 )
- {
- /* get first token on line */
- if (_pico_parse_first( p ) == NULL)
- break;
-
- /* we only parse the first few lines, say 80 */
- if (p->curLine > 80)
- break;
-
- /* skip empty lines */
- if (p->token == NULL || !strlen( p->token ))
- continue;
-
- /* material library keywords are teh good */
- if (!_pico_stricmp(p->token,"usemtl") ||
- !_pico_stricmp(p->token,"mtllib") ||
- !_pico_stricmp(p->token,"g") ||
- !_pico_stricmp(p->token,"v")) /* v,g bit fishy, but uh... */
- {
- /* free the pico parser thing */
- _pico_free_parser( p );
-
- /* seems to be a valid wavefront obj */
- return PICO_PMV_OK;
- }
- /* skip rest of line */
- _pico_parse_skip_rest( p );
- }
- /* free the pico parser thing */
- _pico_free_parser( p );
-
- /* doesn't really look like an obj to us */
- return PICO_PMV_ERROR;
-}
-
-/* SizeObjVertexData:
- * This pretty piece of 'alloc ahead' code dynamically
- * allocates - and reallocates as soon as required -
- * my vertex data array in even steps.
- */
-#define SIZE_OBJ_STEP 4096
-
-static TObjVertexData *SizeObjVertexData(
- TObjVertexData *vertexData, int reqEntries,
- int *entries, int *allocated)
-{
- int newAllocated;
-
- /* sanity checks */
- if (reqEntries < 1)
- return NULL;
- if (entries == NULL || allocated == NULL)
- return NULL; /* must have */
-
- /* no need to grow yet */
- if (vertexData && (reqEntries < *allocated))
- {
- *entries = reqEntries;
- return vertexData;
- }
- /* given vertex data ptr not allocated yet */
- if (vertexData == NULL)
- {
- /* how many entries to allocate */
- newAllocated = (reqEntries > SIZE_OBJ_STEP) ?
- reqEntries : SIZE_OBJ_STEP;
-
- /* throw out an extended debug message */
-#ifdef DEBUG_PM_OBJ_EX
- printf("SizeObjVertexData: allocate (%d entries)\n",
- newAllocated);
-#endif
- /* first time allocation */
- vertexData = (TObjVertexData *)
- _pico_alloc( sizeof(TObjVertexData) * newAllocated );
-
- /* allocation failed */
- if (vertexData == NULL)
- return NULL;
-
- /* allocation succeeded */
- *allocated = newAllocated;
- *entries = reqEntries;
- return vertexData;
- }
- /* given vertex data ptr needs to be resized */
- if (reqEntries == *allocated)
- {
- newAllocated = (*allocated + SIZE_OBJ_STEP);
-
- /* throw out an extended debug message */
-#ifdef DEBUG_PM_OBJ_EX
- printf("SizeObjVertexData: reallocate (%d entries)\n",
- newAllocated);
-#endif
- /* try to reallocate */
- vertexData = (TObjVertexData *)
- _pico_realloc( (void *)&vertexData,
- sizeof(TObjVertexData) * (*allocated),
- sizeof(TObjVertexData) * (newAllocated));
-
- /* reallocation failed */
- if (vertexData == NULL)
- return NULL;
-
- /* reallocation succeeded */
- *allocated = newAllocated;
- *entries = reqEntries;
- return vertexData;
- }
- /* we're b0rked when we reach this */
- return NULL;
-}
-
-static void FreeObjVertexData( TObjVertexData *vertexData )
-{
- if (vertexData != NULL)
- {
- free( (TObjVertexData *)vertexData );
- }
-}
-
-static int _obj_mtl_load( picoModel_t *model )
-{
- picoShader_t *curShader = NULL;
- picoParser_t *p;
- picoByte_t *mtlBuffer;
- int mtlBufSize;
- char *fileName;
-
- /* sanity checks */
- if( model == NULL || model->fileName == NULL )
- return 0;
-
- /* skip if we have a zero length model file name */
- if (!strlen( model->fileName ))
- return 0;
-
- /* helper */
- #define _obj_mtl_error_return \
- { \
- _pico_free_parser( p ); \
- _pico_free_file( mtlBuffer ); \
- _pico_free( fileName ); \
- return 0; \
- }
- /* alloc copy of model file name */
- fileName = _pico_clone_alloc( model->fileName );
- if (fileName == NULL)
- return 0;
-
- /* change extension of model file to .mtl */
- _pico_setfext( fileName, "mtl" );
-
- /* load .mtl file contents */
- _pico_load_file( fileName,&mtlBuffer,&mtlBufSize );
-
- /* check result */
- if (mtlBufSize == 0) return 1; /* file is empty: no error */
- if (mtlBufSize < 0) return 0; /* load failed: error */
-
- /* create a new pico parser */
- p = _pico_new_parser( mtlBuffer, mtlBufSize );
- if (p == NULL)
- _obj_mtl_error_return;
-
- /* doo teh .mtl parse */
- while( 1 )
- {
- /* get next token in material file */
- if (_pico_parse( p,1 ) == NULL)
- break;
-#if 1
-
- /* skip empty lines */
- if (p->token == NULL || !strlen( p->token ))
- continue;
-
- /* skip comment lines */
- if (p->token[0] == '#')
- {
- _pico_parse_skip_rest( p );
- continue;
- }
- /* new material */
- if (!_pico_stricmp(p->token,"newmtl"))
- {
- picoShader_t *shader;
- char *name;
-
- /* get material name */
- name = _pico_parse( p,0 );
-
- /* validate material name */
- if (name == NULL || !strlen(name))
- {
- _pico_printf( PICO_ERROR,"Missing material name in MTL, line %d.",p->curLine);
- _obj_mtl_error_return;
- }
- /* create a new pico shader */
- shader = PicoNewShader( model );
- if (shader == NULL)
- _obj_mtl_error_return;
-
- /* set shader name */
- PicoSetShaderName( shader,name );
-
- /* assign pointer to current shader */
- curShader = shader;
- }
- /* diffuse map name */
- else if (!_pico_stricmp(p->token,"map_kd"))
- {
- char *mapName;
- picoShader_t *shader;
-
- /* pointer to current shader must be valid */
- if (curShader == NULL)
- _obj_mtl_error_return;
-
- /* get material's diffuse map name */
- mapName = _pico_parse( p,0 );
-
- /* validate map name */
- if (mapName == NULL || !strlen(mapName))
- {
- _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine);
- _obj_mtl_error_return;
- }
- /* create a new pico shader */
- shader = PicoNewShader( model );
- if (shader == NULL)
- _obj_mtl_error_return;
- /* set shader map name */
- PicoSetShaderMapName( shader,mapName );
- }
- /* dissolve factor (pseudo transparency 0..1) */
- /* where 0 means 100% transparent and 1 means opaque */
- else if (!_pico_stricmp(p->token,"d"))
- {
- picoByte_t *diffuse;
- float value;
-
-
- /* get dissolve factor */
- if (!_pico_parse_float( p,&value ))
- _obj_mtl_error_return;
-
- /* set shader transparency */
- PicoSetShaderTransparency( curShader,value );
-
- /* get shader's diffuse color */
- diffuse = PicoGetShaderDiffuseColor( curShader );
-
- /* set diffuse alpha to transparency */
- diffuse[ 3 ] = (picoByte_t)( value * 255.0 );
-
- /* set shader's new diffuse color */
- PicoSetShaderDiffuseColor( curShader,diffuse );
- }
- /* shininess (phong specular component) */
- else if (!_pico_stricmp(p->token,"ns"))
- {
- /* remark:
- * - well, this is some major obj spec fuckup once again. some
- * apps store this in 0..1 range, others use 0..100 range,
- * even others use 0..2048 range, and again others use the
- * range 0..128, some even use 0..1000, 0..200, 400..700,
- * honestly, what's up with the 3d app coders? happens when
- * you smoke too much weed i guess. -sea
- */
- float value;
-
- /* pointer to current shader must be valid */
- if (curShader == NULL)
- _obj_mtl_error_return;
-
- /* get totally screwed up shininess (a random value in fact ;) */
- if (!_pico_parse_float( p,&value ))
- _obj_mtl_error_return;
-
- /* okay, there is no way to set this correctly, so we simply */
- /* try to guess a few ranges (most common ones i have seen) */
-
- /* assume 0..2048 range */
- if (value > 1000)
- value = 128.0 * (value / 2048.0);
- /* assume 0..1000 range */
- else if (value > 200)
- value = 128.0 * (value / 1000.0);
- /* assume 0..200 range */
- else if (value > 100)
- value = 128.0 * (value / 200.0);
- /* assume 0..100 range */
- else if (value > 1)
- value = 128.0 * (value / 100.0);
- /* assume 0..1 range */
- else {
- value *= 128.0;
- }
- /* negative shininess is bad (yes, i have seen it...) */
- if (value < 0.0) value = 0.0;
-
- /* set the pico shininess value in range 0..127 */
- /* geez, .obj is such a mess... */
- PicoSetShaderShininess( curShader,value );
- }
- /* kol0r ambient (wut teh fuk does "ka" stand for?) */
- else if (!_pico_stricmp(p->token,"ka"))
- {
- picoColor_t color;
- picoVec3_t v;
-
- /* pointer to current shader must be valid */
- if (curShader == NULL)
- _obj_mtl_error_return;
-
- /* get color vector */
- if (!_pico_parse_vec( p,v ))
- _obj_mtl_error_return;
-
- /* scale to byte range */
- color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 );
- color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 );
- color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 );
- color[ 3 ] = (picoByte_t)( 255 );
-
- /* set ambient color */
- PicoSetShaderAmbientColor( curShader,color );
- }
- /* kol0r diffuse */
- else if (!_pico_stricmp(p->token,"kd"))
- {
- picoColor_t color;
- picoVec3_t v;
-
- /* pointer to current shader must be valid */
- if (curShader == NULL)
- _obj_mtl_error_return;
-
- /* get color vector */
- if (!_pico_parse_vec( p,v ))
- _obj_mtl_error_return;
-
- /* scale to byte range */
- color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 );
- color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 );
- color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 );
- color[ 3 ] = (picoByte_t)( 255 );
-
- /* set diffuse color */
- PicoSetShaderDiffuseColor( curShader,color );
- }
- /* kol0r specular */
- else if (!_pico_stricmp(p->token,"ks"))
- {
- picoColor_t color;
- picoVec3_t v;
-
- /* pointer to current shader must be valid */
- if (curShader == NULL)
- _obj_mtl_error_return;
-
- /* get color vector */
- if (!_pico_parse_vec( p,v ))
- _obj_mtl_error_return;
-
- /* scale to byte range */
- color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 );
- color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 );
- color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 );
- color[ 3 ] = (picoByte_t)( 255 );
-
- /* set specular color */
- PicoSetShaderSpecularColor( curShader,color );
- }
-#endif
- /* skip rest of line */
- _pico_parse_skip_rest( p );
- }
-
- /* free parser, file buffer, and file name */
- _pico_free_parser( p );
- _pico_free_file( mtlBuffer );
- _pico_free( fileName );
-
- /* return with success */
- return 1;
-}
-
-/* _obj_load:
- * loads a wavefront obj model file.
-*/
-static picoModel_t *_obj_load( PM_PARAMS_LOAD )
-{
- TObjVertexData *vertexData = NULL;
- picoModel_t *model;
- picoSurface_t *curSurface = NULL;
- picoParser_t *p;
- int allocated;
- int entries;
- int numVerts = 0;
- int numNormals = 0;
- int numUVs = 0;
- int curVertex = 0;
- int curFace = 0;
-
- int autoGroupNumber = 0;
- char autoGroupNameBuf[64];
-
-#define AUTO_GROUPNAME(namebuf) \
- sprintf(namebuf, "__autogroup_%d", autoGroupNumber++)
-#define NEW_SURFACE(name) \
-{ \
- picoSurface_t *newSurface; \
- /* allocate a pico surface */ \
- newSurface = PicoNewSurface( model ); \
- if (newSurface == NULL) \
- _obj_error_return("Error allocating surface"); \
- /* reset face index for surface */ \
- curFace = 0; \
- /* if we can, assign the previous shader to this surface */ \
- if(curSurface) \
- PicoSetSurfaceShader(newSurface, curSurface->shader); \
- /* set ptr to current surface */ \
- curSurface = newSurface; \
- /* we use triangle meshes */ \
- PicoSetSurfaceType( newSurface,PICO_TRIANGLES ); \
- /* set surface name */ \
- PicoSetSurfaceName( newSurface,name ); \
-}
-
- /* helper */
-#define _obj_error_return(m) \
- { \
- _pico_printf( PICO_ERROR,"%s in OBJ, line %d.",m,p->curLine); \
- _pico_free_parser( p ); \
- FreeObjVertexData( vertexData ); \
- PicoFreeModel( model ); \
- return NULL; \
- }
- /* alllocate a new pico parser */
- p = _pico_new_parser( (const picoByte_t *)buffer,bufSize );
- if (p == NULL) return NULL;
-
- /* create a new pico model */
- model = PicoNewModel();
- if (model == NULL)
- {
- _pico_free_parser( p );
- return NULL;
- }
- /* do model setup */
- PicoSetModelFrameNum( model,frameNum );
- PicoSetModelName( model,fileName );
- PicoSetModelFileName( model,fileName );
-
- /* try loading the materials; we don't handle the result */
-#if 1
- _obj_mtl_load( model );
-#endif
-
- /* parse obj line by line */
- while( 1 )
- {
- /* get first token on line */
- if (_pico_parse_first( p ) == NULL)
- break;
-
- /* skip empty lines */
- if (p->token == NULL || !strlen( p->token ))
- continue;
-
- /* skip comment lines */
- if (p->token[0] == '#')
- {
- _pico_parse_skip_rest( p );
- continue;
- }
- /* vertex */
- if (!_pico_stricmp(p->token,"v"))
- {
- TObjVertexData *data;
- picoVec3_t v;
-
- vertexData = SizeObjVertexData( vertexData,numVerts+1,&entries,&allocated );
- if (vertexData == NULL)
- _obj_error_return("Realloc of vertex data failed (1)");
-
- data = &vertexData[ numVerts++ ];
-
- /* get and copy vertex */
- if (!_pico_parse_vec( p,v ))
- _obj_error_return("Vertex parse error");
-
- _pico_copy_vec( v,data->v );
-
-#ifdef DEBUG_PM_OBJ_EX
- printf("Vertex: x: %f y: %f z: %f\n",v[0],v[1],v[2]);
-#endif
- }
- /* uv coord */
- else if (!_pico_stricmp(p->token,"vt"))
- {
- TObjVertexData *data;
- picoVec2_t coord;
-
- vertexData = SizeObjVertexData( vertexData,numUVs+1,&entries,&allocated );
- if (vertexData == NULL)
- _obj_error_return("Realloc of vertex data failed (2)");
-
- data = &vertexData[ numUVs++ ];
-
- /* get and copy tex coord */
- if (!_pico_parse_vec2( p,coord ))
- _obj_error_return("UV coord parse error");
-
- _pico_copy_vec2( coord,data->vt );
-
-#ifdef DEBUG_PM_OBJ_EX
- printf("TexCoord: u: %f v: %f\n",coord[0],coord[1]);
-#endif
- }
- /* vertex normal */
- else if (!_pico_stricmp(p->token,"vn"))
- {
- TObjVertexData *data;
- picoVec3_t n;
-
- vertexData = SizeObjVertexData( vertexData,numNormals+1,&entries,&allocated );
- if (vertexData == NULL)
- _obj_error_return("Realloc of vertex data failed (3)");
-
- data = &vertexData[ numNormals++ ];
-
- /* get and copy vertex normal */
- if (!_pico_parse_vec( p,n ))
- _obj_error_return("Vertex normal parse error");
-
- _pico_copy_vec( n,data->vn );
-
-#ifdef DEBUG_PM_OBJ_EX
- printf("Normal: x: %f y: %f z: %f\n",n[0],n[1],n[2]);
-#endif
- }
- /* new group (for us this means a new surface) */
- else if (!_pico_stricmp(p->token,"g"))
- {
- char *groupName;
-
- /* get first group name (ignore 2nd,3rd,etc.) */
- groupName = _pico_parse( p,0 );
- if (groupName == NULL || !strlen(groupName))
- {
- /* some obj exporters feel like they don't need to */
- /* supply a group name. so we gotta handle it here */
-#if 1
- strcpy( p->token,"default" );
- groupName = p->token;
-#else
- _obj_error_return("Invalid or missing group name");
-#endif
- }
-
- if(curFace == 0)
- {
- PicoSetSurfaceName( curSurface,groupName );
- }
- else
- {
- NEW_SURFACE(groupName);
- }
-
-#ifdef DEBUG_PM_OBJ_EX
- printf("Group: '%s'\n",groupName);
-#endif
- }
- /* face (oh jesus, hopefully this will do the job right ;) */
- else if (!_pico_stricmp(p->token,"f"))
- {
- /* okay, this is a mess. some 3d apps seem to try being unique, */
- /* hello cinema4d & 3d exploration, feel good today?, and save */
- /* this crap in tons of different formats. gah, those screwed */
- /* coders. tho the wavefront obj standard defines exactly two */
- /* ways of storing face information. so, i really won't support */
- /* such stupid extravaganza here! */
-
- picoVec3_t verts [ 4 ];
- picoVec3_t normals[ 4 ];
- picoVec2_t coords [ 4 ];
-
- int iv [ 4 ], has_v;
- int ivt[ 4 ], has_vt = 0;
- int ivn[ 4 ], has_vn = 0;
- int have_quad = 0;
- int slashcount = 0;
- int doubleslash = 0;
- int i;
-
- if(curSurface == NULL)
- {
- _pico_printf( PICO_ERROR,"No group defined for faces, so creating an autoSurface in OBJ, line %d.",p->curLine);
- AUTO_GROUPNAME(autoGroupNameBuf);
- NEW_SURFACE(autoGroupNameBuf);
- }
-
- /* group defs *must* come before faces */
- if (curSurface == NULL)
- _obj_error_return("No group defined for faces");
-
-#ifdef DEBUG_PM_OBJ_EX
- printf("Face: ");
-#endif
- /* read vertex/uv/normal indices for the first three face */
- /* vertices (cause we only support triangles) into 'i*[]' */
- /* store the actual vertex/uv/normal data in three arrays */
- /* called 'verts','coords' and 'normals'. */
- for (i=0; i<4; i++)
- {
- char *str;
-
- /* get next vertex index string (different */
- /* formats are handled below) */
- str = _pico_parse( p,0 );
- if (str == NULL)
- {
- /* just break for quads */
- if (i == 3) break;
-
- /* error otherwise */
- _obj_error_return("Face parse error");
- }
- /* if this is the fourth index string we're */
- /* parsing we assume that we have a quad */
- if (i == 3)
- have_quad = 1;
-
- /* get slash count once */
- if (i == 0)
- {
- slashcount = _pico_strchcount( str,'/' );
- doubleslash = strstr(str,"//") != NULL;
- }
- /* handle format 'v//vn' */
- if (doubleslash && (slashcount == 2))
- {
- has_v = has_vn = 1;
- sscanf( str,"%d//%d",&iv[ i ],&ivn[ i ] );
- }
- /* handle format 'v/vt/vn' */
- else if (!doubleslash && (slashcount == 2))
- {
- has_v = has_vt = has_vn = 1;
- sscanf( str,"%d/%d/%d",&iv[ i ],&ivt[ i ],&ivn[ i ] );
- }
- /* handle format 'v/vt' (non-standard fuckage) */
- else if (!doubleslash && (slashcount == 1))
- {
- has_v = has_vt = 1;
- sscanf( str,"%d/%d",&iv[ i ],&ivt[ i ] );
- }
- /* else assume face format 'v' */
- /* (must have been invented by some bored granny) */
- else {
- /* get single vertex index */
- has_v = 1;
- iv[ i ] = atoi( str );
-
- /* either invalid face format or out of range */
- if (iv[ i ] == 0)
- _obj_error_return("Invalid face format");
- }
- /* fix useless back references */
- /* todo: check if this works as it is supposed to */
-
- /* assign new indices */
- if (iv [ i ] < 0) iv [ i ] = (numVerts - iv [ i ]);
- if (ivt[ i ] < 0) ivt[ i ] = (numUVs - ivt[ i ]);
- if (ivn[ i ] < 0) ivn[ i ] = (numNormals - ivn[ i ]);
-
- /* validate indices */
- /* - commented out. index range checks will trigger
- if (iv [ i ] < 1) iv [ i ] = 1;
- if (ivt[ i ] < 1) ivt[ i ] = 1;
- if (ivn[ i ] < 1) ivn[ i ] = 1;
- */
- /* set vertex origin */
- if (has_v)
- {
- /* check vertex index range */
- if (iv[ i ] < 1 || iv[ i ] > numVerts)
- _obj_error_return("Vertex index out of range");
-
- /* get vertex data */
- verts[ i ][ 0 ] = vertexData[ iv[ i ] - 1 ].v[ 0 ];
- verts[ i ][ 1 ] = vertexData[ iv[ i ] - 1 ].v[ 1 ];
- verts[ i ][ 2 ] = vertexData[ iv[ i ] - 1 ].v[ 2 ];
- }
- /* set vertex normal */
- if (has_vn)
- {
- /* check normal index range */
- if (ivn[ i ] < 1 || ivn[ i ] > numNormals)
- _obj_error_return("Normal index out of range");
-
- /* get normal data */
- normals[ i ][ 0 ] = vertexData[ ivn[ i ] - 1 ].vn[ 0 ];
- normals[ i ][ 1 ] = vertexData[ ivn[ i ] - 1 ].vn[ 1 ];
- normals[ i ][ 2 ] = vertexData[ ivn[ i ] - 1 ].vn[ 2 ];
- }
- /* set texture coordinate */
- if (has_vt)
- {
- /* check uv index range */
- if (ivt[ i ] < 1 || ivt[ i ] > numUVs)
- _obj_error_return("UV coord index out of range");
-
- /* get uv coord data */
- coords[ i ][ 0 ] = vertexData[ ivt[ i ] - 1 ].vt[ 0 ];
- coords[ i ][ 1 ] = vertexData[ ivt[ i ] - 1 ].vt[ 1 ];
- coords[ i ][ 1 ] = -coords[ i ][ 1 ];
- }
-#ifdef DEBUG_PM_OBJ_EX
- printf("(%4d",iv[ i ]);
- if (has_vt) printf(" %4d",ivt[ i ]);
- if (has_vn) printf(" %4d",ivn[ i ]);
- printf(") ");
-#endif
- }
-#ifdef DEBUG_PM_OBJ_EX
- printf("\n");
-#endif
- /* now that we have extracted all the indices and have */
- /* read the actual data we need to assign all the crap */
- /* to our current pico surface */
- if (has_v)
- {
- int max = 3;
- if (have_quad) max = 4;
-
- /* assign all surface information */
- for (i=0; i<max; i++)
- {
- /*if( has_v )*/ PicoSetSurfaceXYZ ( curSurface, (curVertex + i), verts [ i ] );
- /*if( has_vt )*/ PicoSetSurfaceST ( curSurface,0,(curVertex + i), coords [ i ] );
- /*if( has_vn )*/ PicoSetSurfaceNormal( curSurface, (curVertex + i), normals[ i ] );
- }
- /* add our triangle (A B C) */
- PicoSetSurfaceIndex( curSurface,(curFace * 3 + 2),(picoIndex_t)( curVertex + 0 ) );
- PicoSetSurfaceIndex( curSurface,(curFace * 3 + 1),(picoIndex_t)( curVertex + 1 ) );
- PicoSetSurfaceIndex( curSurface,(curFace * 3 + 0),(picoIndex_t)( curVertex + 2 ) );
- curFace++;
-
- /* if we don't have a simple triangle, but a quad... */
- if (have_quad)
- {
- /* we have to add another triangle (2nd half of quad which is A C D) */
- PicoSetSurfaceIndex( curSurface,(curFace * 3 + 2),(picoIndex_t)( curVertex + 0 ) );
- PicoSetSurfaceIndex( curSurface,(curFace * 3 + 1),(picoIndex_t)( curVertex + 2 ) );
- PicoSetSurfaceIndex( curSurface,(curFace * 3 + 0),(picoIndex_t)( curVertex + 3 ) );
- curFace++;
- }
- /* increase vertex count */
- curVertex += max;
- }
- }
- else if (!_pico_stricmp(p->token,"usemtl"))
- {
- picoShader_t *shader;
- char *name;
-
- /* get material name */
- name = _pico_parse( p,0 );
-
- if(curFace != 0 || curSurface == NULL)
- {
- _pico_printf( PICO_ERROR,"No group defined for usemtl, so creating an autoSurface in OBJ, line %d.",p->curLine);
- AUTO_GROUPNAME(autoGroupNameBuf);
- NEW_SURFACE(autoGroupNameBuf);
- }
-
- /* validate material name */
- if (name == NULL || !strlen(name))
- {
- _pico_printf( PICO_ERROR,"Missing material name in OBJ, line %d.",p->curLine);
- }
- else
- {
- shader = PicoFindShader( model, name, 1 );
- if (shader == NULL)
- {
- _pico_printf( PICO_ERROR,"Undefined material name in OBJ, line %d. Making a default shader.",p->curLine);
-
- /* create a new pico shader */
- shader = PicoNewShader( model );
- if (shader != NULL)
- {
- PicoSetShaderName( shader,name );
- PicoSetShaderMapName( shader,name );
- PicoSetSurfaceShader( curSurface, shader );
- }
- }
- else
- {
- PicoSetSurfaceShader( curSurface, shader );
- }
- }
- }
- /* skip unparsed rest of line and continue */
- _pico_parse_skip_rest( p );
- }
- /* free memory used by temporary vertexdata */
- FreeObjVertexData( vertexData );
-
- /* return allocated pico model */
- return model;
-// return NULL;
-}
-
-/* pico file format module definition */
-const picoModule_t picoModuleOBJ =
-{
- "0.6-b", /* module version string */
- "Wavefront ASCII", /* module display name */
- "seaw0lf", /* author's name */
- "2002 seaw0lf", /* module copyright */
- {
- "obj",NULL,NULL,NULL /* default extensions to use */
- },
- _obj_canload, /* validation routine */
- _obj_load, /* load routine */
- NULL, /* save validation routine */
- NULL /* save routine */
-};