/** * @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; }
static picoModel_t *_terrain_load( PM_PARAMS_LOAD ){ int i, j, v, pw[ 5 ], r; picoParser_t *p; char *shader, *heightmapFile, *colormapFile; picoVec3_t scale, origin; unsigned char *imageBuffer; int imageBufSize, w, h, cw, ch; unsigned char *heightmap, *colormap, *heightPixel, *colorPixel; picoModel_t *picoModel; picoSurface_t *picoSurface; picoShader_t *picoShader; picoVec3_t xyz, normal; picoVec2_t st; picoColor_t color; /* create pico parser */ p = _pico_new_parser( (const picoByte_t*) buffer, bufSize ); if ( p == NULL ) { return NULL; } /* get first token */ if ( _pico_parse_first( p ) == NULL ) { return NULL; } /* check first token */ if ( _pico_stricmp( p->token, "picoterrain" ) ) { _pico_printf( PICO_ERROR, "Invalid PicoTerrain model" ); _pico_free_parser( p ); return NULL; } /* setup */ shader = heightmapFile = colormapFile = NULL; _pico_set_vec( scale, 512, 512, 32 ); /* parse ase model file */ while ( 1 ) { /* get first token on line */ if ( !_pico_parse_first( p ) ) { break; } /* skip empty lines */ if ( !p->token || !p->token[ 0 ] ) { continue; } /* shader */ if ( !_pico_stricmp( p->token, "shader" ) ) { if ( _pico_parse( p, 0 ) && p->token[ 0 ] ) { if ( shader != NULL ) { _pico_free( shader ); } shader = _pico_clone_alloc( p->token ); } } /* heightmap */ else if ( !_pico_stricmp( p->token, "heightmap" ) ) { if ( _pico_parse( p, 0 ) && p->token[ 0 ] ) { if ( heightmapFile != NULL ) { _pico_free( heightmapFile ); } heightmapFile = _pico_clone_alloc( p->token ); } } /* colormap */ else if ( !_pico_stricmp( p->token, "colormap" ) ) { if ( _pico_parse( p, 0 ) && p->token[ 0 ] ) { if ( colormapFile != NULL ) { _pico_free( colormapFile ); } colormapFile = _pico_clone_alloc( p->token ); } } /* scale */ else if ( !_pico_stricmp( p->token, "scale" ) ) { _pico_parse_vec( p, scale ); } /* skip unparsed rest of line and continue */ _pico_parse_skip_rest( p ); } /* ----------------------------------------------------------------- */ /* load heightmap */ heightmap = imageBuffer = NULL; _pico_load_file( heightmapFile, &imageBuffer, &imageBufSize ); _terrain_load_tga_buffer( imageBuffer, &heightmap, &w, &h ); _pico_free( heightmapFile ); _pico_free_file( imageBuffer ); if ( heightmap == NULL || w < 2 || h < 2 ) { _pico_printf( PICO_ERROR, "PicoTerrain model with invalid heightmap" ); if ( shader != NULL ) { _pico_free( shader ); } if ( colormapFile != NULL ) { _pico_free( colormapFile ); } _pico_free_parser( p ); return NULL; } /* set origin (bottom lowest corner of terrain mesh) */ _pico_set_vec( origin, ( w / -2 ) * scale[ 0 ], ( h / -2 ) * scale[ 1 ], -128 * scale[ 2 ] ); /* load colormap */ colormap = imageBuffer = NULL; _pico_load_file( colormapFile, &imageBuffer, &imageBufSize ); _terrain_load_tga_buffer( imageBuffer, &colormap, &cw, &ch ); _pico_free( colormapFile ); _pico_free_file( imageBuffer ); if ( cw != w || ch != h ) { _pico_printf( PICO_WARNING, "PicoTerrain colormap/heightmap size mismatch" ); _pico_free( colormap ); colormap = NULL; } /* ----------------------------------------------------------------- */ /* 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, 1 ); /* 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 ); /* sea */ return NULL; } /* terrain surfaces are triangle meshes */ PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); /* set surface name */ PicoSetSurfaceName( picoSurface, "picoterrain" ); /* create new pico shader */ picoShader = PicoNewShader( picoModel ); if ( picoShader == NULL ) { _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); PicoFreeModel( picoModel ); _pico_free( shader ); return NULL; } /* detox and set shader name */ _pico_setfext( shader, "" ); _pico_unixify( shader ); PicoSetShaderName( picoShader, shader ); _pico_free( shader ); /* associate current surface with newly created shader */ PicoSetSurfaceShader( picoSurface, picoShader ); /* make bogus normal */ _pico_set_vec( normal, 0.0f, 0.0f, 0.0f ); /* create mesh */ for ( j = 0; j < h; j++ ) { for ( i = 0; i < w; i++ ) { /* get pointers */ v = i + ( j * w ); heightPixel = heightmap + v * 4; colorPixel = colormap ? colormap + v * 4 : NULL; /* set xyz */ _pico_set_vec( xyz, origin[ 0 ] + scale[ 0 ] * i, origin[ 1 ] + scale[ 1 ] * j, origin[ 2 ] + scale[ 2 ] * heightPixel[ 0 ] ); PicoSetSurfaceXYZ( picoSurface, v, xyz ); /* set normal */ PicoSetSurfaceNormal( picoSurface, v, normal ); /* set st */ st[ 0 ] = (float) i; st[ 1 ] = (float) j; PicoSetSurfaceST( picoSurface, 0, v, st ); /* set color */ if ( colorPixel != NULL ) { _pico_set_color( color, colorPixel[ 0 ], colorPixel[ 1 ], colorPixel[ 2 ], colorPixel[ 3 ] ); } else{ _pico_set_color( color, 255, 255, 255, 255 ); } PicoSetSurfaceColor( picoSurface, 0, v, color ); /* set triangles (zero alpha in heightmap suppresses this quad) */ if ( i < ( w - 1 ) && j < ( h - 1 ) && heightPixel[ 3 ] >= 128 ) { /* set indexes */ pw[ 0 ] = i + ( j * w ); pw[ 1 ] = i + ( ( j + 1 ) * w ); pw[ 2 ] = i + 1 + ( ( j + 1 ) * w ); pw[ 3 ] = i + 1 + ( j * w ); pw[ 4 ] = i + ( j * w ); /* same as pw[ 0 ] */ /* set radix */ r = ( i + j ) & 1; /* make first triangle */ PicoSetSurfaceIndex( picoSurface, ( v * 6 + 0 ), (picoIndex_t) pw[ r + 0 ] ); PicoSetSurfaceIndex( picoSurface, ( v * 6 + 1 ), (picoIndex_t) pw[ r + 1 ] ); PicoSetSurfaceIndex( picoSurface, ( v * 6 + 2 ), (picoIndex_t) pw[ r + 2 ] ); /* make second triangle */ PicoSetSurfaceIndex( picoSurface, ( v * 6 + 3 ), (picoIndex_t) pw[ r + 0 ] ); PicoSetSurfaceIndex( picoSurface, ( v * 6 + 4 ), (picoIndex_t) pw[ r + 2 ] ); PicoSetSurfaceIndex( picoSurface, ( v * 6 + 5 ), (picoIndex_t) pw[ r + 3 ] ); } } } /* free stuff */ _pico_free_parser( p ); _pico_free( heightmap ); _pico_free( colormap ); /* return the new pico model */ 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; }