/** * @brief the meat and potatoes function */ picoModel_t *PicoLoadModel (char *fileName, int frameNum) { const picoModule_t **modules, *pm; picoModel_t *model; picoByte_t *buffer; int bufSize; /* init */ model = NULL; /* make sure we've got a file name */ if (fileName == NULL) { _pico_printf(PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)"); return NULL; } /* load file data (buffer is allocated by host app) */ _pico_load_file(fileName, &buffer, &bufSize); if (bufSize < 0) { _pico_printf(PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName); return NULL; } /* get ptr to list of supported modules */ modules = PicoModuleList(NULL); /* run it through the various loader functions and try * to find a loader that fits the given file data */ for (; *modules != NULL; modules++) { /* get module */ pm = *modules; /* sanity check */ if (pm == NULL) break; /* module must be able to load */ if (pm->canload == NULL || pm->load == NULL) continue; model = PicoModuleLoadModel(pm, fileName, buffer, bufSize, frameNum); if (model != NULL) { /* model was loaded, so break out of loop */ break; } } /* free memory used by file buffer */ if (buffer) _pico_free_file(buffer); /* return */ return model; }
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 _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; }