void PicoSetSurfaceName (picoSurface_t *surface, char *name) { if (surface == NULL || name == NULL) return; if (surface->name != NULL) _pico_free(surface->name); surface->name = _pico_clone_alloc(name); }
void PicoSetShaderMapName (picoShader_t *shader, char *mapName) { if (shader == NULL || mapName == NULL) return; if (shader->mapName != NULL) _pico_free(shader->mapName); shader->mapName = _pico_clone_alloc(mapName); }
void PicoSetShaderName (picoShader_t *shader, const char *name) { if (shader == NULL || name == NULL) return; if (shader->name != NULL) _pico_free(shader->name); shader->name = _pico_clone_alloc(name); }
void PicoSetModelFileName (picoModel_t *model, const char *fileName) { if (model == NULL || fileName == NULL) return; if (model->fileName != NULL) _pico_free(model->fileName); model->fileName = _pico_clone_alloc(fileName); }
void PicoSetModelName (picoModel_t *model, const char *name) { if (model == NULL || name == NULL) return; if (model->name != NULL) _pico_free(model->name); model->name = _pico_clone_alloc(name); }
static picoShader_t *_obj_default_shader (picoModel_t *model) { picoShader_t *picoShader = PicoNewShader(model); char *skinname = _pico_clone_alloc(model->fileName); _pico_setfext(skinname, ""); PicoSetShaderName(picoShader, skinname); _pico_free(skinname); return picoShader; }
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 int DoNextEditorDataChunk (T3dsLoaderPers *pers, long endofs) { T3dsChunk *chunk; #ifdef DEBUG_PM_3DS_EX printf("DoNextEditorDataChunk: endofs %d\n",endofs); #endif while (pers->cofs < endofs) { long nextofs = pers->cofs; if ((chunk = GetChunk(pers)) == NULL) return 0; if (!chunk->len) return 0; nextofs += chunk->len; #ifdef DEBUG_PM_3DS_EX printf("Chunk %04x (%s), len %d pers->cofs %x\n",chunk->id,DebugGetChunkName(chunk->id),chunk->len,pers->cofs); #endif /*** meshes ***/ if (chunk->id == CHUNK_OBJECT) { picoSurface_t *surface; char surfaceName[ 0xff ] = { 0 }; /* read in surface name */ if( !GetASCIIZ(pers,surfaceName,sizeof(surfaceName)) ) return 0; /* this is bad */ //PicoGetSurfaceName /* ignore NULL name surfaces */ // if( surfaceName /* allocate a pico surface */ surface = PicoNewSurface( pers->model ); if( surface == NULL ) { pers->surface = NULL; return 0; /* this is bad too */ } /* assign ptr to current surface */ pers->surface = surface; /* 3ds models surfaces are all triangle meshes */ PicoSetSurfaceType( pers->surface,PICO_TRIANGLES ); /* set surface name */ PicoSetSurfaceName( pers->surface,surfaceName ); /* continue mess with object's sub chunks */ DoNextEditorDataChunk(pers,nextofs); continue; } if (chunk->id == CHUNK_OBJECT_MESH) { /* continue mess with mesh's sub chunks */ if (!DoNextEditorDataChunk(pers,nextofs)) return 0; continue; } if (chunk->id == CHUNK_OBJECT_VERTICES) { if (!GetMeshVertices(pers)) return 0; continue; } if (chunk->id == CHUNK_OBJECT_FACES) { if (!GetMeshFaces(pers)) return 0; continue; } if (chunk->id == CHUNK_OBJECT_UV) { if (!GetMeshTexCoords(pers)) return 0; continue; } if (chunk->id == CHUNK_OBJECT_MATERIAL) { if (!GetMeshShader(pers)) return 0; continue; } /*** materials ***/ if (chunk->id == CHUNK_MATERIAL) { /* new shader specific things should be */ /* initialized right here */ picoShader_t *shader; /* allocate a pico shader */ shader = PicoNewShader( pers->model ); /* ydnar */ if( shader == NULL ) { pers->shader = NULL; return 0; /* this is bad too */ } /* assign ptr to current shader */ pers->shader = shader; /* continue and process the material's sub chunks */ DoNextEditorDataChunk(pers,nextofs); continue; } if (chunk->id == CHUNK_MATNAME) { /* new material's names should be stored here. note that */ /* GetMeshMaterial returns the name of the material that */ /* is used by the mesh. new material names are set HERE. */ /* but for now we skip the new material's name ... */ if (pers->shader) { char *name = (char*) (pers->bufptr + pers->cofs); char *cleanedName = _pico_clone_alloc( name ); _pico_first_token( cleanedName ); PicoSetShaderName( pers->shader, cleanedName ); #ifdef DEBUG_PM_3DS printf( "NewShader: '%s'\n", cleanedName ); #endif _pico_free( cleanedName ); } } if (chunk->id == CHUNK_MATDIFFUSE) { /* todo: color for last inserted new material should be */ /* stored somewhere by GetDiffuseColor */ if (!GetDiffuseColor(pers)) return 0; /* rest of chunk is skipped here */ } if (chunk->id == CHUNK_MATMAP) { /* continue and process the material map sub chunks */ DoNextEditorDataChunk(pers,nextofs); continue; } if (chunk->id == CHUNK_MATMAPFILE) { /* map file name for last inserted new material should */ /* be stored here. but for now we skip this too ... */ if( pers->shader ) { char *name = (char *)(pers->bufptr + pers->cofs); PicoSetShaderMapName( pers->shader,name ); #ifdef DEBUG_PM_3DS printf("NewShaderMapfile: '%s'\n",name); #endif } } /*** keyframes ***/ if (chunk->id == CHUNK_KEYFRAME_DATA) { /* well umm, this is a bit too much since we don't really */ /* need model animation sequences right now. we skip this */ #ifdef DEBUG_PM_3DS printf("KeyframeData: len %d\n",chunk->len); #endif } /* skip unknown chunk */ pers->cofs = nextofs; if (pers->cofs >= pers->maxofs) break; } return 1; }
static int _obj_mtl_load (picoModel_t *model) { picoParser_t *p; picoByte_t *mtlBuffer; int mtlBufSize; char *fileName; /* sanity checks */ if (model == NULL || model->fileName == NULL) return 0; /* skip if we have a zero length model file name */ if (!strlen(model->fileName)) return 0; /* helper */ #define _obj_mtl_error_return \ { \ _pico_free_parser( p ); \ _pico_free_file( mtlBuffer ); \ _pico_free( fileName ); \ return 0; \ } /* alloc copy of model file name */ fileName = _pico_clone_alloc(model->fileName); if (fileName == NULL) return 0; /* change extension of model file to .mtl */ _pico_setfext(fileName, "mtl"); /* load .mtl file contents */ _pico_load_file(fileName, &mtlBuffer, &mtlBufSize); /* check result */ if (mtlBufSize == 0) return 1; /* file is empty: no error */ if (mtlBufSize < 0) return 0; /* load failed: error */ /* create a new pico parser */ p = _pico_new_parser(mtlBuffer, mtlBufSize); if (p == NULL) _obj_mtl_error_return; /* doo teh .mtl parse */ while (1) { /* get next token in material file */ if (_pico_parse(p, 1) == NULL) break; #if 0 /* skip empty lines */ if (p->token == NULL || !strlen(p->token)) continue; /* skip comment lines */ if (p->token[0] == '#') { _pico_parse_skip_rest(p); continue; } /* new material */ if (!_pico_stricmp(p->token, "newmtl")) { picoShader_t *shader; char *name; /* get material name */ name = _pico_parse(p, 0); /* validate material name */ if (name == NULL || !strlen(name)) { _pico_printf(PICO_ERROR, "Missing material name in MTL, line %d.", p->curLine); _obj_mtl_error_return; } /* create a new pico shader */ shader = PicoNewShader(model); if (shader == NULL) _obj_mtl_error_return; /* set shader name */ PicoSetShaderName(shader, name); /* assign pointer to current shader */ curShader = shader; } /* diffuse map name */ else if (!_pico_stricmp(p->token, "map_kd")) { char *mapName; /* pointer to current shader must be valid */ if (curShader == NULL) _obj_mtl_error_return; /* get material's diffuse map name */ mapName = _pico_parse(p, 0); /* validate map name */ if (mapName == NULL || !strlen(mapName)) { _pico_printf(PICO_ERROR, "Missing material map name in MTL, line %d.", p->curLine); _obj_mtl_error_return; } /* set shader map name */ PicoSetShaderMapName(shader, mapName); } /* dissolve factor (pseudo transparency 0..1) */ /* where 0 means 100% transparent and 1 means opaque */ else if (!_pico_stricmp(p->token, "d")) { picoByte_t *diffuse; float value; /* get dissolve factor */ if (!_pico_parse_float(p, &value)) _obj_mtl_error_return; /* set shader transparency */ PicoSetShaderTransparency(curShader, value); /* get shader's diffuse color */ diffuse = PicoGetShaderDiffuseColor(curShader); /* set diffuse alpha to transparency */ diffuse[3] = (picoByte_t) (value * 255.0); /* set shader's new diffuse color */ PicoSetShaderDiffuseColor(curShader, diffuse); } /* shininess (phong specular component) */ else if (!_pico_stricmp(p->token, "ns")) { /* remark: * - well, this is some major obj spec fuckup once again. some * apps store this in 0..1 range, others use 0..100 range, * even others use 0..2048 range, and again others use the * range 0..128, some even use 0..1000, 0..200, 400..700, * honestly, what's up with the 3d app coders? happens when * you smoke too much weed i guess. -sea */ float value; /* pointer to current shader must be valid */ if (curShader == NULL) _obj_mtl_error_return; /* get totally screwed up shininess (a random value in fact ;) */ if (!_pico_parse_float(p, &value)) _obj_mtl_error_return; /* okay, there is no way to set this correctly, so we simply */ /* try to guess a few ranges (most common ones i have seen) */ /* assume 0..2048 range */ if (value > 1000) value = 128.0 * (value / 2048.0); /* assume 0..1000 range */ else if (value > 200) value = 128.0 * (value / 1000.0); /* assume 0..200 range */ else if (value > 100) value = 128.0 * (value / 200.0); /* assume 0..100 range */ else if (value > 1) value = 128.0 * (value / 100.0); /* assume 0..1 range */ else { value *= 128.0; } /* negative shininess is bad (yes, i have seen it...) */ if (value < 0.0) value = 0.0; /* set the pico shininess value in range 0..127 */ /* geez, .obj is such a mess... */ PicoSetShaderShininess(curShader, value); } /* kol0r ambient (wut teh fuk does "ka" stand for?) */ else if (!_pico_stricmp(p->token, "ka")) { picoColor_t color; picoVec3_t v; /* pointer to current shader must be valid */ if (curShader == NULL) _obj_mtl_error_return; /* get color vector */ if (!_pico_parse_vec(p, v)) _obj_mtl_error_return; /* scale to byte range */ color[0] = (picoByte_t) (v[0] * 255); color[1] = (picoByte_t) (v[1] * 255); color[2] = (picoByte_t) (v[2] * 255); color[3] = (picoByte_t) (255); /* set ambient color */ PicoSetShaderAmbientColor(curShader, color); } /* kol0r diffuse */ else if (!_pico_stricmp(p->token, "kd")) { picoColor_t color; picoVec3_t v; /* pointer to current shader must be valid */ if (curShader == NULL) _obj_mtl_error_return; /* get color vector */ if (!_pico_parse_vec(p, v)) _obj_mtl_error_return; /* scale to byte range */ color[0] = (picoByte_t) (v[0] * 255); color[1] = (picoByte_t) (v[1] * 255); color[2] = (picoByte_t) (v[2] * 255); color[3] = (picoByte_t) (255); /* set diffuse color */ PicoSetShaderDiffuseColor(curShader, color); } /* kol0r specular */ else if (!_pico_stricmp(p->token, "ks")) { picoColor_t color; picoVec3_t v; /* pointer to current shader must be valid */ if (curShader == NULL) _obj_mtl_error_return; /* get color vector */ if (!_pico_parse_vec(p, v)) _obj_mtl_error_return; /* scale to byte range */ color[0] = (picoByte_t) (v[0] * 255); color[1] = (picoByte_t) (v[1] * 255); color[2] = (picoByte_t) (v[2] * 255); color[3] = (picoByte_t) (255); /* set specular color */ PicoSetShaderSpecularColor(curShader, color); } #endif /* skip rest of line */ _pico_parse_skip_rest(p); } /* free parser, file buffer, and file name */ _pico_free_parser(p); _pico_free_file(mtlBuffer); _pico_free(fileName); /* return with success */ return 1; }