char *sgetS0( unsigned char **bp ) { char *s; unsigned char *buf = *bp; size_t len; if ( flen == FLEN_ERROR ) return NULL; len = strlen( buf ) + 1; if ( len == 1 ) { flen += 2; *bp += 2; return NULL; } len += len & 1; s = _pico_alloc( len ); if ( !s ) { flen = FLEN_ERROR; return NULL; } memcpy( s, buf, len ); flen += len; *bp += len; return s; }
/** * @brief creates a new pico surface */ picoSurface_t *PicoNewSurface (picoModel_t *model) { /* allocate and clear */ picoSurface_t *surface = _pico_alloc(sizeof(*surface)); if (surface == NULL) return NULL; /* attach it to the model */ if (model != NULL) { char surfaceName[64]; /* adjust model */ if (!PicoAdjustModel(model, 0, model->numSurfaces + 1)) { _pico_free(surface); return NULL; } /* attach */ model->surface[model->numSurfaces - 1] = surface; surface->model = model; /* set default name */ sprintf(surfaceName, "Unnamed_%d", model->numSurfaces); PicoSetSurfaceName(surface, surfaceName); } /* return */ return surface; }
/** * @brief creates a new pico shader and returns its index. -sea */ picoShader_t *PicoNewShader (picoModel_t *model) { picoShader_t *shader; /* allocate and clear */ shader = _pico_alloc(sizeof(*shader)); if (shader == NULL) return NULL; /* attach it to the model */ if (model != NULL) { /* adjust model */ if (!PicoAdjustModel(model, model->numShaders + 1, 0)) { _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); _pico_set_color(shader->specularColor, 0, 0, 0, 0); /* no need to do this, but i do it anyway */ shader->transparency = 0; shader->shininess = 0; /* return the newly created shader */ return shader; }
picoModel_t *PicoModuleLoadModelStream (const picoModule_t* module, const char *fileName, void* inputStream, PicoInputStreamReadFunc inputStreamRead, size_t streamLength, int frameNum) { 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; }
picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable (picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index) { unsigned int hash; picoVertexCombinationHash_t *vertexCombinationHash; /* dumy check */ if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL) return NULL; vertexCombinationHash = _pico_alloc(sizeof(picoVertexCombinationHash_t)); if (!vertexCombinationHash) return NULL; hash = PicoVertexCoordGenerateHash(xyz); _pico_copy_vec(xyz, vertexCombinationHash->vcd.xyz); _pico_copy_vec(normal, vertexCombinationHash->vcd.normal); _pico_copy_vec2(st, vertexCombinationHash->vcd.st); _pico_copy_color(color, vertexCombinationHash->vcd.color); vertexCombinationHash->index = index; vertexCombinationHash->data = NULL; vertexCombinationHash->next = hashTable[hash]; hashTable[hash] = vertexCombinationHash; return vertexCombinationHash; }
int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist, lwSurface **surf, int *nsurfs ){ lwSurface **s, *st; int i, index; if ( tlist->count == 0 ) { return 1; } s = _pico_calloc( tlist->count, sizeof( lwSurface * ) ); if ( !s ) { return 0; } for ( i = 0; i < tlist->count; i++ ) { st = *surf; while ( st ) { if ( !strcmp( st->name, tlist->tag[ i ] ) ) { s[ i ] = st; break; } st = st->next; } } for ( i = 0; i < polygon->count; i++ ) { index = ( int ) ( (size_t)polygon->pol[ i ].surf ); if ( index < 0 || index > tlist->count ) { return 0; } if ( !s[ index ] ) { s[ index ] = lwDefaultSurface(); if ( !s[ index ] ) { return 0; } s[ index ]->name = _pico_alloc( strlen( tlist->tag[ index ] ) + 1 ); if ( !s[ index ]->name ) { return 0; } strcpy( s[ index ]->name, tlist->tag[ index ] ); lwListAdd( (void **) surf, s[ index ] ); *nsurfs = *nsurfs + 1; } polygon->pol[ i ].surf = s[ index ]; } _pico_free( s ); return 1; }
char *getS0( picoMemStream_t *fp ) { char *s; size_t i, len, pos; int c; if ( flen == FLEN_ERROR ) return NULL; pos = _pico_memstream_tell( fp ); for ( i = 1; ; i++ ) { c = _pico_memstream_getc( fp ); if ( c <= 0 ) break; } if ( c < 0 ) { flen = FLEN_ERROR; return NULL; } if ( i == 1 ) { if ( _pico_memstream_seek( fp, pos + 2, PICO_SEEK_SET )) flen = FLEN_ERROR; else flen += 2; return NULL; } len = i + ( i & 1 ); s = _pico_alloc( len ); if ( !s ) { flen = FLEN_ERROR; return NULL; } if ( _pico_memstream_seek( fp, pos, PICO_SEEK_SET )) { flen = FLEN_ERROR; return NULL; } if ( 1 != _pico_memstream_read( fp, s, len )) { flen = FLEN_ERROR; return NULL; } flen += len; return s; }
/** * @brief creates a new pico model */ picoModel_t *PicoNewModel (void) { picoModel_t *model; /* allocate */ model = _pico_alloc(sizeof(picoModel_t)); if (model == NULL) return NULL; /* model set up */ _pico_zero_bounds(model->mins, model->maxs); /* set initial frame count to 1 -sea */ model->numFrames = 1; /* return ptr to new model */ return model; }
/* _3ds_load: * loads an autodesk 3ds model file. */ static picoModel_t *_3ds_load( PM_PARAMS_LOAD ){ T3dsLoaderPers pers; picoModel_t *model; char basename[128]; /* create a new pico model */ model = PicoNewModel(); if ( model == NULL ) { /* user must have some serious ram problems ;) */ return NULL; } /* get model's base name (eg. jeep from c:\models\jeep.3ds) */ memset( basename,0,sizeof( basename ) ); strncpy( basename,_pico_nopath( fileName ),sizeof( basename ) ); _pico_setfext( basename,"" ); /* initialize persistant vars (formerly static) */ pers.model = model; pers.bufptr = (picoByte_t *)_pico_alloc( bufSize ); memcpy( pers.bufptr, buffer, bufSize ); pers.basename = (char *)basename; pers.maxofs = bufSize; pers.cofs = 0L; /* do model setup */ PicoSetModelFrameNum( model,frameNum ); PicoSetModelName( model,fileName ); PicoSetModelFileName( model,fileName ); /* skip first chunk in file (magic) */ GetChunk( &pers ); /* process chunks */ if ( !DoNextChunk( &pers,pers.maxofs ) ) { /* well, bleh i guess */ PicoFreeModel( model ); return NULL; } /* return allocated pico model */ return model; }
static int add_tvel( float pos[], float vel[], lwEnvelope **elist, int *nenvs ) { lwEnvelope *env; lwKey *key0, *key1; int i; for ( i = 0; i < 3; i++ ) { env = _pico_calloc( 1, sizeof( lwEnvelope )); key0 = _pico_calloc( 1, sizeof( lwKey )); key1 = _pico_calloc( 1, sizeof( lwKey )); if ( !env || !key0 || !key1 ) return 0; key0->next = key1; key0->value = pos[ i ]; key0->time = 0.0f; key1->prev = key0; key1->value = pos[ i ] + vel[ i ] * 30.0f; key1->time = 1.0f; key0->shape = key1->shape = ID_LINE; env->index = *nenvs + i + 1; env->type = 0x0301 + i; env->name = _pico_alloc( 11 ); if ( env->name ) { strcpy( env->name, "Position.X" ); env->name[ 9 ] += i; } env->key = key0; env->nkeys = 2; env->behavior[ 0 ] = BEH_LINEAR; env->behavior[ 1 ] = BEH_LINEAR; lwListAdd( (void *) elist, env ); } *nenvs += 3; return env->index - 2; }
void *getbytes( picoMemStream_t *fp, size_t size ) { void *data; if ( flen == FLEN_ERROR ) return NULL; if ( size < 0 ) { flen = FLEN_ERROR; return NULL; } data = _pico_alloc( size ); if ( !data ) { flen = FLEN_ERROR; return NULL; } if ( 1 != _pico_memstream_read( fp, data, size )) { flen = FLEN_ERROR; _pico_free( data ); return NULL; } flen += size; return data; }
static picoModel_t *_md2_load( PM_PARAMS_LOAD ) { int i, j, dups, dup_index; index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3; index_DUP_LUT_t *p_index_LUT_DUPS; md2Triangle_t *p_md2Triangle; char skinname[ MD2_MAX_SKINNAME ]; md2_t *md2; md2St_t *texCoord; md2Frame_t *frame; md2Triangle_t *triangle; md2XyzNormal_t *vertex; picoByte_t *bb, *bb0; picoModel_t *picoModel; picoSurface_t *picoSurface; picoShader_t *picoShader; picoVec3_t xyz, normal; picoVec2_t st; picoColor_t color; /* set as md2 */ bb0 = bb = (picoByte_t*) _pico_alloc(bufSize); memcpy(bb, buffer, bufSize); md2 = (md2_t*) bb; /* check ident and version */ if( *((const int*) md2->magic) != *((const int*) MD2_MAGIC) || _pico_little_long( md2->version ) != MD2_VERSION ) { /* not an md2 file (todo: set error) */ _pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName ); _pico_free(bb0); return NULL; } // swap md2 md2->version = _pico_little_long( md2->version ); md2->skinWidth = _pico_little_long( md2->skinWidth ); md2->skinHeight = _pico_little_long( md2->skinHeight ); md2->frameSize = _pico_little_long( md2->frameSize ); md2->numSkins = _pico_little_long( md2->numSkins ); md2->numXYZ = _pico_little_long( md2->numXYZ ); md2->numST = _pico_little_long( md2->numST ); md2->numTris = _pico_little_long( md2->numTris ); md2->numGLCmds = _pico_little_long( md2->numGLCmds ); md2->numFrames = _pico_little_long( md2->numFrames ); md2->ofsSkins = _pico_little_long( md2->ofsSkins ); md2->ofsST = _pico_little_long( md2->ofsST ); md2->ofsTris = _pico_little_long( md2->ofsTris ); md2->ofsFrames = _pico_little_long( md2->ofsFrames ); md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds ); md2->ofsEnd = _pico_little_long( md2->ofsEnd ); // do frame check if( md2->numFrames < 1 ) { _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName ); _pico_free(bb0); return NULL; } if( frameNum < 0 || frameNum >= md2->numFrames ) { _pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" ); _pico_free(bb0); return NULL; } // Setup Frame frame = (md2Frame_t *) (bb + md2->ofsFrames + (sizeof(md2Frame_t) * frameNum)); // swap frame scale and translation for( i = 0; i < 3; i++ ) { frame->scale[ i ] = _pico_little_float( frame->scale[ i ] ); frame->translate[ i ] = _pico_little_float( frame->translate[ i ] ); } // swap triangles triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) ); for( i = 0; i < md2->numTris; i++, triangle++ ) { for( j = 0; j < 3; j++ ) { triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] ); triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] ); } } // swap st coords texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) ); for( i = 0; i < md2->numST; i++, texCoord++ ) { texCoord->s = _pico_little_short( texCoord->s ); texCoord->t = _pico_little_short( texCoord->t ); } // set Skin Name strncpy(skinname, (const char *) (bb + md2->ofsSkins), MD2_MAX_SKINNAME ); // Print out md2 values _pico_printf(PICO_VERBOSE,"Skins: %d Verts: %d STs: %d Triangles: %d Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname ); // detox Skin name _pico_setfext( skinname, "" ); _pico_unixify( skinname ); /* create new pico model */ picoModel = PicoNewModel(); if( picoModel == NULL ) { _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); _pico_free(bb0); return NULL; } /* do model setup */ PicoSetModelFrameNum( picoModel, frameNum ); PicoSetModelNumFrames( picoModel, md2->numFrames ); /* sea */ PicoSetModelName( picoModel, fileName ); PicoSetModelFileName( picoModel, fileName ); // allocate new pico surface picoSurface = PicoNewSurface( picoModel ); if( picoSurface == NULL ) { _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); PicoFreeModel( picoModel ); _pico_free(bb0); return NULL; } PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); PicoSetSurfaceName( picoSurface, frame->name ); picoShader = PicoNewShader( picoModel ); if( picoShader == NULL ) { _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); PicoFreeModel( picoModel ); _pico_free(bb0); return NULL; } PicoSetShaderName( picoShader, skinname ); // associate current surface with newly created shader PicoSetSurfaceShader( picoSurface, picoShader ); // Init LUT for Verts p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * md2->numXYZ); for(i=0; i<md2->numXYZ; i++) { p_index_LUT[i].Vert = -1; p_index_LUT[i].ST = -1; p_index_LUT[i].next = NULL; } // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert. dups = 0; for(i=0; i<md2->numTris; i++) { p_md2Triangle = (md2Triangle_t *) ( bb + md2->ofsTris + (sizeof(md2Triangle_t)*i)); for(j=0; j<3; j++) { if (p_index_LUT[p_md2Triangle->index_xyz[j]].ST == -1) // No Main Entry p_index_LUT[p_md2Triangle->index_xyz[j]].ST = p_md2Triangle->index_st[j]; else if (p_md2Triangle->index_st[j] == p_index_LUT[p_md2Triangle->index_xyz[j]].ST ) // Equal to Main Entry continue; else if ( (p_index_LUT[p_md2Triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry { // Add first entry of LL from Main p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); if (p_index_LUT2 == NULL) _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); p_index_LUT[p_md2Triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2; p_index_LUT2->Vert = dups; p_index_LUT2->ST = p_md2Triangle->index_st[j]; p_index_LUT2->next = NULL; p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk dups++; } else // Try to find in LL from Main Entry { p_index_LUT3 = p_index_LUT2 = p_index_LUT[p_md2Triangle->index_xyz[j]].next; while ( (p_index_LUT2 != NULL) && (p_md2Triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL { p_index_LUT3 = p_index_LUT2; p_index_LUT2 = p_index_LUT2->next; } p_index_LUT2 = p_index_LUT3; if ( p_md2Triangle->index_st[j] == p_index_LUT2->ST ) // Found it { p_md2Triangle->index_xyz[j] = p_index_LUT2->Vert + md2->numXYZ; // Make change in Tri hunk continue; } if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL. { // Add the Entry p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); if (p_index_LUT3 == NULL) _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); p_index_LUT2->next = (index_LUT_t *)p_index_LUT3; p_index_LUT3->Vert = p_md2Triangle->index_xyz[j]; p_index_LUT3->ST = p_md2Triangle->index_st[j]; p_index_LUT3->next = NULL; p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk dups++; } } } } // malloc and build array for Dup STs p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups); if (p_index_LUT_DUPS == NULL) _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); dup_index = 0; for(i=0; i<md2->numXYZ; i++) { p_index_LUT2 = p_index_LUT[i].next; while (p_index_LUT2 != NULL) { p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i; p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST; dup_index++; p_index_LUT2 = p_index_LUT2->next; } } // Build Picomodel triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) ); texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) ); vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts) ); for( j = 0; j < md2->numTris; j++, triangle++ ) { PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] ); PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] ); PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] ); } for(i=0; i< md2->numXYZ; i++, vertex++) { /* set vertex origin */ xyz[ 0 ] = vertex->v[0] * frame->scale[0] + frame->translate[0]; xyz[ 1 ] = vertex->v[1] * frame->scale[1] + frame->translate[1]; xyz[ 2 ] = vertex->v[2] * frame->scale[2] + frame->translate[2]; PicoSetSurfaceXYZ( picoSurface, i , xyz ); /* set normal */ normal[ 0 ] = md2_normals[vertex->lightnormalindex][0]; normal[ 1 ] = md2_normals[vertex->lightnormalindex][1]; normal[ 2 ] = md2_normals[vertex->lightnormalindex][2]; PicoSetSurfaceNormal( picoSurface, i , normal ); /* set st coords */ st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)md2->skinWidth)); st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)md2->skinHeight)); PicoSetSurfaceST( picoSurface, 0, i , st ); } if (dups) { for(i=0; i<dups; i++) { j = p_index_LUT_DUPS[i].OldVert; /* set vertex origin */ xyz[ 0 ] = frame->verts[j].v[0] * frame->scale[0] + frame->translate[0]; xyz[ 1 ] = frame->verts[j].v[1] * frame->scale[1] + frame->translate[1]; xyz[ 2 ] = frame->verts[j].v[2] * frame->scale[2] + frame->translate[2]; PicoSetSurfaceXYZ( picoSurface, i + md2->numXYZ , xyz ); /* set normal */ normal[ 0 ] = md2_normals[frame->verts[j].lightnormalindex][0]; normal[ 1 ] = md2_normals[frame->verts[j].lightnormalindex][1]; normal[ 2 ] = md2_normals[frame->verts[j].lightnormalindex][2]; PicoSetSurfaceNormal( picoSurface, i + md2->numXYZ , normal ); /* set st coords */ st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)md2->skinWidth)); st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)md2->skinHeight)); PicoSetSurfaceST( picoSurface, 0, i + md2->numXYZ , st ); } } /* set color */ PicoSetSurfaceColor( picoSurface, 0, 0, color ); // Free up malloc'ed LL entries for(i=0; i<md2->numXYZ; i++) { if(p_index_LUT[i].next != NULL) { p_index_LUT2 = p_index_LUT[i].next; do { p_index_LUT3 = p_index_LUT2->next; _pico_free(p_index_LUT2); p_index_LUT2 = p_index_LUT3; dups--; } while (p_index_LUT2 != NULL); } } if (dups) _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n"); // Free malloc'ed LUTs _pico_free(p_index_LUT); _pico_free(p_index_LUT_DUPS); /* return the new pico model */ _pico_free(bb0); return picoModel; }
/** * @brief adjusts a surface's memory allocations to handle the requested sizes. * will always grow, never shrink */ int PicoAdjustSurface (picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals) { int i; /* dummy check */ if (surface == NULL) return 0; /* bare minimums */ if (numVertexes < 1) numVertexes = 1; if (numSTArrays < 1) numSTArrays = 1; if (numColorArrays < 1) numColorArrays = 1; if (numIndexes < 1) numIndexes = 1; /* additional vertexes? */ while (numVertexes > surface->maxVertexes) { /* fix */ surface->maxVertexes += PICO_GROW_VERTEXES; if (!_pico_realloc((void *) &surface->xyz, surface->numVertexes * sizeof(*surface->xyz), surface->maxVertexes * sizeof(*surface->xyz))) return 0; 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; for (i = 0; i < surface->numColorArrays; i++) if (!_pico_realloc((void*) &surface->color[i], surface->numVertexes * sizeof(*surface->color[i]), surface->maxVertexes * sizeof(*surface->color[i]))) return 0; } /* set vertex count to higher */ if (numVertexes > surface->numVertexes) surface->numVertexes = numVertexes; /* additional st arrays? */ while (numSTArrays > surface->maxSTArrays) { /* fix */ surface->maxSTArrays += PICO_GROW_ARRAYS; if (!_pico_realloc((void*) &surface->st, surface->numSTArrays * sizeof(*surface->st), surface->maxSTArrays * sizeof(*surface->st))) return 0; while (surface->numSTArrays < numSTArrays) { surface->st[surface->numSTArrays] = _pico_alloc(surface->maxVertexes * sizeof(*surface->st[0])); memset(surface->st[surface->numSTArrays], 0, surface->maxVertexes * sizeof(*surface->st[0])); surface->numSTArrays++; } } /* additional color arrays? */ while (numColorArrays > surface->maxColorArrays) { /* fix */ surface->maxColorArrays += PICO_GROW_ARRAYS; if (!_pico_realloc((void*) &surface->color, surface->numColorArrays * sizeof(*surface->color), surface->maxColorArrays * sizeof(*surface->color))) return 0; while (surface->numColorArrays < numColorArrays) { surface->color[surface->numColorArrays] = _pico_alloc(surface->maxVertexes * sizeof(*surface->color[0])); memset(surface->color[surface->numColorArrays], 0, surface->maxVertexes * sizeof(*surface->color[0])); surface->numColorArrays++; } } /* additional indexes? */ while (numIndexes > surface->maxIndexes) { /* fix */ surface->maxIndexes += PICO_GROW_INDEXES; if (!_pico_realloc((void*) &surface->index, surface->numIndexes * sizeof(*surface->index), surface->maxIndexes * sizeof(*surface->index))) return 0; } /* set index count to higher */ if (numIndexes > surface->numIndexes) surface->numIndexes = numIndexes; /* additional face normals? */ while (numFaceNormals > surface->maxFaceNormals) { /* fix */ surface->maxFaceNormals += PICO_GROW_FACES; if (!_pico_realloc((void *) &surface->faceNormal, surface->numFaceNormals * sizeof(*surface->faceNormal), surface->maxFaceNormals * sizeof(*surface->faceNormal))) return 0; } /* set face normal count to higher */ if (numFaceNormals > surface->numFaceNormals) surface->numFaceNormals = numFaceNormals; /* return ok */ return 1; }
static picoModel_t *_md2_load( PM_PARAMS_LOAD ) { int i, j; short tot_numVerts; index_LUT_t *p_index_LUT; md2Triangle_t *p_md2Triangle; char skinname[ MD2_MAX_SKINNAME ]; md2_t *md2; md2St_t *texCoord; md2Frame_t *frame; md2Triangle_t *triangle; md2XyzNormal_t *vertex; picoByte_t *bb; picoModel_t *picoModel; picoSurface_t *picoSurface; picoShader_t *picoShader; picoVec3_t xyz, normal; picoVec2_t st; picoColor_t color; /* set as md2 */ bb = (picoByte_t*) buffer; md2 = (md2_t*) buffer; /* check ident and version */ if( *((int*) md2->magic) != *((int*) MD2_MAGIC) || _pico_little_long( md2->version ) != MD2_VERSION ) { /* not an md2 file (todo: set error) */ _pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName ); return NULL; } // swap md2 md2->version = _pico_little_long( md2->version ); md2->skinWidth = _pico_little_long( md2->skinWidth ); md2->skinHeight = _pico_little_long( md2->skinHeight ); md2->frameSize = _pico_little_long( md2->frameSize ); md2->numSkins = _pico_little_long( md2->numSkins ); md2->numXYZ = _pico_little_long( md2->numXYZ ); md2->numST = _pico_little_long( md2->numST ); md2->numTris = _pico_little_long( md2->numTris ); md2->numGLCmds = _pico_little_long( md2->numGLCmds ); md2->numFrames = _pico_little_long( md2->numFrames ); md2->ofsSkins = _pico_little_long( md2->ofsSkins ); md2->ofsST = _pico_little_long( md2->ofsST ); md2->ofsTris = _pico_little_long( md2->ofsTris ); md2->ofsFrames = _pico_little_long( md2->ofsFrames ); md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds ); md2->ofsEnd = _pico_little_long( md2->ofsEnd ); // do frame check if( md2->numFrames < 1 ) { _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName ); return NULL; } if( frameNum < 0 || frameNum >= md2->numFrames ) { _pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" ); return NULL; } // Setup Frame frame = (md2Frame_t *) (bb + md2->ofsFrames + (sizeof(md2Frame_t) * frameNum)); // swap frame scale and translation for( i = 0; i < 3; i++ ) { frame->scale[ i ] = _pico_little_float( frame->scale[ i ] ); frame->translate[ i ] = _pico_little_float( frame->translate[ i ] ); } // swap triangles triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) ); for( i = 0; i < md2->numTris; i++, triangle++ ) { for( j = 0; j < 3; j++ ) { triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] ); triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] ); } } // swap st coords texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) ); for( i = 0; i < md2->numST; i++, texCoord++ ) { texCoord->s = _pico_little_short( texCoord->s ); texCoord->t = _pico_little_short( texCoord->t ); } // Print out md2 values _pico_printf(PICO_VERBOSE,"Skins: %d Verts: %d STs: %d Triangles: %d Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname ); /* create new pico model */ picoModel = PicoNewModel(); if( picoModel == NULL ) { _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); return NULL; } /* do model setup */ PicoSetModelFrameNum( picoModel, frameNum ); PicoSetModelNumFrames( picoModel, md2->numFrames ); /* sea */ PicoSetModelName( picoModel, fileName ); PicoSetModelFileName( picoModel, fileName ); for (i = 0; i < md2->numSkins; i++) { char *offsetSkin = (char*) (bb + md2->ofsSkins) + i * MD2_MAX_SKINNAME; /* set Skin Name */ strncpy(skinname, offsetSkin, MD2_MAX_SKINNAME); /* detox Skin name */ if (skinname[0] == '.') {/* special case ufoai skinpath */ char path[MD2_MAX_SKINNAME]; char skinnameRelative[MD2_MAX_SKINNAME]; strncpy(path, fileName, MD2_MAX_SKINNAME); strncpy(skinnameRelative, skinname, MD2_MAX_SKINNAME); _pico_unixify(path); for (j = MD2_MAX_SKINNAME; j--;) {/* skip filename */ if (path[j] == '/') break; path[j] = '\0'; } snprintf(skinname, MD2_MAX_SKINNAME, "%s%s", path, &skinnameRelative[1]); } _pico_setfext(skinname, ""); picoShader = PicoNewShader(picoModel); if (picoShader == NULL) { _pico_printf(PICO_ERROR, "Unable to allocate a new model shader"); PicoFreeModel(picoModel); return NULL; } PicoSetShaderName(picoShader, skinname); } // allocate new pico surface picoSurface = PicoNewSurface( picoModel ); if( picoSurface == NULL ) { _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); PicoFreeModel( picoModel ); return NULL; } PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); PicoSetSurfaceName( picoSurface, frame->name ); picoShader = PicoNewShader( picoModel ); if( picoShader == NULL ) { _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); PicoFreeModel( picoModel ); return NULL; } PicoSetShaderName( picoShader, skinname ); // associate current surface with newly created shader PicoSetSurfaceShader( picoSurface, picoShader ); // Init LUT for Verts p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * md2->numXYZ); for(i=0; i<md2->numXYZ; i++) { p_index_LUT[i].Vert = -1; p_index_LUT[i].ST = -1; } /* Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert. */ tot_numVerts = md2->numXYZ; for (i = 0; i < md2->numTris; i++) { p_md2Triangle = (md2Triangle_t *) (bb + md2->ofsTris + (sizeof(md2Triangle_t) * i)); for (j = 0; j < 3; j++) { if (p_index_LUT[p_md2Triangle->index_xyz[j]].ST == -1) /* No Main Entry */ p_index_LUT[p_md2Triangle->index_xyz[j]].ST = p_md2Triangle->index_st[j]; } } /* Build Picomodel */ triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris)); for (j = 0; j < md2->numTris; j++, triangle++) { PicoSetSurfaceIndex(picoSurface, j * 3, triangle->index_xyz[0]); PicoSetSurfaceIndex(picoSurface, j * 3 + 1, triangle->index_xyz[1]); PicoSetSurfaceIndex(picoSurface, j * 3 + 2, triangle->index_xyz[2]); } _pico_set_color(color, 255, 255, 255, 255); texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST)); vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts)); for (i = 0; i < md2->numXYZ; i++, vertex++) { /* set vertex origin */ xyz[0] = vertex->v[0] * frame->scale[0] + frame->translate[0]; xyz[1] = vertex->v[1] * frame->scale[1] + frame->translate[1]; xyz[2] = vertex->v[2] * frame->scale[2] + frame->translate[2]; PicoSetSurfaceXYZ(picoSurface, i, xyz); /* set normal */ normal[0] = md2_normals[vertex->lightnormalindex][0]; normal[1] = md2_normals[vertex->lightnormalindex][1]; normal[2] = md2_normals[vertex->lightnormalindex][2]; PicoSetSurfaceNormal(picoSurface, i, normal); /* set st coords */ st[0] = (float) texCoord[p_index_LUT[i].ST].s / (float) md2->skinWidth; st[1] = (float) texCoord[p_index_LUT[i].ST].t / (float) md2->skinHeight; PicoSetSurfaceST(picoSurface, 0, i, st); /* set color */ PicoSetSurfaceColor(picoSurface, 0, i, color); } /* Free malloc'ed LUTs */ _pico_free(p_index_LUT); /* return the new pico model */ return picoModel; }
/** * @brief This pretty piece of 'alloc ahead' code dynamically * allocates - and reallocates as soon as required - * my vertex data array in even steps. */ 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; }
/* _ms3d_load: * loads a milkshape3d model file. */ static picoModel_t *_ms3d_load( PM_PARAMS_LOAD ){ picoModel_t *model; unsigned char *bufptr, *bufptr0; int shaderRefs[ MS3D_MAX_GROUPS ]; int numGroups; int numMaterials; // unsigned char *ptrToGroups; int numVerts; unsigned char *ptrToVerts; int numTris; unsigned char *ptrToTris; int i,k,m; /* create new pico model */ model = PicoNewModel(); if ( model == NULL ) { return NULL; } /* do model setup */ PicoSetModelFrameNum( model, frameNum ); PicoSetModelName( model, fileName ); PicoSetModelFileName( model, fileName ); bufptr0 = bufptr = (picoByte_t*) _pico_alloc( bufSize ); memcpy( bufptr, buffer, bufSize ); /* skip header */ bufptr += sizeof( TMsHeader ); /* get number of vertices */ bufptr = GetWord( bufptr,&numVerts ); ptrToVerts = bufptr; #ifdef DEBUG_PM_MS3D printf( "NumVertices: %d\n",numVerts ); #endif /* swap verts */ for ( i = 0; i < numVerts; i++ ) { TMsVertex *vertex; vertex = (TMsVertex *)bufptr; bufptr += sizeof( TMsVertex ); vertex->xyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] ); vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] ); vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] ); #ifdef DEBUG_PM_MS3D_EX_ printf( "Vertex: x: %f y: %f z: %f\n", msvd[i]->vertex[0], msvd[i]->vertex[1], msvd[i]->vertex[2] ); #endif } /* get number of triangles */ bufptr = GetWord( bufptr,&numTris ); ptrToTris = bufptr; #ifdef DEBUG_PM_MS3D printf( "NumTriangles: %d\n",numTris ); #endif /* swap tris */ for ( i = 0; i < numTris; i++ ) { TMsTriangle *triangle; triangle = (TMsTriangle *)bufptr; bufptr += sizeof( TMsTriangle ); triangle->flags = _pico_little_short( triangle->flags ); /* run through all tri verts */ for ( k = 0; k < 3; k++ ) { /* swap tex coords */ triangle->s[ k ] = _pico_little_float( triangle->s[ k ] ); triangle->t[ k ] = _pico_little_float( triangle->t[ k ] ); /* swap fields */ triangle->vertexIndices[ k ] = _pico_little_short( triangle->vertexIndices[ k ] ); triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] ); triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] ); triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] ); /* check for out of range indices */ if ( triangle->vertexIndices[ k ] >= numVerts ) { _pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts - 1 ); PicoFreeModel( model ); _pico_free( bufptr0 ); return NULL; /* yuck */ } } } /* get number of groups */ bufptr = GetWord( bufptr,&numGroups ); // ptrToGroups = bufptr; #ifdef DEBUG_PM_MS3D printf( "NumGroups: %d\n",numGroups ); #endif /* run through all groups in model */ for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ ) { picoSurface_t *surface; TMsGroup *group; group = (TMsGroup *)bufptr; bufptr += sizeof( TMsGroup ); /* we ignore hidden groups */ if ( group->flags & MS3D_HIDDEN ) { bufptr += ( group->numTriangles * 2 ) + 1; continue; } /* forced null term of group name */ group->name[ 31 ] = '\0'; /* create new pico surface */ surface = PicoNewSurface( model ); if ( surface == NULL ) { PicoFreeModel( model ); _pico_free( bufptr0 ); return NULL; } /* do surface setup */ PicoSetSurfaceType( surface,PICO_TRIANGLES ); PicoSetSurfaceName( surface,group->name ); /* process triangle indices */ for ( k = 0; k < group->numTriangles; k++ ) { TMsTriangle *triangle; unsigned int triangleIndex; /* get triangle index */ bufptr = GetWord( bufptr,(int *)&triangleIndex ); /* get ptr to triangle data */ triangle = (TMsTriangle *)( ptrToTris + ( sizeof( TMsTriangle ) * triangleIndex ) ); /* run through triangle vertices */ for ( m = 0; m < 3; m++ ) { TMsVertex *vertex; unsigned int vertexIndex; picoVec2_t texCoord; /* get ptr to vertex data */ vertexIndex = triangle->vertexIndices[ m ]; vertex = (TMsVertex *)( ptrToVerts + ( sizeof( TMsVertex ) * vertexIndex ) ); /* store vertex origin */ PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz ); /* store vertex color */ PicoSetSurfaceColor( surface,0,vertexIndex,white ); /* store vertex normal */ PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] ); /* store current face vertex index */ PicoSetSurfaceIndex( surface,( k * 3 + ( 2 - m ) ),(picoIndex_t)vertexIndex ); /* get texture vertex coord */ texCoord[ 0 ] = triangle->s[ m ]; texCoord[ 1 ] = -triangle->t[ m ]; /* flip t */ /* store texture vertex coord */ PicoSetSurfaceST( surface,0,vertexIndex,texCoord ); } } /* store material */ shaderRefs[ i ] = *bufptr++; #ifdef DEBUG_PM_MS3D printf( "Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles ); #endif } /* get number of materials */ bufptr = GetWord( bufptr,&numMaterials ); #ifdef DEBUG_PM_MS3D printf( "NumMaterials: %d\n",numMaterials ); #endif /* run through all materials in model */ for ( i = 0; i < numMaterials; i++ ) { picoShader_t *shader; picoColor_t ambient,diffuse,specular; TMsMaterial *material; int k; material = (TMsMaterial *)bufptr; bufptr += sizeof( TMsMaterial ); /* null term strings */ material->name [ 31 ] = '\0'; material->texture [ 127 ] = '\0'; material->alphamap[ 127 ] = '\0'; /* ltrim strings */ _pico_strltrim( material->name ); _pico_strltrim( material->texture ); _pico_strltrim( material->alphamap ); /* rtrim strings */ _pico_strrtrim( material->name ); _pico_strrtrim( material->texture ); _pico_strrtrim( material->alphamap ); /* create new pico shader */ shader = PicoNewShader( model ); if ( shader == NULL ) { PicoFreeModel( model ); _pico_free( bufptr0 ); return NULL; } /* scale shader colors */ for ( k = 0; k < 4; k++ ) { ambient [ k ] = (picoByte_t) ( material->ambient[ k ] * 255 ); diffuse [ k ] = (picoByte_t) ( material->diffuse[ k ] * 255 ); specular[ k ] = (picoByte_t) ( material->specular[ k ] * 255 ); } /* set shader colors */ PicoSetShaderAmbientColor( shader,ambient ); PicoSetShaderDiffuseColor( shader,diffuse ); PicoSetShaderSpecularColor( shader,specular ); /* set shader transparency */ PicoSetShaderTransparency( shader,material->transparency ); /* set shader shininess (0..127) */ PicoSetShaderShininess( shader,material->shininess ); /* set shader name */ PicoSetShaderName( shader,material->name ); /* set shader texture map name */ PicoSetShaderMapName( shader,material->texture ); #ifdef DEBUG_PM_MS3D printf( "Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap ); #endif } /* assign shaders to surfaces */ for ( i = 0; i < numGroups && i < MS3D_MAX_GROUPS; i++ ) { picoSurface_t *surface; picoShader_t *shader; /* sanity check */ if ( shaderRefs[ i ] >= MS3D_MAX_MATERIALS || shaderRefs[ i ] < 0 ) { continue; } /* get surface */ surface = PicoGetModelSurface( model,i ); if ( surface == NULL ) { continue; } /* get shader */ shader = PicoGetModelShader( model,shaderRefs[ i ] ); if ( shader == NULL ) { continue; } /* assign shader */ PicoSetSurfaceShader( surface,shader ); #ifdef DEBUG_PM_MS3D printf( "Mapped: %d ('%s') to %d (%s)\n", shaderRefs[i],shader->name,i,surface->name ); #endif } /* return allocated pico model */ _pico_free( bufptr0 ); return model; // return NULL; }
/* _ase_load: * loads a 3dsmax ase model file. */ static picoModel_t *_ase_load( PM_PARAMS_LOAD ) { picoModel_t *model; picoParser_t *p; char lastNodeName[ 1024 ]; aseVertex_t* vertices = NULL; aseTexCoord_t* texcoords = NULL; aseColor_t* colors = NULL; aseFace_t* faces = NULL; int numVertices = 0; int numFaces = 0; int numTextureVertices = 0; int numTextureVertexFaces = 0; int numColorVertices = 0; int numColorVertexFaces = 0; int vertexId = 0; int currentVertexFace=0; int currentVertexIndex=0; int counter=0; int submodel=0; aseMaterial_t* materials = NULL; #ifdef DEBUG_PM_ASE clock_t start, finish; double elapsed; start = clock(); #endif /* helper */ #define _ase_error_return(m) \ { \ _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine); \ _pico_free_parser( p ); \ PicoFreeModel( model ); \ return NULL; \ } /* create a new pico parser */ p = _pico_new_parser( (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 ); /* initialize some stuff */ memset( lastNodeName,0,sizeof(lastNodeName) ); /* parse ase model file */ while( 1 ) { /* get first token on line */ if (_pico_parse_first( p ) == NULL) break; /* we just skip empty lines */ if (p->token == NULL || !strlen( p->token )) continue; /* we skip invalid ase statements */ if (p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}') { _pico_parse_skip_rest( p ); continue; } /* remember node name */ if (!_pico_stricmp(p->token,"*node_name")) { /* read node name */ char *ptr = _pico_parse( p,0 ); if (ptr == NULL) _ase_error_return("Node name parse error"); /* remember node name */ strncpy( lastNodeName,ptr,sizeof(lastNodeName) ); } /* model mesh (originally contained within geomobject) */ else if (!_pico_stricmp(p->token,"*mesh")) { /* finish existing surface */ _ase_submit_triangles(model, materials, vertices, texcoords, colors, faces, numFaces,numVertices,submodel++); _pico_free(faces); _pico_free(vertices); _pico_free(texcoords); _pico_free(colors); } else if (!_pico_stricmp(p->token,"*mesh_numvertex")) { if (!_pico_parse_int( p, &numVertices) ) _ase_error_return("Missing MESH_NUMVERTEX value"); vertices = _pico_calloc(numVertices, sizeof(aseVertex_t)); currentVertexIndex=0; } else if (!_pico_stricmp(p->token,"*mesh_numfaces")) { if (!_pico_parse_int( p, &numFaces) ) _ase_error_return("Missing MESH_NUMFACES value"); faces = _pico_calloc(numFaces, sizeof(aseFace_t)); } else if (!_pico_stricmp(p->token,"*mesh_numtvertex")) { if (!_pico_parse_int( p, &numTextureVertices) ) _ase_error_return("Missing MESH_NUMTVERTEX value"); texcoords = _pico_calloc(numTextureVertices, sizeof(aseTexCoord_t)); } else if (!_pico_stricmp(p->token,"*mesh_numtvfaces")) { if (!_pico_parse_int( p, &numTextureVertexFaces) ) _ase_error_return("Missing MESH_NUMTVFACES value"); } else if (!_pico_stricmp(p->token,"*mesh_numcvertex")) { if (!_pico_parse_int( p, &numColorVertices) ) _ase_error_return("Missing MESH_NUMCVERTEX value"); colors = _pico_calloc(numColorVertices, sizeof(aseColor_t)); memset( colors, 255, numColorVertices * sizeof( aseColor_t ) ); /* ydnar: force colors to white initially */ } else if (!_pico_stricmp(p->token,"*mesh_numcvfaces")) { if (!_pico_parse_int( p, &numColorVertexFaces) ) _ase_error_return("Missing MESH_NUMCVFACES value"); } /* mesh material reference. this usually comes at the end of */ /* geomobjects after the mesh blocks. we must assume that the */ /* new mesh was already created so all we can do here is assign */ /* the material reference id (shader index) now. */ else if (!_pico_stricmp(p->token,"*material_ref")) { int mtlId; /* get the material ref (0..n) */ if (!_pico_parse_int( p,&mtlId) ) _ase_error_return("Missing material reference ID"); { int i = 0; /* fix up all of the aseFaceList in the surface to point to the parent material */ /* we've already saved off their subMtl */ for(; i < numFaces; ++i) { faces[i].materialId = mtlId; } } } /* model mesh vertex */ else if (!_pico_stricmp(p->token,"*mesh_vertex")) { int index; if( numVertices == 0 ) _ase_error_return("Vertex parse error"); /* get vertex data (orig: index +y -x +z) */ if (!_pico_parse_int( p,&index )) _ase_error_return("Vertex parse error"); if (!_pico_parse_vec( p,vertices[index].xyz )) _ase_error_return("Vertex parse error"); vertices[index].id = vertexId++; } else if (!_pico_stricmp(p->token,"*mesh_facenormal")) { //Grab the faceindex for the next vertex normals. if( numVertices == 0 ) _ase_error_return("Vertex parse error (facenormals)"); if (!_pico_parse_int( p,¤tVertexFace )) _ase_error_return("Vertex parse error"); if (!_pico_parse_vec( p,faces[currentVertexFace].facenormal )) _ase_error_return("Vertex parse error"); } /* model mesh vertex normal */ else if (!_pico_stricmp(p->token,"*mesh_vertexnormal")) { int index; if( numVertices == 0 ) _ase_error_return("Vertex parse error"); /* get vertex data (orig: index +y -x +z) */ if (!_pico_parse_int( p,&index )) _ase_error_return("Vertex parse error"); //^^ Index is 'wrong' in .ase models. they reference the same vert index with multiple normals.. // I've tried, this is a lost cause. Use the SG's // /* if (!_pico_parse_vec( p,vertices[counter].normal )) _ase_error_return("Vertex parse error"); vertices[counter].faceid=index; counter++; */ } /* model mesh face */ else if (!_pico_stricmp(p->token,"*mesh_normals")) { // counter=0; //part of the above vertex normals fix } /* model mesh face */ else if (!_pico_stricmp(p->token,"*mesh_face")) { picoIndex_t indexes[3]; int index; if( numFaces == 0 ) _ase_error_return("Face parse error"); /* get face index */ if (!_pico_parse_int( p,&index )) _ase_error_return("Face parse error"); /* get 1st vertex index */ _pico_parse( p,0 ); if (!_pico_parse_int( p,&indexes[0] )) _ase_error_return("Face parse error"); /* get 2nd vertex index */ _pico_parse( p,0 ); if (!_pico_parse_int( p,&indexes[1] )) _ase_error_return("Face parse error"); /* get 3rd vertex index */ _pico_parse( p,0 ); if (!_pico_parse_int( p,&indexes[2] )) _ase_error_return("Face parse error"); /* parse to the subMaterial ID */ while ( 1 ) { if (!_pico_parse (p,0)) /* EOL */ { break; } if (!_pico_stricmp (p->token,"*MESH_SMOOTHING" )) { int total=0; char* point; char* start; _pico_parse(p,0); point=p->token; start=point; faces[index].smoothingGroup=0; //Super dodgy comma delimited string parse while (*point<'A') { if (*point<=32 || *point==',') { total=atoi(start); if (total!=0) { faces[index].smoothingGroup+=1<<total; } start=point+1; } point++; } } if (!_pico_stricmp (p->token,"*MESH_MTLID" )) { _pico_parse_int ( p , &faces[index].subMaterialId ); } } faces[index].materialId = 0; faces[index].indices[0] = indexes[2]; faces[index].indices[1] = indexes[1]; faces[index].indices[2] = indexes[0]; } /* model texture vertex */ else if (!_pico_stricmp(p->token,"*mesh_tvert")) { int index; if( numVertices == 0 ) _ase_error_return("Vertex parse error"); /* get uv vertex index */ if (!_pico_parse_int( p,&index )) _ase_error_return("UV vertex parse error"); /* get uv vertex s */ if (!_pico_parse_float( p,&texcoords[index].texcoord[0] )) _ase_error_return("UV vertex parse error"); /* get uv vertex t */ if (!_pico_parse_float( p,&texcoords[index].texcoord[1] )) _ase_error_return("UV vertex parse error"); /* ydnar: invert t */ texcoords[index].texcoord[ 1 ] = 1.0f - texcoords[index].texcoord[ 1 ]; } /* ydnar: model mesh texture face */ else if( !_pico_stricmp( p->token, "*mesh_tface" ) ) { picoIndex_t indexes[3]; int index; if( numFaces == 0 ) _ase_error_return("Texture face parse error"); /* get face index */ if (!_pico_parse_int( p,&index )) _ase_error_return("Texture face parse error"); /* get 1st vertex index */ if (!_pico_parse_int( p,&indexes[0] )) _ase_error_return("Texture face parse error"); /* get 2nd vertex index */ if (!_pico_parse_int( p,&indexes[1] )) _ase_error_return("Texture face parse error"); /* get 3rd vertex index */ if (!_pico_parse_int( p,&indexes[2] )) _ase_error_return("Texture face parse error"); faces[index].indices[3] = indexes[2]; faces[index].indices[4] = indexes[1]; faces[index].indices[5] = indexes[0]; } /* model color vertex */ else if (!_pico_stricmp(p->token,"*mesh_vertcol")) { int index; float colorInput; if( numVertices == 0 ) _ase_error_return("Color Vertex parse error"); /* get color vertex index */ if (!_pico_parse_int( p,&index )) _ase_error_return("Color vertex parse error"); /* get R component */ if (!_pico_parse_float( p,&colorInput )) _ase_error_return("Color vertex parse error"); colors[index].color[0] = (picoByte_t)(colorInput * 255); /* get G component */ if (!_pico_parse_float( p,&colorInput )) _ase_error_return("Color vertex parse error"); colors[index].color[1] = (picoByte_t)(colorInput * 255); /* get B component */ if (!_pico_parse_float( p,&colorInput )) _ase_error_return("Color vertex parse error"); colors[index].color[2] = (picoByte_t)(colorInput * 255); /* leave alpha alone since we don't get any data from the ASE format */ colors[index].color[3] = 255; /* 27 hack, red as alpha */ colors[index].color[3]=colors[index].color[0]; colors[index].color[0]=255; colors[index].color[1]=255; colors[index].color[2]=255; } /* model color face */ else if (!_pico_stricmp(p->token,"*mesh_cface")) { picoIndex_t indexes[3]; int index; if( numFaces == 0 ) _ase_error_return("Face parse error"); /* get face index */ if (!_pico_parse_int( p,&index )) _ase_error_return("Face parse error"); /* get 1st cvertex index */ // _pico_parse( p,0 ); if (!_pico_parse_int( p,&indexes[0] )) _ase_error_return("Face parse error"); /* get 2nd cvertex index */ // _pico_parse( p,0 ); if (!_pico_parse_int( p,&indexes[1] )) _ase_error_return("Face parse error"); /* get 3rd cvertex index */ // _pico_parse( p,0 ); if (!_pico_parse_int( p,&indexes[2] )) _ase_error_return("Face parse error"); faces[index].indices[6] = indexes[2]; faces[index].indices[7] = indexes[1]; faces[index].indices[8] = indexes[0]; } /* model material */ else if( !_pico_stricmp( p->token, "*material" ) ) { aseSubMaterial_t* subMaterial = NULL; picoShader_t *shader; int level = 1, index; char materialName[ 1024 ]; float transValue = 0.0f, shineValue = 1.0f; picoColor_t ambientColor, diffuseColor, specularColor; char *mapname = NULL; int subMtlId, subMaterialLevel = -1; /* get material index */ _pico_parse_int( p,&index ); /* check brace */ if (!_pico_parse_check(p,1,"{")) _ase_error_return("Material missing opening brace"); /* parse material block */ while( 1 ) { /* get next token */ if (_pico_parse(p,1) == NULL) break; if (!strlen(p->token)) continue; /* handle levels */ if (p->token[0] == '{') level++; if (p->token[0] == '}') level--; if (!level) break; if( level == subMaterialLevel ) { /* set material name */ _pico_first_token( materialName ); PicoSetShaderName( shader, materialName); /* set shader's transparency */ PicoSetShaderTransparency( shader,transValue ); /* set shader's ambient color */ PicoSetShaderAmbientColor( shader,ambientColor ); /* set diffuse alpha to transparency */ diffuseColor[3] = (picoByte_t)( transValue * 255.0 ); /* set shader's diffuse color */ PicoSetShaderDiffuseColor( shader,diffuseColor ); /* set shader's specular color */ PicoSetShaderSpecularColor( shader,specularColor ); /* set shader's shininess */ PicoSetShaderShininess( shader,shineValue ); /* set material map name */ PicoSetShaderMapName( shader, mapname ); subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader ); subMaterialLevel = -1; } /* parse submaterial index */ if (!_pico_stricmp(p->token,"*submaterial")) { /* allocate new pico shader */ _pico_parse_int( p , &subMtlId ); shader = PicoNewShader( model ); if (shader == NULL) { PicoFreeModel( model ); return NULL; } subMaterialLevel = level; } /* parse material name */ else if (!_pico_stricmp(p->token,"*material_name")) { char* name = _pico_parse(p,0); if ( name == NULL) _ase_error_return("Missing material name"); strcpy ( materialName , name ); /* skip rest and continue with next token */ _pico_parse_skip_rest( p ); continue; } /* parse material transparency */ else if (!_pico_stricmp(p->token,"*material_transparency")) { /* get transparency value from ase */ if (!_pico_parse_float( p,&transValue )) _ase_error_return("Material transparency parse error"); /* skip rest and continue with next token */ _pico_parse_skip_rest( p ); continue; } /* parse material shininess */ else if (!_pico_stricmp(p->token,"*material_shine")) { /* remark: * - not sure but instead of '*material_shine' i might * need to use '*material_shinestrength' */ /* get shine value from ase */ if (!_pico_parse_float( p,&shineValue )) _ase_error_return("Material shine parse error"); /* scale ase shine range 0..1 to pico range 0..127 */ shineValue *= 128.0; /* skip rest and continue with next token */ _pico_parse_skip_rest( p ); continue; } /* parse ambient material color */ else if (!_pico_stricmp(p->token,"*material_ambient")) { picoVec3_t vec; /* get r,g,b float values from ase */ if (!_pico_parse_vec( p,vec )) _ase_error_return("Material color parse error"); /* setup 0..255 range color values */ ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 ); ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 ); ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 ); ambientColor[ 3 ] = (int)( 255 ); /* skip rest and continue with next token */ _pico_parse_skip_rest( p ); continue; } /* parse diffuse material color */ else if (!_pico_stricmp(p->token,"*material_diffuse")) { picoVec3_t vec; /* get r,g,b float values from ase */ if (!_pico_parse_vec( p,vec )) _ase_error_return("Material color parse error"); /* setup 0..255 range color */ diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 ); diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 ); diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 ); diffuseColor[ 3 ] = (int)( 255 ); /* skip rest and continue with next token */ _pico_parse_skip_rest( p ); continue; } /* parse specular material color */ else if (!_pico_stricmp(p->token,"*material_specular")) { picoVec3_t vec; /* get r,g,b float values from ase */ if (!_pico_parse_vec( p,vec )) _ase_error_return("Material color parse error"); /* setup 0..255 range color */ specularColor[ 0 ] = (int)( vec[ 0 ] * 255 ); specularColor[ 1 ] = (int)( vec[ 1 ] * 255 ); specularColor[ 2 ] = (int)( vec[ 2 ] * 255 ); specularColor[ 3 ] = (int)( 255 ); /* skip rest and continue with next token */ _pico_parse_skip_rest( p ); continue; } /* material diffuse map */ else if (!_pico_stricmp(p->token,"*map_diffuse") ) { int sublevel = 0; /* parse material block */ while( 1 ) { /* get next token */ if (_pico_parse(p,1) == NULL) break; if (!strlen(p->token)) continue; /* handle levels */ if (p->token[0] == '{') sublevel++; if (p->token[0] == '}') sublevel--; if (!sublevel) break; /* parse diffuse map bitmap */ if (!_pico_stricmp(p->token,"*bitmap")) { char* name = _pico_parse(p,0); if (name == NULL) _ase_error_return("Missing material map bitmap name"); mapname = _pico_alloc ( strlen ( name ) + 1 ); strcpy ( mapname, name ); /* skip rest and continue with next token */ _pico_parse_skip_rest( p ); continue; } } } /* end map_diffuse block */ } /* end material block */ if( subMaterial == NULL ) { /* allocate new pico shader */ shader = PicoNewShader( model ); if (shader == NULL) { PicoFreeModel( model ); return NULL; } /* set material name */ PicoSetShaderName( shader,materialName ); /* set shader's transparency */ PicoSetShaderTransparency( shader,transValue ); /* set shader's ambient color */ PicoSetShaderAmbientColor( shader,ambientColor ); /* set diffuse alpha to transparency */ diffuseColor[3] = (picoByte_t)( transValue * 255.0 ); /* set shader's diffuse color */ PicoSetShaderDiffuseColor( shader,diffuseColor ); /* set shader's specular color */ PicoSetShaderSpecularColor( shader,specularColor ); /* set shader's shininess */ PicoSetShaderShininess( shader,shineValue ); /* set material map name */ PicoSetShaderMapName( shader, mapname ); /* extract shadername from bitmap path */ if(mapname != NULL) { char* p = mapname; /* convert to shader-name format */ { /* unix-style path separators */ char* s = mapname; for(; *s != '\0'; ++s) { if(*s == '\\') { *s = '/'; } } } { /* remove extension */ char* last_period = strrchr(p, '.'); if(last_period != NULL) { *last_period = '\0'; } } /* find game root */ for(; *p != '\0'; ++p) { if(_pico_strnicmp(p, "quake", 5) == 0 || _pico_strnicmp(p, "doom", 4) == 0) { break; } } /* root-relative */ for(; *p != '\0'; ++p) { if(*p == '/') { ++p; break; } } /* game-relative */ for(; *p != '\0'; ++p) { if(*p == '/') { ++p; break; } } if(*p != '\0') { /* set material name */ PicoSetShaderName( shader,p ); } } /* this is just a material with 1 submaterial */ subMaterial = _ase_add_submaterial( &materials, index, 0, shader ); } /* ydnar: free mapname */ if( mapname != NULL ) _pico_free( mapname ); } // !_pico_stricmp ( "*material" ) /* skip unparsed rest of line and continue */ _pico_parse_skip_rest( p ); } /* ydnar: finish existing surface */ _ase_submit_triangles(model, materials, vertices, texcoords, colors, faces, numFaces,numVertices,submodel++); _pico_free(faces); _pico_free(vertices); _pico_free(texcoords); _pico_free(colors); #ifdef DEBUG_PM_ASE _ase_print_materials(materials); finish = clock(); elapsed = (double)(finish - start) / CLOCKS_PER_SEC; _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed ); #endif //DEBUG_PM_ASE _ase_free_materials(&materials); _pico_free_parser( p ); /* return allocated pico model */ return model; }
// _fm_canload() static int _fm_canload( PM_PARAMS_CANLOAD ) { fm_t fm; unsigned char *bb, *bb0; int fm_file_pos; bb0 = bb = (picoByte_t*) _pico_alloc(bufSize); memcpy(bb, buffer, bufSize); // Header fm.fm_header_hdr = (fm_chunk_header_t *) bb; fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size; #ifdef FM_VERBOSE_DBG _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident ); #endif if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) ) { #ifdef FM_DBG _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n"); #endif _pico_free(bb0); return PICO_PMV_ERROR_IDENT; } // check fm if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) { #ifdef FM_DBG _pico_printf( PICO_WARNING, "FM Header Version incorrect\n"); #endif _pico_free(bb0); return PICO_PMV_ERROR_VERSION; } // Skin fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size; #ifdef FM_VERBOSE_DBG _pico_printf( PICO_VERBOSE, "SKIN: %s\n", (unsigned char *) fm.fm_skin_hdr->ident ); #endif if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) ) { #ifdef FM_DBG _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n"); #endif _pico_free(bb0); return PICO_PMV_ERROR_IDENT; } // check fm if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) { #ifdef FM_DBG _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n"); #endif _pico_free(bb0); return PICO_PMV_ERROR_VERSION; } // st fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size; #ifdef FM_VERBOSE_DBG _pico_printf( PICO_VERBOSE, "ST: %s\n", (unsigned char *) fm.fm_st_hdr->ident ); #endif if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) ) { #ifdef FM_DBG _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n"); #endif _pico_free(bb0); return PICO_PMV_ERROR_IDENT; } // check fm if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) { #ifdef FM_DBG _pico_printf( PICO_WARNING, "FM ST Version incorrect\n"); #endif _pico_free(bb0); return PICO_PMV_ERROR_VERSION; } // tri fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size; #ifdef FM_VERBOSE_DBG _pico_printf( PICO_VERBOSE, "TRI: %s\n", (unsigned char *) fm.fm_tri_hdr->ident ); #endif if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) ) { #ifdef FM_DBG _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n"); #endif _pico_free(bb0); return PICO_PMV_ERROR_IDENT; } // check fm if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) { #ifdef FM_DBG _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n"); #endif _pico_free(bb0); return PICO_PMV_ERROR_VERSION; } // frame fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); fm_file_pos += sizeof(fm_chunk_header_t); #ifdef FM_VERBOSE_DBG _pico_printf( PICO_VERBOSE, "FRAME: %s\n", (unsigned char *) fm.fm_frame_hdr->ident ); #endif if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) ) { #ifdef FM_DBG _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n"); #endif _pico_free(bb0); return PICO_PMV_ERROR_IDENT; } // check fm if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) { #ifdef FM_DBG _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n"); #endif _pico_free(bb0); return PICO_PMV_ERROR_VERSION; } // file seems to be a valid fm return PICO_PMV_OK; }
// _fm_load() loads a Heretic 2 model file. static picoModel_t *_fm_load( PM_PARAMS_LOAD ) { int i, j, dups, dup_index; int fm_file_pos; index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3; index_DUP_LUT_t *p_index_LUT_DUPS; fm_vert_normal_t *vert; char skinname[FM_SKINPATHSIZE]; fm_t fm; fm_header_t *fm_head; fm_st_t *texCoord; fm_xyz_st_t *tri_verts; fm_xyz_st_t *triangle; fm_frame_t *frame; picoByte_t *bb, *bb0; picoModel_t *picoModel; picoSurface_t *picoSurface; picoShader_t *picoShader; picoVec3_t xyz, normal; picoVec2_t st; picoColor_t color; bb0 = bb = (picoByte_t*) _pico_alloc(bufSize); memcpy(bb, buffer, bufSize); // Header Header fm.fm_header_hdr = (fm_chunk_header_t *) bb; fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size; if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) ) { _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n"); _pico_free(bb0); return NULL; } if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) { _pico_printf( PICO_WARNING, "FM Header Version incorrect\n"); _pico_free(bb0); return NULL; } // Skin Header fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size; if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) ) { _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n"); _pico_free(bb0); return NULL; } if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) { _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n"); _pico_free(bb0); return NULL; } // ST Header fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size; if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) ) { _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n"); _pico_free(bb0); return NULL; } if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) { _pico_printf( PICO_WARNING, "FM ST Version incorrect\n"); _pico_free(bb0); return NULL; } // Tris Header fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size; if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) ) { _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n"); _pico_free(bb0); return NULL; } if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) { _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n"); _pico_free(bb0); return NULL; } // Frame Header fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); fm_file_pos += sizeof(fm_chunk_header_t); if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) ) { _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n"); _pico_free(bb0); return NULL; } if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) { _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n"); _pico_free(bb0); return NULL; } // Header fm_file_pos = sizeof(fm_chunk_header_t); fm_head = fm.fm_header = (fm_header_t *) (bb + fm_file_pos); fm_file_pos += fm.fm_header_hdr->size; // Skin fm_file_pos += sizeof(fm_chunk_header_t); fm.fm_skin = (fm_skinpath_t *) (bb + fm_file_pos); fm_file_pos += fm.fm_skin_hdr->size; // ST fm_file_pos += sizeof(fm_chunk_header_t); texCoord = fm.fm_st = (fm_st_t *) (bb + fm_file_pos); fm_file_pos += fm.fm_st_hdr->size; // Tri fm_file_pos += sizeof(fm_chunk_header_t); tri_verts = fm.fm_tri = (fm_xyz_st_t *) (bb + fm_file_pos); fm_file_pos += fm.fm_tri_hdr->size; // Frame fm_file_pos += sizeof(fm_chunk_header_t); frame = fm.fm_frame = (fm_frame_t *) (bb + fm_file_pos); // do frame check if( fm_head->numFrames < 1 ) { _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName ); _pico_free(bb0); return NULL; } if( frameNum < 0 || frameNum >= fm_head->numFrames ) { _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" ); _pico_free(bb0); return NULL; } // swap fm fm_head->skinWidth = _pico_little_long( fm_head->skinWidth ); fm_head->skinHeight = _pico_little_long( fm_head->skinHeight ); fm_head->frameSize = _pico_little_long( fm_head->frameSize ); fm_head->numSkins = _pico_little_long( fm_head->numSkins ); fm_head->numXYZ = _pico_little_long( fm_head->numXYZ ); fm_head->numST = _pico_little_long( fm_head->numST ); fm_head->numTris = _pico_little_long( fm_head->numTris ); fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds ); fm_head->numFrames = _pico_little_long( fm_head->numFrames ); // swap frame scale and translation for( i = 0; i < 3; i++ ) { frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] ); frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] ); } // swap triangles triangle = tri_verts; for( i = 0; i < fm_head->numTris; i++, triangle++ ) { for( j = 0; j < 3; j++ ) { triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] ); triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] ); } } // swap st coords for( i = 0; i < fm_head->numST; i++ ) { texCoord->s = _pico_little_short( texCoord[i].s ); texCoord->t = _pico_little_short( texCoord[i].t ); } // set Skin Name strncpy(skinname, (const char *) fm.fm_skin, FM_SKINPATHSIZE ); #ifdef FM_VERBOSE_DBG // Print out md2 values _pico_printf(PICO_VERBOSE,"numSkins->%d numXYZ->%d numST->%d numTris->%d numFrames->%d\nSkin Name \"%s\"\n", fm_head->numSkins, fm_head->numXYZ, fm_head->numST, fm_head->numTris, fm_head->numFrames, &skinname ); #endif // detox Skin name _pico_setfext( skinname, "" ); _pico_unixify( skinname ); /* create new pico model */ picoModel = PicoNewModel(); if( picoModel == NULL ) { _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); _pico_free(bb0); return NULL; } /* do model setup */ PicoSetModelFrameNum( picoModel, frameNum ); PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */ PicoSetModelName( picoModel, fileName ); PicoSetModelFileName( picoModel, fileName ); // allocate new pico surface picoSurface = PicoNewSurface( picoModel ); if( picoSurface == NULL ) { _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); PicoFreeModel( picoModel ); _pico_free(bb0); return NULL; } PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); PicoSetSurfaceName( picoSurface, frame->header.name ); picoShader = PicoNewShader( picoModel ); if( picoShader == NULL ) { _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); PicoFreeModel( picoModel ); _pico_free(bb0); return NULL; } PicoSetShaderName( picoShader, skinname ); // associate current surface with newly created shader PicoSetSurfaceShader( picoSurface, picoShader ); // Init LUT for Verts p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * fm_head->numXYZ); for(i=0; i<fm_head->numXYZ; i++) { p_index_LUT[i].Vert = -1; p_index_LUT[i].ST = -1; p_index_LUT[i].next = NULL; } // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert. dups = 0; triangle = tri_verts; for(i=0; i<fm_head->numTris; i++) { for(j=0; j<3; j++) { if (p_index_LUT[triangle->index_xyz[j]].ST == -1) // No Main Entry p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j]; else if (triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) // Equal to Main Entry { #ifdef FM_VERBOSE_DBG _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); #endif continue; } else if ( (p_index_LUT[triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry { // Add first entry of LL from Main p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); if (p_index_LUT2 == NULL) _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2; p_index_LUT2->Vert = dups; p_index_LUT2->ST = triangle->index_st[j]; p_index_LUT2->next = NULL; #ifdef FM_VERBOSE_DBG _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j]); #endif triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk dups++; } else // Try to find in LL from Main Entry { p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next; while ( (p_index_LUT2 != NULL) && (triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL { p_index_LUT3 = p_index_LUT2; p_index_LUT2 = p_index_LUT2->next; } p_index_LUT2 = p_index_LUT3; if ( triangle->index_st[j] == p_index_LUT2->ST ) // Found it { triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk #ifdef FM_VERBOSE_DBG _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); #endif continue; } if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL. { // Add the Entry p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); if (p_index_LUT3 == NULL) _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); p_index_LUT2->next = (index_LUT_t *)p_index_LUT3; p_index_LUT3->Vert = dups; p_index_LUT3->ST = triangle->index_st[j]; p_index_LUT3->next = NULL; #ifdef FM_VERBOSE_DBG _pico_printf( PICO_NORMAL, " ADDING additional LL XYZ:%d DUP:%d NewXYZ:%d ST:%d\n", triangle->index_xyz[j], dups, dups + (fm_head->numXYZ), triangle->index_st[j]); #endif triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk dups++; } } #ifdef FM_VERBOSE_DBG _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); #endif } triangle++; } // malloc and build array for Dup STs p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups); if (p_index_LUT_DUPS == NULL) _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); dup_index = 0; for(i=0; i<fm_head->numXYZ; i++) { p_index_LUT2 = p_index_LUT[i].next; while (p_index_LUT2 != NULL) { p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i; p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST; dup_index++; p_index_LUT2 = p_index_LUT2->next; } } #ifdef FM_VERBOSE_DBG _pico_printf( PICO_NORMAL, " Dups = %d\n", dups); _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index); #endif for(i=0; i<fm_head->numXYZ; i++) { #ifdef FM_VERBOSE_DBG _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST); #endif if (p_index_LUT[i].next != NULL) { p_index_LUT2 = p_index_LUT[i].next; do { #ifdef FM_VERBOSE_DBG _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST); #endif p_index_LUT2 = p_index_LUT2->next; } while ( p_index_LUT2 != NULL); } #ifdef FM_VERBOSE_DBG _pico_printf( PICO_NORMAL, "\n"); #endif } #ifdef FM_VERBOSE_DBG for(i=0; i<dup_index; i++) _pico_printf( PICO_NORMAL, " Dup Index #%d OldVert: %d ST: %d\n", i, p_index_LUT_DUPS[i].OldVert, p_index_LUT_DUPS[i].ST); triangle = tri_verts; for(i=0; i<fm_head->numTris; i++) { for(j=0; j<3; j++) _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); _pico_printf( PICO_NORMAL, "\n"); triangle++; } #endif // Build Picomodel triangle = tri_verts; for( j = 0; j < fm_head->numTris; j++, triangle++ ) { PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] ); PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] ); PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] ); } vert = (fm_vert_normal_t*) ((picoByte_t*) (frame->verts) ); for(i=0; i< fm_head->numXYZ; i++, vert++) { /* set vertex origin */ xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0]; xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1]; xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2]; PicoSetSurfaceXYZ( picoSurface, i , xyz ); /* set normal */ normal[ 0 ] = fm_normals[vert->lightnormalindex][0]; normal[ 1 ] = fm_normals[vert->lightnormalindex][1]; normal[ 2 ] = fm_normals[vert->lightnormalindex][2]; PicoSetSurfaceNormal( picoSurface, i , normal ); /* set st coords */ st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)fm_head->skinWidth)); st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)fm_head->skinHeight)); PicoSetSurfaceST( picoSurface, 0, i , st ); } if (dups) { for(i=0; i<dups; i++) { j = p_index_LUT_DUPS[i].OldVert; /* set vertex origin */ xyz[ 0 ] = frame->verts[j].v[0] * frame->header.scale[0] + frame->header.translate[0]; xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1]; xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2]; PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ , xyz ); /* set normal */ normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0]; normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1]; normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2]; PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ , normal ); /* set st coords */ st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)fm_head->skinWidth)); st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)fm_head->skinHeight)); PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ , st ); } } /* set color */ PicoSetSurfaceColor( picoSurface, 0, 0, color ); // Free up malloc'ed LL entries for(i=0; i<fm_head->numXYZ; i++) { if(p_index_LUT[i].next != NULL) { p_index_LUT2 = p_index_LUT[i].next; do { p_index_LUT3 = p_index_LUT2->next; _pico_free(p_index_LUT2); p_index_LUT2 = p_index_LUT3; dups--; } while (p_index_LUT2 != NULL); } } if (dups) _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n"); // Free malloc'ed LUTs _pico_free(p_index_LUT); _pico_free(p_index_LUT_DUPS); /* return the new pico model */ _pico_free(bb0); return picoModel; }
void _terrain_load_tga_buffer( unsigned char *buffer, unsigned char **pic, int *width, int *height ){ int row, column; int columns, rows, numPixels; unsigned char *pixbuf; unsigned char *buf_p; tga_t targa_header; unsigned char *targa_rgba; *pic = NULL; if ( buffer == NULL ) { return; } buf_p = buffer; targa_header.id_length = *buf_p++; targa_header.colormap_type = *buf_p++; targa_header.image_type = *buf_p++; targa_header.colormap_index = _pico_little_short( *(short*)buf_p ); buf_p += 2; targa_header.colormap_length = _pico_little_short( *(short*) buf_p ); buf_p += 2; targa_header.colormap_size = *buf_p++; targa_header.x_origin = _pico_little_short( *(short*) buf_p ); buf_p += 2; targa_header.y_origin = _pico_little_short( *(short*) buf_p ); buf_p += 2; targa_header.width = _pico_little_short( *(short*) buf_p ); buf_p += 2; targa_header.height = _pico_little_short( *(short*) buf_p ); buf_p += 2; targa_header.pixel_size = *buf_p++; targa_header.attributes = *buf_p++; if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 ) { _pico_printf( PICO_ERROR, "Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n" ); pic = NULL; return; } if ( targa_header.colormap_type != 0 ) { _pico_printf( PICO_ERROR, "Indexed color TGA images not supported\n" ); return; } if ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 && targa_header.image_type != 3 ) { _pico_printf( PICO_ERROR, "Only 32 or 24 bit TGA images supported (not indexed color)\n" ); pic = NULL; return; } columns = targa_header.width; rows = targa_header.height; numPixels = columns * rows; if ( width ) { *width = columns; } if ( height ) { *height = rows; } targa_rgba = _pico_alloc( numPixels * 4 ); *pic = targa_rgba; if ( targa_header.id_length != 0 ) { buf_p += targa_header.id_length; // skip TARGA image comment } if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) { // Uncompressed RGB or gray scale image for ( row = rows - 1; row >= 0; row-- ) { pixbuf = targa_rgba + row * columns * 4; for ( column = 0; column < columns; column++ ) { unsigned char red,green,blue,alphabyte; switch ( targa_header.pixel_size ) { case 8: blue = *buf_p++; green = blue; red = blue; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = 255; break; case 24: blue = *buf_p++; green = *buf_p++; red = *buf_p++; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = 255; break; case 32: blue = *buf_p++; green = *buf_p++; red = *buf_p++; alphabyte = *buf_p++; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alphabyte; break; default: break; } } } } /* rle encoded pixels */ else if ( targa_header.image_type == 10 ) { unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; red = 0; green = 0; blue = 0; alphabyte = 0xff; for ( row = rows - 1; row >= 0; row-- ) { pixbuf = targa_rgba + row * columns * 4; for ( column = 0; column < columns; ) { packetHeader = *buf_p++; packetSize = 1 + ( packetHeader & 0x7f ); if ( packetHeader & 0x80 ) { // run-length packet switch ( targa_header.pixel_size ) { case 24: blue = *buf_p++; green = *buf_p++; red = *buf_p++; alphabyte = 255; break; case 32: blue = *buf_p++; green = *buf_p++; red = *buf_p++; alphabyte = *buf_p++; break; default: //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); break; } for ( j = 0; j < packetSize; j++ ) { *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alphabyte; column++; if ( column == columns ) { // run spans across rows column = 0; if ( row > 0 ) { row--; } else{ goto breakOut; } pixbuf = targa_rgba + row * columns * 4; } } } else { // non run-length packet for ( j = 0; j < packetSize; j++ ) { switch ( targa_header.pixel_size ) { case 24: blue = *buf_p++; green = *buf_p++; red = *buf_p++; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = 255; break; case 32: blue = *buf_p++; green = *buf_p++; red = *buf_p++; alphabyte = *buf_p++; *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alphabyte; break; default: //Sysprintf("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); break; } column++; if ( column == columns ) { // pixel packet run spans across rows column = 0; if ( row > 0 ) { row--; } else{ goto breakOut; } pixbuf = targa_rgba + row * columns * 4; } } } } breakOut:; } } /* fix vertically flipped image */ if ( ( targa_header.attributes & ( 1 << 5 ) ) ) { int flip; for ( row = 0; row < .5f * rows; row++ ) { for ( column = 0; column < columns; column++ ) { flip = *( (int*)targa_rgba + row * columns + column ); *( (int*)targa_rgba + row * columns + column ) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ); *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip; } } } }