----------------------------------------------------------------------------- */
-
-
-/* marker */
-#define PICOMODEL_C
-
-
-
/* dependencies */
#include "picointernal.h"
sets the ptr to the file load function
*/
-void PicoSetLoadFileFunc( void ( *func )( char*, unsigned char**, int* ) ){
+void PicoSetLoadFileFunc( void ( *func )( const char*, unsigned char**, int* ) ){
if ( func != NULL ) {
_pico_ptr_load_file = func;
}
+picoModel_t *PicoModuleLoadModel( const picoModule_t* pm, const char* fileName, picoByte_t* buffer, int bufSize, int frameNum ){
+ char *modelFileName, *remapFileName;
+
+ /* see whether this module can load the model file or not */
+ if ( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK ) {
+ /* use loader provided by module to read the model data */
+ picoModel_t* model = pm->load( fileName, frameNum, buffer, bufSize );
+ if ( model == NULL ) {
+ _pico_free_file( buffer );
+ return NULL;
+ }
+
+ /* assign pointer to file format module */
+ model->module = pm;
+
+ /* get model file name */
+ modelFileName = PicoGetModelFileName( model );
+
+ /* apply model remappings from <model>.remap */
+ if ( strlen( modelFileName ) ) {
+ /* alloc copy of model file name */
+ remapFileName = _pico_alloc( strlen( modelFileName ) + 20 );
+ if ( remapFileName != NULL ) {
+ /* copy model file name and change extension */
+ strcpy( remapFileName, modelFileName );
+ _pico_setfext( remapFileName, "remap" );
+
+ /* try to remap model; we don't handle the result */
+ PicoRemapModel( model, remapFileName );
+
+ /* free the remap file name string */
+ _pico_free( remapFileName );
+ }
+ }
+
+ return model;
+ }
+
+ return NULL;
+}
+
/*
PicoLoadModel()
the meat and potatoes function
*/
-picoModel_t *PicoLoadModel( char *fileName, int frameNum ){
+picoModel_t *PicoLoadModel( const char *fileName, int frameNum ){
const picoModule_t **modules, *pm;
picoModel_t *model;
picoByte_t *buffer;
int bufSize;
- char *modelFileName, *remapFileName;
/* init */
continue;
}
- /* see whether this module can load the model file or not */
- if ( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK ) {
- /* use loader provided by module to read the model data */
- model = pm->load( fileName, frameNum, buffer, bufSize );
- if ( model == NULL ) {
- _pico_free_file( buffer );
- return NULL;
- }
-
- /* assign pointer to file format module */
- model->module = pm;
-
- /* get model file name */
- modelFileName = PicoGetModelFileName( model );
-
- /* apply model remappings from <model>.remap */
- if ( strlen( modelFileName ) ) {
- /* alloc copy of model file name */
- remapFileName = _pico_alloc( strlen( modelFileName ) + 20 );
- if ( remapFileName != NULL ) {
- /* copy model file name and change extension */
- strcpy( remapFileName, modelFileName );
- _pico_setfext( remapFileName, "remap" );
-
- /* try to remap model; we don't handle the result */
- PicoRemapModel( model, remapFileName );
-
- /* free the remap file name string */
- _pico_free( remapFileName );
- }
- }
-
+ model = PicoModuleLoadModel( pm, fileName, buffer, bufSize, frameNum );
+ if ( model != NULL ) {
/* model was loaded, so break out of loop */
break;
}
return model;
}
+picoModel_t *PicoModuleLoadModelStream( const picoModule_t* module, void* inputStream, PicoInputStreamReadFunc inputStreamRead, size_t streamLength, int frameNum, const char *fileName ){
+ picoModel_t *model;
+ picoByte_t *buffer;
+ int bufSize;
+
+
+ /* init */
+ model = NULL;
+
+ if ( inputStream == NULL ) {
+ _pico_printf( PICO_ERROR, "PicoLoadModel: invalid input stream (inputStream == NULL)" );
+ return NULL;
+ }
+
+ if ( inputStreamRead == NULL ) {
+ _pico_printf( PICO_ERROR, "PicoLoadModel: invalid input stream (inputStreamRead == NULL)" );
+ return NULL;
+ }
+
+ buffer = _pico_alloc( streamLength + 1 );
+
+ bufSize = (int)inputStreamRead( inputStream, buffer, streamLength );
+ buffer[bufSize] = '\0';
+
+ model = PicoModuleLoadModel( module, fileName, buffer, bufSize, frameNum );
+
+ if ( model != 0 ) {
+ _pico_free( buffer );
+ }
+
+ /* return */
+ return model;
+}
/* ----------------------------------------------------------------------------
_pico_free( model->name );
}
+ if ( model->fileName ) {
+ _pico_free( model->fileName );
+ }
+
/* free shaders */
for ( i = 0; i < model->numShaders; i++ )
PicoFreeShader( model->shader[ i ] );
_pico_free( shader );
return NULL;
}
+
/* attach */
model->shader[ model->numShaders - 1 ] = shader;
shader->model = model;
}
+
/* setup default shader colors */
_pico_set_color( shader->ambientColor,0,0,0,0 );
_pico_set_color( shader->diffuseColor,255,255,255,1 );
/* free bits */
_pico_free( surface->xyz );
_pico_free( surface->normal );
+ _pico_free( surface->smoothingGroup );
_pico_free( surface->index );
_pico_free( surface->faceNormal );
+ if ( surface->name ) {
+ _pico_free( surface->name );
+ }
+
/* free arrays */
for ( i = 0; i < surface->numSTArrays; i++ )
_pico_free( surface->st[ i ] );
if ( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) ) {
return 0;
}
+ if ( !_pico_realloc( (void *) &surface->smoothingGroup, surface->numVertexes * sizeof( *surface->smoothingGroup ), surface->maxVertexes * sizeof( *surface->smoothingGroup ) ) ) {
+ return 0;
+ }
for ( i = 0; i < surface->numSTArrays; i++ )
if ( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) ) {
return 0;
PicoSet*() Setter Functions
----------------------------------------------------------------------------*/
-void PicoSetModelName( picoModel_t *model, char *name ){
+void PicoSetModelName( picoModel_t *model, const char *name ){
if ( model == NULL || name == NULL ) {
return;
}
_pico_free( model->name );
}
- model->name = _pico_clone_alloc( name,-1 );
+ model->name = _pico_clone_alloc( name );
}
-void PicoSetModelFileName( picoModel_t *model, char *fileName ){
+void PicoSetModelFileName( picoModel_t *model, const char *fileName ){
if ( model == NULL || fileName == NULL ) {
return;
}
_pico_free( model->fileName );
}
- model->fileName = _pico_clone_alloc( fileName,-1 );
+ model->fileName = _pico_clone_alloc( fileName );
}
_pico_free( shader->name );
}
- shader->name = _pico_clone_alloc( name,-1 );
+ shader->name = _pico_clone_alloc( name );
}
_pico_free( shader->mapName );
}
- shader->mapName = _pico_clone_alloc( mapName,-1 );
+ shader->mapName = _pico_clone_alloc( mapName );
}
-void PicoSetSurfaceName( picoSurface_t *surface, char *name ){
+void PicoSetSurfaceName( picoSurface_t *surface, const char *name ){
if ( surface == NULL || name == NULL ) {
return;
}
_pico_free( surface->name );
}
- surface->name = _pico_clone_alloc( name,-1 );
+ surface->name = _pico_clone_alloc( name );
}
}
+void PicoSetSurfaceSmoothingGroup( picoSurface_t *surface, int num, picoIndex_t smoothingGroup ){
+ if ( num < 0 ) {
+ return;
+ }
+ if ( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) {
+ return;
+ }
+ surface->smoothingGroup[ num ] = smoothingGroup;
+}
+
+
void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ){
if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) {
return;
return surface->faceNormal[ num ];
}
+picoIndex_t PicoGetSurfaceSmoothingGroup( picoSurface_t *surface, int num ){
+ if ( surface == NULL || num < 0 || num > surface->numVertexes ) {
+ return -1;
+ }
+ return surface->smoothingGroup[ num ];
+}
+
int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ){
if ( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) {
/* hashtable code for faster vertex lookups */
//#define HASHTABLE_SIZE 32768 // 2048 /* power of 2, use & */
-#define HASHTABLE_SIZE 7919 // 32749 // 2039 /* prime, use % */
+const int HASHTABLE_SIZE = 7919; // 32749 // 2039 /* prime, use % */
int PicoGetHashTableSize( void ){
return HASHTABLE_SIZE;
fixme: needs non-naive algorithm
*/
-int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color ){
+int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color, picoIndex_t smoothingGroup ){
int i, j;
continue;
}
+ /* check normal */
+ if ( surface->smoothingGroup[ i ] != smoothingGroup ) {
+ continue;
+ }
+
/* check st */
if ( numSTs > 0 && st != NULL ) {
for ( j = 0; j < numSTs; j++ )
-/*
- PicoFixSurfaceNormals()
- fixes broken normals (certain formats bork normals)
- */
-#define MAX_NORMAL_VOTES 128
-#define EQUAL_NORMAL_EPSILON 0.01
-#define BAD_NORMAL_EPSILON 0.5
+typedef struct _IndexArray IndexArray;
+struct _IndexArray
+{
+ picoIndex_t* data;
+ picoIndex_t* last;
+};
-void PicoFixSurfaceNormals( picoSurface_t *surface ){
- int i, j, k, a, b, c, numVotes, faceIndex;
- picoVec3_t votes[ MAX_NORMAL_VOTES ];
- picoVec3_t *normals, diff;
- picoVec4_t plane;
+void indexarray_push_back( IndexArray* self, picoIndex_t value ){
+ *self->last++ = value;
+}
+size_t indexarray_size( IndexArray* self ){
+ return self->last - self->data;
+}
- /* dummy check */
- if ( surface == NULL || surface->numVertexes == 0 ) {
- return;
- }
+void indexarray_reserve( IndexArray* self, size_t size ){
+ self->data = self->last = _pico_calloc( size, sizeof( picoIndex_t ) );
+}
- /* fixme: handle other surface types */
- if ( surface->type != PICO_TRIANGLES ) {
- return;
- }
+void indexarray_clear( IndexArray* self ){
+ _pico_free( self->data );
+}
- /* allocate normal storage */
- normals = _pico_alloc( surface->numVertexes * sizeof( *normals ) );
- if ( normals == NULL ) {
- _pico_printf( PICO_ERROR, "PicoFixSurfaceNormals: Unable to allocate memory for temporary normal storage" );
- return;
- }
+typedef struct _BinaryTreeNode BinaryTreeNode;
+struct _BinaryTreeNode
+{
+ picoIndex_t left;
+ picoIndex_t right;
+};
- /* zero it out */
- memset( normals, 0, surface->numVertexes * sizeof( *normals ) );
+typedef struct _BinaryTree BinaryTree;
+struct _BinaryTree
+{
+ BinaryTreeNode* data;
+ BinaryTreeNode* last;
+};
- /* walk vertex list */
- for ( i = 0; i < surface->numVertexes; i++ )
- {
- /* zero out votes */
- numVotes = 0;
+void binarytree_extend( BinaryTree* self ){
+ self->last->left = 0;
+ self->last->right = 0;
+ ++self->last;
+}
- /* find all the triangles that reference this vertex */
- for ( j = 0, faceIndex = 0; j < surface->numIndexes; j += 3, faceIndex++ )
- {
- /* get triangle */
- a = surface->index[ j ];
- b = surface->index[ j + 1 ];
- c = surface->index[ j + 2 ];
+size_t binarytree_size( BinaryTree* self ){
+ return self->last - self->data;
+}
+
+void binarytree_reserve( BinaryTree* self, size_t size ){
+ self->data = self->last = _pico_calloc( size, sizeof( BinaryTreeNode ) );
+}
- /* ignore degenerate triangles */
- if ( a == b || b == c || c == a ) {
+void binarytree_clear( BinaryTree* self ){
+ _pico_free( self->data );
+}
+
+typedef int ( *LessFunc )( void*, picoIndex_t, picoIndex_t );
+
+typedef struct _UniqueIndices UniqueIndices;
+struct _UniqueIndices
+{
+ BinaryTree tree;
+ IndexArray indices;
+ LessFunc lessFunc;
+ void* lessData;
+};
+
+size_t UniqueIndices_size( UniqueIndices* self ){
+ return binarytree_size( &self->tree );
+}
+
+void UniqueIndices_reserve( UniqueIndices* self, size_t size ){
+ binarytree_reserve( &self->tree, size );
+ indexarray_reserve( &self->indices, size );
+}
+
+void UniqueIndices_init( UniqueIndices* self, LessFunc lessFunc, void* lessData ){
+ self->lessFunc = lessFunc;
+ self->lessData = lessData;
+}
+
+void UniqueIndices_destroy( UniqueIndices* self ){
+ binarytree_clear( &self->tree );
+ indexarray_clear( &self->indices );
+}
+
+
+picoIndex_t UniqueIndices_find_or_insert( UniqueIndices* self, picoIndex_t value ){
+ picoIndex_t index = 0;
+
+ for (;; )
+ {
+ if ( self->lessFunc( self->lessData, value, self->indices.data[index] ) ) {
+ BinaryTreeNode* node = self->tree.data + index;
+ if ( node->left != 0 ) {
+ index = node->left;
continue;
}
-
- /* ignore indexes out of range */
- if ( a < 0 || a >= surface->numVertexes ||
- b < 0 || b >= surface->numVertexes ||
- c < 0 || c >= surface->numVertexes ) {
+ else
+ {
+ node->left = (picoIndex_t)binarytree_size( &self->tree );
+ binarytree_extend( &self->tree );
+ indexarray_push_back( &self->indices, value );
+ return node->left;
+ }
+ }
+ if ( self->lessFunc( self->lessData, self->indices.data[index], value ) ) {
+ BinaryTreeNode* node = self->tree.data + index;
+ if ( node->right != 0 ) {
+ index = node->right;
continue;
}
+ else
+ {
+ node->right = (picoIndex_t)binarytree_size( &self->tree );
+ binarytree_extend( &self->tree );
+ indexarray_push_back( &self->indices, value );
+ return node->right;
+ }
+ }
- /* test triangle */
- if ( a == i || b == i || c == i ) {
- /* if this surface has face normals */
- if ( surface->numFaceNormals && faceIndex < surface->numFaceNormals ) {
- _pico_copy_vec( surface->faceNormal[ faceIndex ], plane );
- if ( plane[ 0 ] == 0.f && plane[ 1 ] == 0.f && plane[ 2 ] == 0.f ) {
- /* if null normal, make plane from the 3 points */
- if ( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) {
- continue;
- }
- }
- }
- /* make a plane from the 3 points */
- else if ( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) {
- continue;
- }
+ return index;
+ }
+}
- /* see if this normal has already been voted */
- for ( k = 0; k < numVotes; k++ )
- {
- _pico_subtract_vec( plane, votes[ k ], diff );
- if ( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON &&
- fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON &&
- fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON ) {
- break;
- }
- }
+picoIndex_t UniqueIndices_insert( UniqueIndices* self, picoIndex_t value ){
+ if ( self->tree.data == self->tree.last ) {
+ binarytree_extend( &self->tree );
+ indexarray_push_back( &self->indices, value );
+ return 0;
+ }
+ else
+ {
+ return UniqueIndices_find_or_insert( self, value );
+ }
+}
- /* add a new vote? */
- if ( k == numVotes && numVotes < MAX_NORMAL_VOTES ) {
- _pico_copy_vec( plane, votes[ numVotes ] );
- numVotes++;
- }
+typedef struct picoSmoothVertices_s picoSmoothVertices_t;
+struct picoSmoothVertices_s
+{
+ picoVec3_t* xyz;
+ picoIndex_t* smoothingGroups;
+};
+
+int lessSmoothVertex( void* data, picoIndex_t first, picoIndex_t second ){
+ picoSmoothVertices_t* smoothVertices = data;
+
+ if ( smoothVertices->xyz[first][0] != smoothVertices->xyz[second][0] ) {
+ return smoothVertices->xyz[first][0] < smoothVertices->xyz[second][0];
+ }
+ if ( smoothVertices->xyz[first][1] != smoothVertices->xyz[second][1] ) {
+ return smoothVertices->xyz[first][1] < smoothVertices->xyz[second][1];
+ }
+ if ( smoothVertices->xyz[first][2] != smoothVertices->xyz[second][2] ) {
+ return smoothVertices->xyz[first][2] < smoothVertices->xyz[second][2];
+ }
+ if ( smoothVertices->smoothingGroups[first] != smoothVertices->smoothingGroups[second] ) {
+ return smoothVertices->smoothingGroups[first] < smoothVertices->smoothingGroups[second];
+ }
+ return 0;
+}
+
+void _pico_vertices_combine_shared_normals( picoVec3_t* xyz, picoIndex_t* smoothingGroups, picoVec3_t* normals, picoIndex_t numVertices ){
+ UniqueIndices vertices;
+ IndexArray indices;
+ picoSmoothVertices_t smoothVertices = { xyz, smoothingGroups };
+ UniqueIndices_init( &vertices, lessSmoothVertex, &smoothVertices );
+ UniqueIndices_reserve( &vertices, numVertices );
+ indexarray_reserve( &indices, numVertices );
+
+
+ {
+ picoIndex_t i = 0;
+ for (; i < numVertices; ++i )
+ {
+ size_t size = UniqueIndices_size( &vertices );
+ picoIndex_t index = UniqueIndices_insert( &vertices, i );
+ if ( (size_t)index != size ) {
+ float* normal = normals[vertices.indices.data[index]];
+ _pico_add_vec( normal, normals[i], normal );
}
+ indexarray_push_back( &indices, index );
}
+ }
- /* tally votes */
- if ( numVotes > 0 ) {
- /* create average normal */
- _pico_zero_vec( normals[ i ] );
- for ( k = 0; k < numVotes; k++ )
- _pico_add_vec( normals[ i ], votes[ k ], normals[ i ] );
-
- /* normalize it */
- if ( _pico_normalize_vec( normals[ i ] ) ) {
- /* test against actual normal */
- if ( fabs( _pico_dot_vec( normals[ i ], surface->normal[ i ] ) - 1 ) > BAD_NORMAL_EPSILON ) {
- //% printf( "Normal %8d: (%f %f %f) -> (%f %f %f)\n", i,
- //% surface->normal[ i ][ 0 ], surface->normal[ i ][ 1 ], surface->normal[ i ][ 2 ],
- //% normals[ i ][ 0 ], normals[ i ][ 1 ], normals[ i ][ 2 ] );
- _pico_copy_vec( normals[ i ], surface->normal[ i ] );
+ {
+ picoIndex_t maxIndex = 0;
+ picoIndex_t* i = indices.data;
+ for (; i != indices.last; ++i )
+ {
+ if ( *i <= maxIndex ) {
+ _pico_copy_vec( normals[vertices.indices.data[*i]], normals[i - indices.data] );
+ }
+ else
+ {
+ maxIndex = *i;
+ }
+ }
+ }
+
+ UniqueIndices_destroy( &vertices );
+ indexarray_clear( &indices );
+}
+
+typedef picoVec3_t* picoNormalIter_t;
+typedef picoIndex_t* picoIndexIter_t;
+
+#define THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL 1
+
+void _pico_triangles_generate_weighted_normals( picoIndexIter_t first, picoIndexIter_t end, picoVec3_t* xyz, picoVec3_t* normals ){
+ for (; first != end; first += 3 )
+ {
+#if ( THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL )
+ picoVec3_t weightedNormal;
+ {
+ float* a = xyz[*( first + 0 )];
+ float* b = xyz[*( first + 1 )];
+ float* c = xyz[*( first + 2 )];
+ picoVec3_t ba, ca;
+ _pico_subtract_vec( b, a, ba );
+ _pico_subtract_vec( c, a, ca );
+ _pico_cross_vec( ca, ba, weightedNormal );
+ }
+#endif
+ {
+ int j = 0;
+ for (; j < 3; ++j )
+ {
+ float* normal = normals[*( first + j )];
+#if ( !THE_CROSSPRODUCTS_OF_ANY_PAIR_OF_EDGES_OF_A_GIVEN_TRIANGLE_ARE_EQUAL )
+ picoVec3_t weightedNormal;
+ {
+ float* a = xyz[*( first + ( ( j + 0 ) % 3 ) )];
+ float* b = xyz[*( first + ( ( j + 1 ) % 3 ) )];
+ float* c = xyz[*( first + ( ( j + 2 ) % 3 ) )];
+ picoVec3_t ba, ca;
+ _pico_subtract_vec( b, a, ba );
+ _pico_subtract_vec( c, a, ca );
+ _pico_cross_vec( ca, ba, weightedNormal );
}
+#endif
+ _pico_add_vec( weightedNormal, normal, normal );
}
}
}
+}
- /* free normal storage */
- _pico_free( normals );
+void _pico_normals_zero( picoNormalIter_t first, picoNormalIter_t last ){
+ for (; first != last; ++first )
+ {
+ _pico_zero_vec( *first );
+ }
+}
+
+void _pico_normals_normalize( picoNormalIter_t first, picoNormalIter_t last ){
+ for (; first != last; ++first )
+ {
+ _pico_normalize_vec( *first );
+ }
}
+double _pico_length_vec( picoVec3_t vec ){
+ return sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] );
+}
+#define NORMAL_UNIT_LENGTH_EPSILON 0.01
+#define FLOAT_EQUAL_EPSILON( f, other, epsilon ) ( fabs( f - other ) < epsilon )
+
+int _pico_normal_is_unit_length( picoVec3_t normal ){
+ return FLOAT_EQUAL_EPSILON( _pico_length_vec( normal ), 1.0, NORMAL_UNIT_LENGTH_EPSILON );
+}
+
+int _pico_normal_within_tolerance( picoVec3_t normal, picoVec3_t other ){
+ return _pico_dot_vec( normal, other ) > 0.0f;
+}
+
+
+void _pico_normals_assign_generated_normals( picoNormalIter_t first, picoNormalIter_t last, picoNormalIter_t generated ){
+ for (; first != last; ++first, ++generated )
+ {
+ if ( !_pico_normal_is_unit_length( *first ) || !_pico_normal_within_tolerance( *first, *generated ) ) {
+ _pico_copy_vec( *generated, *first );
+ }
+ }
+}
+
+void PicoFixSurfaceNormals( picoSurface_t* surface ){
+ picoVec3_t* normals = (picoVec3_t*)_pico_calloc( surface->numVertexes, sizeof( picoVec3_t ) );
+
+ _pico_normals_zero( normals, normals + surface->numVertexes );
+
+ _pico_triangles_generate_weighted_normals( surface->index, surface->index + surface->numIndexes, surface->xyz, normals );
+ _pico_vertices_combine_shared_normals( surface->xyz, surface->smoothingGroup, normals, surface->numVertexes );
+
+ _pico_normals_normalize( normals, normals + surface->numVertexes );
+
+ _pico_normals_assign_generated_normals( surface->normal, surface->normal + surface->numVertexes, normals );
+
+ _pico_free( normals );
+}
/*
if ( !strlen( p->token ) ) {
continue;
}
- materialName = _pico_clone_alloc( p->token,-1 );
+ materialName = _pico_clone_alloc( p->token );
if ( materialName == NULL ) {
_prm_error_return;
}
}
/* temporary copy of material name */
- tempMaterialName = _pico_clone_alloc( p->token,-1 );
+ tempMaterialName = _pico_clone_alloc( p->token );
if ( tempMaterialName == NULL ) {
_prm_error_return;
}
color[ 0 ] = (picoByte_t)v[ 0 ];
color[ 1 ] = (picoByte_t)v[ 1 ];
color[ 2 ] = (picoByte_t)v[ 2 ];
- color[ 3 ] = 1;
/* set new ambient color */
PicoSetShaderAmbientColor( shader,color );
color[ 0 ] = (picoByte_t)v[ 0 ];
color[ 1 ] = (picoByte_t)v[ 1 ];
color[ 2 ] = (picoByte_t)v[ 2 ];
- color[ 3 ] = 1;
/* set new ambient color */
PicoSetShaderDiffuseColor( shader,color );
color[ 0 ] = (picoByte_t)v[ 0 ];
color[ 1 ] = (picoByte_t)v[ 1 ];
color[ 2 ] = (picoByte_t)v[ 2 ];
- color[ 3 ] = 1;
/* set new ambient color */
PicoSetShaderSpecularColor( shader,color );
void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals,
int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors,
- picoShader_t* shader ){
+ picoShader_t* shader, const char *name, picoIndex_t* smoothingGroup ){
int i,j;
int vertDataIndex;
picoSurface_t* workSurface = NULL;
for ( i = 0 ; i < model->numSurfaces ; i++ )
{
workSurface = model->surface[i];
- if ( workSurface->shader == shader ) {
- break;
+ if ( !name || !strcmp( workSurface->name, name ) ) {
+ if ( workSurface->shader == shader ) {
+ break;
+ }
}
}
/* do surface setup */
PicoSetSurfaceType( workSurface, PICO_TRIANGLES );
- PicoSetSurfaceName( workSurface, shader->name );
+ PicoSetSurfaceName( workSurface, name ? name : shader->name );
PicoSetSurfaceShader( workSurface, shader );
}
int newVertIndex = PicoGetSurfaceNumIndexes( workSurface );
/* get the index of the vertex that we're going to store at newVertIndex */
- vertDataIndex = PicoFindSurfaceVertexNum( workSurface, *xyz[i], *normals[i], numSTs, st[i], numColors, colors[i] );
+ vertDataIndex = PicoFindSurfaceVertexNum( workSurface, *xyz[i], *normals[i], numSTs, st[i], numColors, colors[i], smoothingGroup[i] );
/* the vertex wasn't found, so create a new vertex in the pool from the data we have */
if ( vertDataIndex == -1 ) {
{
PicoSetSurfaceST( workSurface, j, vertDataIndex, st[i][j] );
}
+
+ PicoSetSurfaceSmoothingGroup( workSurface, vertDataIndex, smoothingGroup[i] );
}
/* add this vertex to the triangle */