/* _ms3d_canload: * validates a milkshape3d model file. */ static int _ms3d_canload( PM_PARAMS_CANLOAD ){ const TMsHeader *hdr; /* sanity check */ if ( (size_t) bufSize < sizeof( TMsHeader ) ) { return PICO_PMV_ERROR_SIZE; } /* get ms3d header */ hdr = (const TMsHeader *)buffer; /* check ms3d magic */ if ( strncmp( hdr->magic,"MS3D000000",10 ) != 0 ) { return PICO_PMV_ERROR_IDENT; } /* check ms3d version */ if ( _pico_little_long( hdr->version ) < 3 || _pico_little_long( hdr->version ) > 4 ) { _pico_printf( PICO_ERROR,"MS3D file ignored. Only MS3D 1.3 and 1.4 is supported." ); return PICO_PMV_ERROR_VERSION; } /* file seems to be a valid ms3d */ return PICO_PMV_OK; }
static int _md2_canload( PM_PARAMS_CANLOAD ) { md2_t *md2; /* to keep the compiler happy */ *fileName = *fileName; /* sanity check */ if( bufSize < ( sizeof( *md2 ) * 2) ) return PICO_PMV_ERROR_SIZE; /* set as md2 */ md2 = (md2_t*) buffer; /* check md2 magic */ if( *((int*) md2->magic) != *((int*) MD2_MAGIC) ) return PICO_PMV_ERROR_IDENT; /* check md2 version */ if( _pico_little_long( md2->version ) != MD2_VERSION ) return PICO_PMV_ERROR_VERSION; /* file seems to be a valid md2 */ return PICO_PMV_OK; }
/* _3ds_canload: * validates an autodesk 3ds model file. */ static int _3ds_canload( PM_PARAMS_CANLOAD ) { T3dsChunk *chunk; /* to keep the compiler happy */ *fileName = *fileName; /* sanity check */ if (bufSize < sizeof(T3dsChunk)) return PICO_PMV_ERROR_SIZE; /* get pointer to 3ds header chunk */ chunk = (T3dsChunk *)buffer; /* check data length */ if (bufSize < _pico_little_long(chunk->len)) return PICO_PMV_ERROR_SIZE; /* check 3ds magic */ if (_pico_little_short(chunk->id) != CHUNK_MAIN) return PICO_PMV_ERROR_IDENT; /* file seems to be a valid 3ds */ return PICO_PMV_OK; }
static T3dsChunk *GetChunk( T3dsLoaderPers *pers ){ T3dsChunk *chunk; /* sanity check */ if ( pers->cofs > pers->maxofs ) { return 0; } #ifdef DEBUG_PM_3DS /* printf("GetChunk: pers->cofs %x\n",pers->cofs); */ #endif /* fill in pointer to chunk */ chunk = (T3dsChunk *)&pers->bufptr[ pers->cofs ]; if ( !chunk ) { return NULL; } chunk->id = _pico_little_short( chunk->id ); chunk->len = _pico_little_long( chunk->len ); /* advance in buffer */ pers->cofs += sizeof( T3dsChunk ); /* this means yay */ return chunk; }
/* _3ds_canload: * validates an autodesk 3ds model file. */ static int _3ds_canload( PM_PARAMS_CANLOAD ){ const T3dsChunk *chunk; /* sanity check */ if ( bufSize < (int) sizeof( T3dsChunk ) ) { return PICO_PMV_ERROR_SIZE; } /* get pointer to 3ds header chunk */ chunk = (const T3dsChunk *)buffer; /* check data length */ if ( bufSize < (int) _pico_little_long( chunk->len ) ) { return PICO_PMV_ERROR_SIZE; } /* check 3ds magic */ if ( _pico_little_short( chunk->id ) != CHUNK_MAIN ) { return PICO_PMV_ERROR_IDENT; } /* file seems to be a valid 3ds */ return PICO_PMV_OK; }
// _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; }
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; }
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; }