picomodel.c

Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------------
00002 
00003  PicoModel Library
00004 
00005  Copyright (c) 2002, Randy Reddig & seaw0lf
00006  All rights reserved.
00007 
00008  Redistribution and use in source and binary forms, with or without modification,
00009  are permitted provided that the following conditions are met:
00010 
00011  Redistributions of source code must retain the above copyright notice, this list
00012  of conditions and the following disclaimer.
00013 
00014  Redistributions in binary form must reproduce the above copyright notice, this
00015  list of conditions and the following disclaimer in the documentation and/or
00016  other materials provided with the distribution.
00017 
00018  Neither the names of the copyright holders nor the names of its contributors may
00019  be used to endorse or promote products derived from this software without
00020  specific prior written permission.
00021 
00022  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00023  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00024  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00025  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
00026  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00027  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00029  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00030  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00031  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00032 
00033  ----------------------------------------------------------------------------- */
00034 
00035 /* marker */
00036 #define PICOMODEL_C
00037 
00038 /* dependencies */
00039 #include "picointernal.h"
00040 
00041 /*
00042  PicoInit()
00043  initializes the picomodel library
00044  */
00045 
00046 int PicoInit (void)
00047 {
00048     /* successfully initialized -sea */
00049     return 1;
00050 }
00051 
00055 void PicoShutdown (void)
00056 {
00057 }
00058 
00062 int PicoError (void)
00063 {
00064     return 0;
00065 }
00066 
00070 void PicoSetMallocFunc (void *(*func) (size_t))
00071 {
00072     if (func != NULL)
00073         _pico_ptr_malloc = func;
00074 }
00075 
00079 void PicoSetFreeFunc (void(*func) (void*))
00080 {
00081     if (func != NULL)
00082         _pico_ptr_free = func;
00083 }
00084 
00088 void PicoSetLoadFileFunc (void(*func) (char*, unsigned char**, int*))
00089 {
00090     if (func != NULL)
00091         _pico_ptr_load_file = func;
00092 }
00093 
00097 void PicoSetFreeFileFunc (void(*func) (void*))
00098 {
00099     if (func != NULL)
00100         _pico_ptr_free_file = func;
00101 }
00102 
00106 void PicoSetPrintFunc (void(*func) (int, const char*))
00107 {
00108     if (func != NULL)
00109         _pico_ptr_print = func;
00110 }
00111 
00112 static picoModel_t *PicoModuleLoadModel (const picoModule_t* pm, const char* fileName, picoByte_t* buffer, int bufSize,
00113         int frameNum)
00114 {
00115     /* see whether this module can load the model file or not */
00116     if (pm->canload(fileName, buffer, bufSize) == PICO_PMV_OK) {
00117         /* use loader provided by module to read the model data */
00118         picoModel_t* model = pm->load(fileName, frameNum, buffer, bufSize);
00119         if (model == NULL) {
00120             _pico_free_file(buffer);
00121             return NULL;
00122         }
00123 
00124         /* assign pointer to file format module */
00125         model->module = pm;
00126 
00127         return model;
00128     }
00129 
00130     return NULL;
00131 }
00132 
00136 picoModel_t *PicoLoadModel (char *fileName, int frameNum)
00137 {
00138     const picoModule_t **modules, *pm;
00139     picoModel_t *model;
00140     picoByte_t *buffer;
00141     int bufSize;
00142 
00143     /* init */
00144     model = NULL;
00145 
00146     /* make sure we've got a file name */
00147     if (fileName == NULL) {
00148         _pico_printf(PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)");
00149         return NULL;
00150     }
00151 
00152     /* load file data (buffer is allocated by host app) */
00153     _pico_load_file(fileName, &buffer, &bufSize);
00154     if (bufSize < 0) {
00155         _pico_printf(PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName);
00156         return NULL;
00157     }
00158 
00159     /* get ptr to list of supported modules */
00160     modules = PicoModuleList(NULL);
00161 
00162     /* run it through the various loader functions and try
00163      * to find a loader that fits the given file data */
00164     for (; *modules != NULL; modules++) {
00165         /* get module */
00166         pm = *modules;
00167 
00168         /* sanity check */
00169         if (pm == NULL)
00170             break;
00171 
00172         /* module must be able to load */
00173         if (pm->canload == NULL || pm->load == NULL)
00174             continue;
00175 
00176         model = PicoModuleLoadModel(pm, fileName, buffer, bufSize, frameNum);
00177         if (model != NULL) {
00178             /* model was loaded, so break out of loop */
00179             break;
00180         }
00181     }
00182 
00183     /* free memory used by file buffer */
00184     if (buffer)
00185         _pico_free_file(buffer);
00186 
00187     /* return */
00188     return model;
00189 }
00190 
00191 picoModel_t *PicoModuleLoadModelStream (const picoModule_t* module, const char *fileName, void* inputStream,
00192         PicoInputStreamReadFunc inputStreamRead, size_t streamLength, int frameNum)
00193 {
00194     picoModel_t *model;
00195     picoByte_t *buffer;
00196     int bufSize;
00197 
00198     /* init */
00199     model = NULL;
00200 
00201     if (inputStream == NULL) {
00202         _pico_printf(PICO_ERROR, "PicoLoadModel: invalid input stream (inputStream == NULL)");
00203         return NULL;
00204     }
00205 
00206     if (inputStreamRead == NULL) {
00207         _pico_printf(PICO_ERROR, "PicoLoadModel: invalid input stream (inputStreamRead == NULL)");
00208         return NULL;
00209     }
00210 
00211     buffer = _pico_alloc(streamLength + 1);
00212 
00213     bufSize = (int) inputStreamRead(inputStream, buffer, streamLength);
00214     buffer[bufSize] = '\0';
00215 
00216     model = PicoModuleLoadModel(module, fileName, buffer, bufSize, frameNum);
00217     if (model != 0)
00218         _pico_free(buffer);
00219 
00220     /* return */
00221     return model;
00222 }
00223 
00227 picoModel_t *PicoNewModel (void)
00228 {
00229     picoModel_t *model;
00230 
00231     /* allocate */
00232     model = _pico_alloc(sizeof(picoModel_t));
00233     if (model == NULL)
00234         return NULL;
00235 
00236     /* clear */
00237     memset(model, 0, sizeof(picoModel_t));
00238 
00239     /* model set up */
00240     _pico_zero_bounds(model->mins, model->maxs);
00241 
00242     /* set initial frame count to 1 -sea */
00243     model->numFrames = 1;
00244 
00245     /* return ptr to new model */
00246     return model;
00247 }
00248 
00252 void PicoFreeModel (picoModel_t *model)
00253 {
00254     int i;
00255 
00256     /* sanity check */
00257     if (model == NULL)
00258         return;
00259 
00260     /* free bits */
00261     if (model->name)
00262         _pico_free(model->name);
00263 
00264     if (model->fileName)
00265         _pico_free(model->fileName);
00266 
00267     /* free shaders */
00268     for (i = 0; i < model->numShaders; i++)
00269         PicoFreeShader(model->shader[i]);
00270     free(model->shader);
00271 
00272     /* free surfaces */
00273     for (i = 0; i < model->numSurfaces; i++)
00274         PicoFreeSurface(model->surface[i]);
00275     free(model->surface);
00276 
00277     /* free the model */
00278     _pico_free(model);
00279 }
00280 
00285 int PicoAdjustModel (picoModel_t *model, int numShaders, int numSurfaces)
00286 {
00287     /* dummy check */
00288     if (model == NULL)
00289         return 0;
00290 
00291     /* bare minimums */
00292     /* sea: null surface/shader fix (1s=>0s) */
00293     if (numShaders < 0)
00294         numShaders = 0;
00295     if (numSurfaces < 0)
00296         numSurfaces = 0;
00297 
00298     /* additional shaders? */
00299     while (numShaders > model->maxShaders) {
00300         model->maxShaders += PICO_GROW_SHADERS;
00301         if (!_pico_realloc((void *) &model->shader, model->numShaders * sizeof(*model->shader), model->maxShaders
00302                 * sizeof(*model->shader)))
00303             return 0;
00304     }
00305 
00306     /* set shader count to higher */
00307     if (numShaders > model->numShaders)
00308         model->numShaders = numShaders;
00309 
00310     /* additional surfaces? */
00311     while (numSurfaces > model->maxSurfaces) {
00312         model->maxSurfaces += PICO_GROW_SURFACES;
00313         if (!_pico_realloc((void *) &model->surface, model->numSurfaces * sizeof(*model->surface), model->maxSurfaces
00314                 * sizeof(*model->surface)))
00315             return 0;
00316     }
00317 
00318     /* set shader count to higher */
00319     if (numSurfaces > model->numSurfaces)
00320         model->numSurfaces = numSurfaces;
00321 
00322     /* return ok */
00323     return 1;
00324 }
00325 
00329 picoShader_t *PicoNewShader (picoModel_t *model)
00330 {
00331     picoShader_t *shader;
00332 
00333     /* allocate and clear */
00334     shader = _pico_alloc(sizeof(*shader));
00335     if (shader == NULL)
00336         return NULL;
00337     memset(shader, 0, sizeof(*shader));
00338 
00339     /* attach it to the model */
00340     if (model != NULL) {
00341         /* adjust model */
00342         if (!PicoAdjustModel(model, model->numShaders + 1, 0)) {
00343             _pico_free(shader);
00344             return NULL;
00345         }
00346 
00347         /* attach */
00348         model->shader[model->numShaders - 1] = shader;
00349         shader->model = model;
00350     }
00351 
00352     /* setup default shader colors */
00353     _pico_set_color(shader->ambientColor, 0, 0, 0, 0);
00354     _pico_set_color(shader->diffuseColor, 255, 255, 255, 1);
00355     _pico_set_color(shader->specularColor, 0, 0, 0, 0);
00356 
00357     /* no need to do this, but i do it anyway */
00358     shader->transparency = 0;
00359     shader->shininess = 0;
00360 
00361     /* return the newly created shader */
00362     return shader;
00363 }
00364 
00368 void PicoFreeShader (picoShader_t *shader)
00369 {
00370     /* dummy check */
00371     if (shader == NULL)
00372         return;
00373 
00374     /* free bits */
00375     if (shader->name)
00376         _pico_free(shader->name);
00377     if (shader->mapName)
00378         _pico_free(shader->mapName);
00379 
00380     /* free the shader */
00381     _pico_free(shader);
00382 }
00383 
00387 picoShader_t *PicoFindShader (picoModel_t *model, char *name, int caseSensitive)
00388 {
00389     int i;
00390 
00391     /* sanity checks */
00392     if (model == NULL || name == NULL) /* sea: null name fix */
00393         return NULL;
00394 
00395     /* walk list */
00396     for (i = 0; i < model->numShaders; i++) {
00397         /* skip null shaders or shaders with null names */
00398         if (model->shader[i] == NULL || model->shader[i]->name == NULL)
00399             continue;
00400 
00401         /* compare the shader name with name we're looking for */
00402         if (caseSensitive) {
00403             if (!strcmp(name, model->shader[i]->name))
00404                 return model->shader[i];
00405         } else if (!_pico_stricmp(name, model->shader[i]->name))
00406             return model->shader[i];
00407     }
00408 
00409     /* named shader not found */
00410     return NULL;
00411 }
00412 
00416 picoSurface_t *PicoNewSurface (picoModel_t *model)
00417 {
00418     picoSurface_t *surface;
00419     char surfaceName[64];
00420 
00421     /* allocate and clear */
00422     surface = _pico_alloc(sizeof(*surface));
00423     if (surface == NULL)
00424         return NULL;
00425     memset(surface, 0, sizeof(*surface));
00426 
00427     /* attach it to the model */
00428     if (model != NULL) {
00429         /* adjust model */
00430         if (!PicoAdjustModel(model, 0, model->numSurfaces + 1)) {
00431             _pico_free(surface);
00432             return NULL;
00433         }
00434 
00435         /* attach */
00436         model->surface[model->numSurfaces - 1] = surface;
00437         surface->model = model;
00438 
00439         /* set default name */
00440         sprintf(surfaceName, "Unnamed_%d", model->numSurfaces);
00441         PicoSetSurfaceName(surface, surfaceName);
00442     }
00443 
00444     /* return */
00445     return surface;
00446 }
00447 
00451 void PicoFreeSurface (picoSurface_t *surface)
00452 {
00453     int i;
00454 
00455     /* dummy check */
00456     if (surface == NULL)
00457         return;
00458 
00459     /* free bits */
00460     _pico_free(surface->xyz);
00461     _pico_free(surface->normal);
00462     _pico_free(surface->smoothingGroup);
00463     _pico_free(surface->index);
00464     _pico_free(surface->faceNormal);
00465 
00466     if (surface->name)
00467         _pico_free(surface->name);
00468 
00469     /* free arrays */
00470     for (i = 0; i < surface->numSTArrays; i++)
00471         _pico_free(surface->st[i]);
00472     free(surface->st);
00473     for (i = 0; i < surface->numColorArrays; i++)
00474         _pico_free(surface->color[i]);
00475     free(surface->color);
00476 
00477     /* free the surface */
00478     _pico_free(surface);
00479 }
00480 
00485 int PicoAdjustSurface (picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes,
00486         int numFaceNormals)
00487 {
00488     int i;
00489 
00490     /* dummy check */
00491     if (surface == NULL)
00492         return 0;
00493 
00494     /* bare minimums */
00495     if (numVertexes < 1)
00496         numVertexes = 1;
00497     if (numSTArrays < 1)
00498         numSTArrays = 1;
00499     if (numColorArrays < 1)
00500         numColorArrays = 1;
00501     if (numIndexes < 1)
00502         numIndexes = 1;
00503 
00504     /* additional vertexes? */
00505     while (numVertexes > surface->maxVertexes) { /* fix */
00506         surface->maxVertexes += PICO_GROW_VERTEXES;
00507         if (!_pico_realloc((void *) &surface->xyz, surface->numVertexes * sizeof(*surface->xyz), surface->maxVertexes
00508                 * sizeof(*surface->xyz)))
00509             return 0;
00510         if (!_pico_realloc((void *) &surface->normal, surface->numVertexes * sizeof(*surface->normal),
00511                 surface->maxVertexes * sizeof(*surface->normal)))
00512             return 0;
00513         if (!_pico_realloc((void *) &surface->smoothingGroup, surface->numVertexes * sizeof(*surface->smoothingGroup),
00514                 surface->maxVertexes * sizeof(*surface->smoothingGroup)))
00515             return 0;
00516         for (i = 0; i < surface->numSTArrays; i++)
00517             if (!_pico_realloc((void*) &surface->st[i], surface->numVertexes * sizeof(*surface->st[i]),
00518                     surface->maxVertexes * sizeof(*surface->st[i])))
00519                 return 0;
00520         for (i = 0; i < surface->numColorArrays; i++)
00521             if (!_pico_realloc((void*) &surface->color[i], surface->numVertexes * sizeof(*surface->color[i]),
00522                     surface->maxVertexes * sizeof(*surface->color[i])))
00523                 return 0;
00524     }
00525 
00526     /* set vertex count to higher */
00527     if (numVertexes > surface->numVertexes)
00528         surface->numVertexes = numVertexes;
00529 
00530     /* additional st arrays? */
00531     while (numSTArrays > surface->maxSTArrays) { /* fix */
00532         surface->maxSTArrays += PICO_GROW_ARRAYS;
00533         if (!_pico_realloc((void*) &surface->st, surface->numSTArrays * sizeof(*surface->st), surface->maxSTArrays
00534                 * sizeof(*surface->st)))
00535             return 0;
00536         while (surface->numSTArrays < numSTArrays) {
00537             surface->st[surface->numSTArrays] = _pico_alloc(surface->maxVertexes * sizeof(*surface->st[0]));
00538             memset(surface->st[surface->numSTArrays], 0, surface->maxVertexes * sizeof(*surface->st[0]));
00539             surface->numSTArrays++;
00540         }
00541     }
00542 
00543     /* additional color arrays? */
00544     while (numColorArrays > surface->maxColorArrays) { /* fix */
00545         surface->maxColorArrays += PICO_GROW_ARRAYS;
00546         if (!_pico_realloc((void*) &surface->color, surface->numColorArrays * sizeof(*surface->color),
00547                 surface->maxColorArrays * sizeof(*surface->color)))
00548             return 0;
00549         while (surface->numColorArrays < numColorArrays) {
00550             surface->color[surface->numColorArrays] = _pico_alloc(surface->maxVertexes * sizeof(*surface->color[0]));
00551             memset(surface->color[surface->numColorArrays], 0, surface->maxVertexes * sizeof(*surface->color[0]));
00552             surface->numColorArrays++;
00553         }
00554     }
00555 
00556     /* additional indexes? */
00557     while (numIndexes > surface->maxIndexes) { /* fix */
00558         surface->maxIndexes += PICO_GROW_INDEXES;
00559         if (!_pico_realloc((void*) &surface->index, surface->numIndexes * sizeof(*surface->index), surface->maxIndexes
00560                 * sizeof(*surface->index)))
00561             return 0;
00562     }
00563 
00564     /* set index count to higher */
00565     if (numIndexes > surface->numIndexes)
00566         surface->numIndexes = numIndexes;
00567 
00568     /* additional face normals? */
00569     while (numFaceNormals > surface->maxFaceNormals) { /* fix */
00570         surface->maxFaceNormals += PICO_GROW_FACES;
00571         if (!_pico_realloc((void *) &surface->faceNormal, surface->numFaceNormals * sizeof(*surface->faceNormal),
00572                 surface->maxFaceNormals * sizeof(*surface->faceNormal)))
00573             return 0;
00574     }
00575 
00576     /* set face normal count to higher */
00577     if (numFaceNormals > surface->numFaceNormals)
00578         surface->numFaceNormals = numFaceNormals;
00579 
00580     /* return ok */
00581     return 1;
00582 }
00583 
00587 picoSurface_t *PicoFindSurface (picoModel_t *model, char *name, int caseSensitive)
00588 {
00589     int i;
00590 
00591     /* sanity check */
00592     if (model == NULL || name == NULL)
00593         return NULL;
00594 
00595     /* walk list */
00596     for (i = 0; i < model->numSurfaces; i++) {
00597         /* skip null surfaces or surfaces with null names */
00598         if (model->surface[i] == NULL || model->surface[i]->name == NULL)
00599             continue;
00600 
00601         /* compare the surface name with name we're looking for */
00602         if (caseSensitive) {
00603             if (!strcmp(name, model->surface[i]->name))
00604                 return model->surface[i];
00605         } else {
00606             if (!_pico_stricmp(name, model->surface[i]->name))
00607                 return model->surface[i];
00608         }
00609     }
00610     /* named surface not found */
00611     return NULL;
00612 }
00613 
00614 void PicoSetModelName (picoModel_t *model, const char *name)
00615 {
00616     if (model == NULL || name == NULL)
00617         return;
00618     if (model->name != NULL)
00619         _pico_free(model->name);
00620 
00621     model->name = _pico_clone_alloc(name);
00622 }
00623 
00624 void PicoSetModelFileName (picoModel_t *model, const char *fileName)
00625 {
00626     if (model == NULL || fileName == NULL)
00627         return;
00628     if (model->fileName != NULL)
00629         _pico_free(model->fileName);
00630 
00631     model->fileName = _pico_clone_alloc(fileName);
00632 }
00633 
00634 void PicoSetModelFrameNum (picoModel_t *model, int frameNum)
00635 {
00636     if (model == NULL)
00637         return;
00638     model->frameNum = frameNum;
00639 }
00640 
00641 void PicoSetModelNumFrames (picoModel_t *model, int numFrames)
00642 {
00643     if (model == NULL)
00644         return;
00645     model->numFrames = numFrames;
00646 }
00647 
00648 void PicoSetModelData (picoModel_t *model, void *data)
00649 {
00650     if (model == NULL)
00651         return;
00652     model->data = data;
00653 }
00654 
00655 void PicoSetShaderName (picoShader_t *shader, const char *name)
00656 {
00657     if (shader == NULL || name == NULL)
00658         return;
00659     if (shader->name != NULL)
00660         _pico_free(shader->name);
00661 
00662     shader->name = _pico_clone_alloc(name);
00663 }
00664 
00665 void PicoSetShaderMapName (picoShader_t *shader, char *mapName)
00666 {
00667     if (shader == NULL || mapName == NULL)
00668         return;
00669     if (shader->mapName != NULL)
00670         _pico_free(shader->mapName);
00671 
00672     shader->mapName = _pico_clone_alloc(mapName);
00673 }
00674 
00675 void PicoSetShaderAmbientColor (picoShader_t *shader, picoColor_t color)
00676 {
00677     if (shader == NULL || color == NULL)
00678         return;
00679     shader->ambientColor[0] = color[0];
00680     shader->ambientColor[1] = color[1];
00681     shader->ambientColor[2] = color[2];
00682     shader->ambientColor[3] = color[3];
00683 }
00684 
00685 void PicoSetShaderDiffuseColor (picoShader_t *shader, picoColor_t color)
00686 {
00687     if (shader == NULL || color == NULL)
00688         return;
00689     shader->diffuseColor[0] = color[0];
00690     shader->diffuseColor[1] = color[1];
00691     shader->diffuseColor[2] = color[2];
00692     shader->diffuseColor[3] = color[3];
00693 }
00694 
00695 void PicoSetShaderSpecularColor (picoShader_t *shader, picoColor_t color)
00696 {
00697     if (shader == NULL || color == NULL)
00698         return;
00699     shader->specularColor[0] = color[0];
00700     shader->specularColor[1] = color[1];
00701     shader->specularColor[2] = color[2];
00702     shader->specularColor[3] = color[3];
00703 }
00704 
00705 void PicoSetShaderTransparency (picoShader_t *shader, float value)
00706 {
00707     if (shader == NULL)
00708         return;
00709     shader->transparency = value;
00710 
00711     /* cap to 0..1 range */
00712     if (shader->transparency < 0.0)
00713         shader->transparency = 0.0;
00714     if (shader->transparency > 1.0)
00715         shader->transparency = 1.0;
00716 }
00717 
00718 void PicoSetShaderShininess (picoShader_t *shader, float value)
00719 {
00720     if (shader == NULL)
00721         return;
00722     shader->shininess = value;
00723 
00724     /* cap to 0..127 range */
00725     if (shader->shininess < 0.0)
00726         shader->shininess = 0.0;
00727     if (shader->shininess > 127.0)
00728         shader->shininess = 127.0;
00729 }
00730 
00731 void PicoSetSurfaceData (picoSurface_t *surface, void *data)
00732 {
00733     if (surface == NULL)
00734         return;
00735     surface->data = data;
00736 }
00737 
00738 void PicoSetSurfaceType (picoSurface_t *surface, picoSurfaceType_t type)
00739 {
00740     if (surface == NULL)
00741         return;
00742     surface->type = type;
00743 }
00744 
00745 void PicoSetSurfaceName (picoSurface_t *surface, char *name)
00746 {
00747     if (surface == NULL || name == NULL)
00748         return;
00749     if (surface->name != NULL)
00750         _pico_free(surface->name);
00751 
00752     surface->name = _pico_clone_alloc(name);
00753 }
00754 
00755 void PicoSetSurfaceShader (picoSurface_t *surface, picoShader_t *shader)
00756 {
00757     if (surface == NULL)
00758         return;
00759     surface->shader = shader;
00760 }
00761 
00762 void PicoSetSurfaceXYZ (picoSurface_t *surface, int num, picoVec3_t xyz)
00763 {
00764     if (surface == NULL || num < 0 || xyz == NULL)
00765         return;
00766     if (!PicoAdjustSurface(surface, num + 1, 0, 0, 0, 0))
00767         return;
00768     _pico_copy_vec(xyz, surface->xyz[num]);
00769     if (surface->model != NULL)
00770         _pico_expand_bounds(xyz, surface->model->mins, surface->model->maxs);
00771 }
00772 
00773 void PicoSetSurfaceNormal (picoSurface_t *surface, int num, picoVec3_t normal)
00774 {
00775     if (surface == NULL || num < 0 || normal == NULL)
00776         return;
00777     if (!PicoAdjustSurface(surface, num + 1, 0, 0, 0, 0))
00778         return;
00779     _pico_copy_vec(normal, surface->normal[num]);
00780 }
00781 
00782 void PicoSetSurfaceST (picoSurface_t *surface, int array, int num, picoVec2_t st)
00783 {
00784     if (surface == NULL || num < 0 || st == NULL)
00785         return;
00786     if (!PicoAdjustSurface(surface, num + 1, array + 1, 0, 0, 0))
00787         return;
00788     surface->st[array][num][0] = st[0];
00789     surface->st[array][num][1] = st[1];
00790 }
00791 
00792 void PicoSetSurfaceColor (picoSurface_t *surface, int array, int num, const picoColor_t color)
00793 {
00794     if (surface == NULL || num < 0 || color == NULL)
00795         return;
00796     if (!PicoAdjustSurface(surface, num + 1, 0, array + 1, 0, 0))
00797         return;
00798     surface->color[array][num][0] = color[0];
00799     surface->color[array][num][1] = color[1];
00800     surface->color[array][num][2] = color[2];
00801     surface->color[array][num][3] = color[3];
00802 }
00803 
00804 void PicoSetSurfaceIndex (picoSurface_t *surface, int num, picoIndex_t index)
00805 {
00806     if (surface == NULL || num < 0)
00807         return;
00808     if (!PicoAdjustSurface(surface, 0, 0, 0, num + 1, 0))
00809         return;
00810     surface->index[num] = index;
00811 }
00812 
00813 void PicoSetSurfaceIndexes (picoSurface_t *surface, int num, picoIndex_t *index, int count)
00814 {
00815     if (num < 0 || index == NULL || count < 1)
00816         return;
00817     if (!PicoAdjustSurface(surface, 0, 0, 0, num + count, 0))
00818         return;
00819     memcpy(&surface->index[num], index, count * sizeof(surface->index[num]));
00820 }
00821 
00822 void PicoSetFaceNormal (picoSurface_t *surface, int num, picoVec3_t normal)
00823 {
00824     if (surface == NULL || num < 0 || normal == NULL)
00825         return;
00826     if (!PicoAdjustSurface(surface, 0, 0, 0, 0, num + 1))
00827         return;
00828     _pico_copy_vec(normal, surface->faceNormal[num]);
00829 }
00830 
00831 void PicoSetSurfaceSmoothingGroup (picoSurface_t *surface, int num, picoIndex_t smoothingGroup)
00832 {
00833     if (num < 0)
00834         return;
00835     if (!PicoAdjustSurface(surface, num + 1, 0, 0, 0, 0))
00836         return;
00837     surface->smoothingGroup[num] = smoothingGroup;
00838 }
00839 
00840 void PicoSetSurfaceSpecial (picoSurface_t *surface, int num, int special)
00841 {
00842     if (surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL)
00843         return;
00844     surface->special[num] = special;
00845 }
00846 
00847 char *PicoGetModelName (picoModel_t *model)
00848 {
00849     if (model == NULL)
00850         return NULL;
00851     if (model->name == NULL)
00852         return (char*) "";
00853     return model->name;
00854 }
00855 
00856 char *PicoGetModelFileName (picoModel_t *model)
00857 {
00858     if (model == NULL)
00859         return NULL;
00860     if (model->fileName == NULL)
00861         return (char*) "";
00862     return model->fileName;
00863 }
00864 
00865 int PicoGetModelFrameNum (picoModel_t *model)
00866 {
00867     if (model == NULL)
00868         return 0;
00869     return model->frameNum;
00870 }
00871 
00872 int PicoGetModelNumFrames (picoModel_t *model)
00873 {
00874     if (model == NULL)
00875         return 0;
00876     return model->numFrames;
00877 }
00878 
00879 void *PicoGetModelData (picoModel_t *model)
00880 {
00881     if (model == NULL)
00882         return NULL;
00883     return model->data;
00884 }
00885 
00886 int PicoGetModelNumShaders (picoModel_t *model)
00887 {
00888     if (model == NULL)
00889         return 0;
00890     return model->numShaders;
00891 }
00892 
00893 picoShader_t *PicoGetModelShader (picoModel_t *model, int num)
00894 {
00895     /* a few sanity checks */
00896     if (model == NULL)
00897         return NULL;
00898     if (model->shader == NULL)
00899         return NULL;
00900     if (num < 0 || num >= model->numShaders)
00901         return NULL;
00902 
00903     /* return the shader */
00904     return model->shader[num];
00905 }
00906 
00907 int PicoGetModelNumSurfaces (picoModel_t *model)
00908 {
00909     if (model == NULL)
00910         return 0;
00911     return model->numSurfaces;
00912 }
00913 
00914 picoSurface_t *PicoGetModelSurface (picoModel_t *model, int num)
00915 {
00916     /* a few sanity checks */
00917     if (model == NULL)
00918         return NULL;
00919     if (model->surface == NULL)
00920         return NULL;
00921     if (num < 0 || num >= model->numSurfaces)
00922         return NULL;
00923 
00924     /* return the surface */
00925     return model->surface[num];
00926 }
00927 
00928 int PicoGetModelTotalVertexes (picoModel_t *model)
00929 {
00930     int i, count;
00931 
00932     if (model == NULL)
00933         return 0;
00934     if (model->surface == NULL)
00935         return 0;
00936 
00937     count = 0;
00938     for (i = 0; i < model->numSurfaces; i++)
00939         count += PicoGetSurfaceNumVertexes(model->surface[i]);
00940 
00941     return count;
00942 }
00943 
00944 int PicoGetModelTotalIndexes (picoModel_t *model)
00945 {
00946     int i, count;
00947 
00948     if (model == NULL)
00949         return 0;
00950     if (model->surface == NULL)
00951         return 0;
00952 
00953     count = 0;
00954     for (i = 0; i < model->numSurfaces; i++)
00955         count += PicoGetSurfaceNumIndexes(model->surface[i]);
00956 
00957     return count;
00958 }
00959 
00960 char *PicoGetShaderName (picoShader_t *shader)
00961 {
00962     if (shader == NULL)
00963         return NULL;
00964     if (shader->name == NULL)
00965         return (char*) "";
00966     return shader->name;
00967 }
00968 
00969 char *PicoGetShaderMapName (picoShader_t *shader)
00970 {
00971     if (shader == NULL)
00972         return NULL;
00973     if (shader->mapName == NULL)
00974         return (char*) "";
00975     return shader->mapName;
00976 }
00977 
00978 picoByte_t *PicoGetShaderAmbientColor (picoShader_t *shader)
00979 {
00980     if (shader == NULL)
00981         return NULL;
00982     return shader->ambientColor;
00983 }
00984 
00985 picoByte_t *PicoGetShaderDiffuseColor (picoShader_t *shader)
00986 {
00987     if (shader == NULL)
00988         return NULL;
00989     return shader->diffuseColor;
00990 }
00991 
00992 picoByte_t *PicoGetShaderSpecularColor (picoShader_t *shader)
00993 {
00994     if (shader == NULL)
00995         return NULL;
00996     return shader->specularColor;
00997 }
00998 
00999 float PicoGetShaderTransparency (picoShader_t *shader)
01000 {
01001     if (shader == NULL)
01002         return 0.0f;
01003     return shader->transparency;
01004 }
01005 
01006 float PicoGetShaderShininess (picoShader_t *shader)
01007 {
01008     if (shader == NULL)
01009         return 0.0f;
01010     return shader->shininess;
01011 }
01012 
01013 void *PicoGetSurfaceData (picoSurface_t *surface)
01014 {
01015     if (surface == NULL)
01016         return NULL;
01017     return surface->data;
01018 }
01019 
01020 picoSurfaceType_t PicoGetSurfaceType (picoSurface_t *surface)
01021 {
01022     if (surface == NULL)
01023         return PICO_BAD;
01024     return surface->type;
01025 }
01026 
01027 char *PicoGetSurfaceName (picoSurface_t *surface)
01028 {
01029     if (surface == NULL)
01030         return NULL;
01031     if (surface->name == NULL)
01032         return (char*) "";
01033     return surface->name;
01034 }
01035 
01036 picoShader_t *PicoGetSurfaceShader (picoSurface_t *surface)
01037 {
01038     if (surface == NULL)
01039         return NULL;
01040     return surface->shader;
01041 }
01042 
01043 int PicoGetSurfaceNumVertexes (picoSurface_t *surface)
01044 {
01045     if (surface == NULL)
01046         return 0;
01047     return surface->numVertexes;
01048 }
01049 
01050 picoVec_t *PicoGetSurfaceXYZ (picoSurface_t *surface, int num)
01051 {
01052     if (surface == NULL || num < 0 || num > surface->numVertexes)
01053         return NULL;
01054     return surface->xyz[num];
01055 }
01056 
01057 picoVec_t *PicoGetSurfaceNormal (picoSurface_t *surface, int num)
01058 {
01059     if (surface == NULL || num < 0 || num > surface->numVertexes)
01060         return NULL;
01061     return surface->normal[num];
01062 }
01063 
01064 picoVec_t *PicoGetSurfaceST (picoSurface_t *surface, int array, int num)
01065 {
01066     if (surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes)
01067         return NULL;
01068     return surface->st[array][num];
01069 }
01070 
01071 picoByte_t *PicoGetSurfaceColor (picoSurface_t *surface, int array, int num)
01072 {
01073     if (surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes)
01074         return NULL;
01075     return surface->color[array][num];
01076 }
01077 
01078 int PicoGetSurfaceNumIndexes (picoSurface_t *surface)
01079 {
01080     if (surface == NULL)
01081         return 0;
01082     return surface->numIndexes;
01083 }
01084 
01085 picoIndex_t PicoGetSurfaceIndex (picoSurface_t *surface, int num)
01086 {
01087     if (surface == NULL || num < 0 || num > surface->numIndexes)
01088         return 0;
01089     return surface->index[num];
01090 }
01091 
01092 picoIndex_t *PicoGetSurfaceIndexes (picoSurface_t *surface, int num)
01093 {
01094     if (surface == NULL || num < 0 || num > surface->numIndexes)
01095         return NULL;
01096     return &surface->index[num];
01097 }
01098 
01099 picoVec_t *PicoGetFaceNormal (picoSurface_t *surface, int num)
01100 {
01101     if (surface == NULL || num < 0 || num > surface->numFaceNormals)
01102         return NULL;
01103     return surface->faceNormal[num];
01104 }
01105 
01106 int PicoGetSurfaceSpecial (picoSurface_t *surface, int num)
01107 {
01108     if (surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL)
01109         return 0;
01110     return surface->special[num];
01111 }
01112 
01113 /* ----------------------------------------------------------------------------
01114  hashtable related functions
01115  ---------------------------------------------------------------------------- */
01116 
01117 /* hashtable code for faster vertex lookups */
01118 /* power of 2, use & */
01119 /*#define HASHTABLE_SIZE 32768 */
01120 /* prime, use % */
01121 #define HASHTABLE_SIZE 7919
01122 #define HASH_XYZ_EPSILON                    0.01f
01123 #define HASH_XYZ_EPSILONSPACE_MULTIPLIER    1.f / HASH_XYZ_EPSILON
01124 #define HASH_ST_EPSILON                     0.0001f
01125 #define HASH_NORMAL_EPSILON                 0.02f
01126 
01127 unsigned int PicoVertexCoordGenerateHash (picoVec3_t xyz)
01128 {
01129     unsigned int hash = 0;
01130 
01131     picoVec3_t xyz_epsilonspace;
01132 
01133     _pico_scale_vec(xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace);
01134     xyz_epsilonspace[0] = (float) floor(xyz_epsilonspace[0]);
01135     xyz_epsilonspace[1] = (float) floor(xyz_epsilonspace[1]);
01136     xyz_epsilonspace[2] = (float) floor(xyz_epsilonspace[2]);
01137 
01138     hash += ~(*((unsigned int*) &xyz_epsilonspace[0]) << 15);
01139     hash ^= (*((unsigned int*) &xyz_epsilonspace[0]) >> 10);
01140     hash += (*((unsigned int*) &xyz_epsilonspace[1]) << 3);
01141     hash ^= (*((unsigned int*) &xyz_epsilonspace[1]) >> 6);
01142     hash += ~(*((unsigned int*) &xyz_epsilonspace[2]) << 11);
01143     hash ^= (*((unsigned int*) &xyz_epsilonspace[2]) >> 16);
01144 
01145     /* hash = hash & (HASHTABLE_SIZE-1); */
01146     hash = hash % (HASHTABLE_SIZE);
01147     return hash;
01148 }
01149 
01150 picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable (void)
01151 {
01152     picoVertexCombinationHash_t **hashTable = _pico_alloc(HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*));
01153 
01154     memset(hashTable, 0, HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*));
01155 
01156     return hashTable;
01157 }
01158 
01159 void PicoFreeVertexCombinationHashTable (picoVertexCombinationHash_t **hashTable)
01160 {
01161     int i;
01162     picoVertexCombinationHash_t *vertexCombinationHash;
01163     picoVertexCombinationHash_t *nextVertexCombinationHash;
01164 
01165     /* dummy check */
01166     if (hashTable == NULL)
01167         return;
01168 
01169     for (i = 0; i < HASHTABLE_SIZE; i++) {
01170         if (hashTable[i]) {
01171             nextVertexCombinationHash = NULL;
01172 
01173             for (vertexCombinationHash = hashTable[i]; vertexCombinationHash; vertexCombinationHash
01174                     = nextVertexCombinationHash) {
01175                 nextVertexCombinationHash = vertexCombinationHash->next;
01176                 if (vertexCombinationHash->data != NULL) {
01177                     _pico_free(vertexCombinationHash->data);
01178                 }
01179                 _pico_free(vertexCombinationHash);
01180             }
01181         }
01182     }
01183 
01184     _pico_free(hashTable);
01185 }
01186 
01187 picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable (picoVertexCombinationHash_t **hashTable,
01188         picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color)
01189 {
01190     unsigned int hash;
01191     picoVertexCombinationHash_t *vertexCombinationHash;
01192 
01193     /* dumy check */
01194     if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL)
01195         return NULL;
01196 
01197     hash = PicoVertexCoordGenerateHash(xyz);
01198 
01199     for (vertexCombinationHash = hashTable[hash]; vertexCombinationHash; vertexCombinationHash
01200             = vertexCombinationHash->next) {
01201         /* check xyz */
01202         if ((fabs(xyz[0] - vertexCombinationHash->vcd.xyz[0])) > HASH_XYZ_EPSILON || (fabs(xyz[1]
01203                 - vertexCombinationHash->vcd.xyz[1])) > HASH_XYZ_EPSILON || (fabs(xyz[2]
01204                 - vertexCombinationHash->vcd.xyz[2])) > HASH_XYZ_EPSILON)
01205             continue;
01206 
01207         /* check normal */
01208         if ((fabs(normal[0] - vertexCombinationHash->vcd.normal[0])) > HASH_NORMAL_EPSILON || (fabs(normal[1]
01209                 - vertexCombinationHash->vcd.normal[1])) > HASH_NORMAL_EPSILON || (fabs(normal[2]
01210                 - vertexCombinationHash->vcd.normal[2])) > HASH_NORMAL_EPSILON)
01211             continue;
01212 
01213         /* check st */
01214         if ((fabs(st[0] - vertexCombinationHash->vcd.st[0])) > HASH_ST_EPSILON || (fabs(st[1]
01215                 - vertexCombinationHash->vcd.st[1])) > HASH_ST_EPSILON)
01216             continue;
01217 
01218         /* check color */
01219         if (*((int*) vertexCombinationHash->vcd.color) != *((int*) color))
01220             continue;
01221 
01222         /* gotcha */
01223         return vertexCombinationHash;
01224     }
01225 
01226     return NULL;
01227 }
01228 
01229 picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable (picoVertexCombinationHash_t **hashTable,
01230         picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index)
01231 {
01232     unsigned int hash;
01233     picoVertexCombinationHash_t *vertexCombinationHash;
01234 
01235     /* dumy check */
01236     if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL)
01237         return NULL;
01238 
01239     vertexCombinationHash = _pico_alloc(sizeof(picoVertexCombinationHash_t));
01240 
01241     if (!vertexCombinationHash)
01242         return NULL;
01243 
01244     hash = PicoVertexCoordGenerateHash(xyz);
01245 
01246     _pico_copy_vec(xyz, vertexCombinationHash->vcd.xyz);
01247     _pico_copy_vec(normal, vertexCombinationHash->vcd.normal);
01248     _pico_copy_vec2(st, vertexCombinationHash->vcd.st);
01249     _pico_copy_color(color, vertexCombinationHash->vcd.color);
01250     vertexCombinationHash->index = index;
01251     vertexCombinationHash->data = NULL;
01252     vertexCombinationHash->next = hashTable[hash];
01253     hashTable[hash] = vertexCombinationHash;
01254 
01255     return vertexCombinationHash;
01256 }
01257 
01262 int PicoFindSurfaceVertexNum (picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st,
01263         int numColors, picoColor_t *color, picoIndex_t smoothingGroup)
01264 {
01265     int i, j;
01266 
01267     /* dummy check */
01268     if (surface == NULL || surface->numVertexes <= 0)
01269         return -1;
01270 
01271     /* walk vertex list */
01272     for (i = 0; i < surface->numVertexes; i++) {
01273         /* check xyz */
01274         if (xyz != NULL && (surface->xyz[i][0] != xyz[0] || surface->xyz[i][1] != xyz[1] || surface->xyz[i][2]
01275                 != xyz[2]))
01276             continue;
01277 
01278         /* check normal */
01279         if (normal != NULL && (surface->normal[i][0] != normal[0] || surface->normal[i][1] != normal[1]
01280                 || surface->normal[i][2] != normal[2]))
01281             continue;
01282 
01283         /* check normal */
01284         if (surface->smoothingGroup[i] != smoothingGroup)
01285             continue;
01286 
01287         /* check st */
01288         if (numSTs > 0 && st != NULL) {
01289             for (j = 0; j < numSTs; j++) {
01290                 if (surface->st[j][i][0] != st[j][0] || surface->st[j][i][1] != st[j][1])
01291                     break;
01292             }
01293             if (j != numSTs)
01294                 continue;
01295         }
01296 
01297         /* check color */
01298         if (numColors > 0 && color != NULL) {
01299             for (j = 0; j < numSTs; j++) {
01300                 if (*((int*) surface->color[j]) != *((int*) color[j]))
01301                     break;
01302             }
01303             if (j != numColors)
01304                 continue;
01305         }
01306 
01307         /* vertex matches */
01308         return i;
01309     }
01310 
01311     /* nada */
01312     return -1;
01313 }
01314 
01315 typedef struct _IndexArray
01316 {
01317     picoIndex_t* data;
01318     picoIndex_t* last;
01319 } IndexArray;
01320 
01321 static void indexarray_push_back (IndexArray* self, picoIndex_t value)
01322 {
01323     *self->last++ = value;
01324 }
01325 
01326 static void indexarray_reserve (IndexArray* self, size_t size)
01327 {
01328     self->data = self->last = _pico_calloc(size, sizeof(picoIndex_t));
01329 }
01330 
01331 static void indexarray_clear (IndexArray* self)
01332 {
01333     _pico_free(self->data);
01334 }
01335 
01336 typedef struct _BinaryTreeNode
01337 {
01338     picoIndex_t left;
01339     picoIndex_t right;
01340 } BinaryTreeNode;
01341 
01342 typedef struct _BinaryTree
01343 {
01344     BinaryTreeNode* data;
01345     BinaryTreeNode* last;
01346 } BinaryTree;
01347 
01348 static void binarytree_extend (BinaryTree* self)
01349 {
01350     self->last->left = 0;
01351     self->last->right = 0;
01352     ++self->last;
01353 }
01354 
01355 static size_t binarytree_size (BinaryTree* self)
01356 {
01357     return self->last - self->data;
01358 }
01359 
01360 static void binarytree_reserve (BinaryTree* self, size_t size)
01361 {
01362     self->data = self->last = _pico_calloc(size, sizeof(BinaryTreeNode));
01363 }
01364 
01365 static void binarytree_clear (BinaryTree* self)
01366 {
01367     _pico_free(self->data);
01368 }
01369 
01370 typedef int (*LessFunc) (void*, picoIndex_t, picoIndex_t);
01371 
01372 typedef struct _UniqueIndices
01373 {
01374     BinaryTree tree;
01375     IndexArray indices;
01376     LessFunc lessFunc;
01377     void* lessData;
01378 } UniqueIndices;
01379 
01380 static size_t UniqueIndices_size (UniqueIndices* self)
01381 {
01382     return binarytree_size(&self->tree);
01383 }
01384 
01385 static void UniqueIndices_reserve (UniqueIndices* self, size_t size)
01386 {
01387     binarytree_reserve(&self->tree, size);
01388     indexarray_reserve(&self->indices, size);
01389 }
01390 
01391 static void UniqueIndices_init (UniqueIndices* self, LessFunc lessFunc, void* lessData)
01392 {
01393     self->lessFunc = lessFunc;
01394     self->lessData = lessData;
01395 }
01396 
01397 static void UniqueIndices_destroy (UniqueIndices* self)
01398 {
01399     binarytree_clear(&self->tree);
01400     indexarray_clear(&self->indices);
01401 }
01402 
01403 static picoIndex_t UniqueIndices_find_or_insert (UniqueIndices* self, picoIndex_t value)
01404 {
01405     picoIndex_t index = 0;
01406 
01407     for (;;) {
01408         if (self->lessFunc(self->lessData, value, self->indices.data[index])) {
01409             BinaryTreeNode* node = self->tree.data + index;
01410             if (node->left != 0) {
01411                 index = node->left;
01412                 continue;
01413             } else {
01414                 node->left = (picoIndex_t) binarytree_size(&self->tree);
01415                 binarytree_extend(&self->tree);
01416                 indexarray_push_back(&self->indices, value);
01417                 return node->left;
01418             }
01419         }
01420         if (self->lessFunc(self->lessData, self->indices.data[index], value)) {
01421             BinaryTreeNode* node = self->tree.data + index;
01422             if (node->right != 0) {
01423                 index = node->right;
01424                 continue;
01425             } else {
01426                 node->right = (picoIndex_t) binarytree_size(&self->tree);
01427                 binarytree_extend(&self->tree);
01428                 indexarray_push_back(&self->indices, value);
01429                 return node->right;
01430             }
01431         }
01432 
01433         return index;
01434     }
01435 }
01436 
01437 static picoIndex_t UniqueIndices_insert (UniqueIndices* self, picoIndex_t value)
01438 {
01439     if (self->tree.data == self->tree.last) {
01440         binarytree_extend(&self->tree);
01441         indexarray_push_back(&self->indices, value);
01442         return 0;
01443     } else {
01444         return UniqueIndices_find_or_insert(self, value);
01445     }
01446 }
01447 
01448 typedef struct picoSmoothVertices_s
01449 {
01450     picoVec3_t* xyz;
01451     picoIndex_t* smoothingGroups;
01452 } picoSmoothVertices_t;
01453 
01454 static int lessSmoothVertex (void* data, picoIndex_t first, picoIndex_t second)
01455 {
01456     picoSmoothVertices_t* smoothVertices = data;
01457 
01458     if (smoothVertices->xyz[first][0] != smoothVertices->xyz[second][0])
01459         return smoothVertices->xyz[first][0] < smoothVertices->xyz[second][0];
01460     if (smoothVertices->xyz[first][1] != smoothVertices->xyz[second][1])
01461         return smoothVertices->xyz[first][1] < smoothVertices->xyz[second][1];
01462     if (smoothVertices->xyz[first][2] != smoothVertices->xyz[second][2])
01463         return smoothVertices->xyz[first][2] < smoothVertices->xyz[second][2];
01464     if (smoothVertices->smoothingGroups[first] != smoothVertices->smoothingGroups[second])
01465         return smoothVertices->smoothingGroups[first] < smoothVertices->smoothingGroups[second];
01466     return 0;
01467 }
01468 
01469 static void _pico_vertices_combine_shared_normals (picoVec3_t* xyz, picoIndex_t* smoothingGroups, picoVec3_t* normals,
01470         picoIndex_t numVertices)
01471 {
01472     UniqueIndices vertices;
01473     IndexArray indices;
01474     picoSmoothVertices_t smoothVertices = { xyz, smoothingGroups };
01475     UniqueIndices_init(&vertices, lessSmoothVertex, &smoothVertices);
01476     UniqueIndices_reserve(&vertices, numVertices);
01477     indexarray_reserve(&indices, numVertices);
01478 
01479     {
01480         picoIndex_t i = 0;
01481         for (; i < numVertices; ++i) {
01482             size_t size = UniqueIndices_size(&vertices);
01483             picoIndex_t index = UniqueIndices_insert(&vertices, i);
01484             if ((size_t) index != size) {
01485                 float* normal = normals[vertices.indices.data[index]];
01486                 _pico_add_vec(normal, normals[i], normal);
01487             }
01488             indexarray_push_back(&indices, index);
01489         }
01490     }
01491 
01492     {
01493         picoIndex_t maxIndex = 0;
01494         picoIndex_t* i = indices.data;
01495         for (; i != indices.last; ++i) {
01496             if (*i <= maxIndex) {
01497                 _pico_copy_vec(normals[vertices.indices.data[*i]], normals[i - indices.data]);
01498             } else {
01499                 maxIndex = *i;
01500             }
01501         }
01502     }
01503 
01504     UniqueIndices_destroy(&vertices);
01505     indexarray_clear(&indices);
01506 }
01507 
01508 typedef picoVec3_t* picoNormalIter_t;
01509 typedef picoIndex_t* picoIndexIter_t;
01510 
01511 static void _pico_triangles_generate_weighted_normals (picoIndexIter_t first, picoIndexIter_t end, picoVec3_t* xyz,
01512         picoVec3_t* normals)
01513 {
01514     for (; first != end; first += 3) {
01515         picoVec3_t weightedNormal;
01516         {
01517             float* a = xyz[*(first + 0)];
01518             float* b = xyz[*(first + 1)];
01519             float* c = xyz[*(first + 2)];
01520             picoVec3_t ba, ca;
01521             _pico_subtract_vec(b, a, ba);
01522             _pico_subtract_vec(c, a, ca);
01523             _pico_cross_vec(ca, ba, weightedNormal);
01524         }
01525         {
01526             int j = 0;
01527             for (; j < 3; ++j) {
01528                 float* normal = normals[*(first + j)];
01529                 _pico_add_vec(weightedNormal, normal, normal);
01530             }
01531         }
01532     }
01533 }
01534 
01535 static void _pico_normals_zero (picoNormalIter_t first, picoNormalIter_t last)
01536 {
01537     for (; first != last; ++first) {
01538         _pico_zero_vec(*first);
01539     }
01540 }
01541 
01542 static void _pico_normals_normalize (picoNormalIter_t first, picoNormalIter_t last)
01543 {
01544     for (; first != last; ++first) {
01545         _pico_normalize_vec(*first);
01546     }
01547 }
01548 
01549 static double _pico_length_vec (picoVec3_t vec)
01550 {
01551     return sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
01552 }
01553 
01554 #define NORMAL_UNIT_LENGTH_EPSILON 0.01
01555 #define FLOAT_EQUAL_EPSILON(f, other, epsilon) (fabs(f - other) < epsilon)
01556 
01557 static int _pico_normal_is_unit_length (picoVec3_t normal)
01558 {
01559     return FLOAT_EQUAL_EPSILON(_pico_length_vec(normal), 1.0, NORMAL_UNIT_LENGTH_EPSILON);
01560 }
01561 
01562 static int _pico_normal_within_tolerance (picoVec3_t normal, picoVec3_t other)
01563 {
01564     return _pico_dot_vec(normal, other) > 0.0f;
01565 }
01566 
01567 static void _pico_normals_assign_generated_normals (picoNormalIter_t first, picoNormalIter_t last,
01568         picoNormalIter_t generated)
01569 {
01570     for (; first != last; ++first, ++generated) {
01571         if (!_pico_normal_is_unit_length(*first) || !_pico_normal_within_tolerance(*first, *generated)) {
01572             _pico_copy_vec(*generated, *first);
01573         }
01574     }
01575 }
01576 
01577 void PicoFixSurfaceNormals (picoSurface_t* surface)
01578 {
01579     picoVec3_t* normals = (picoVec3_t*) _pico_calloc(surface->numVertexes, sizeof(picoVec3_t));
01580 
01581     _pico_normals_zero(normals, normals + surface->numVertexes);
01582 
01583     _pico_triangles_generate_weighted_normals(surface->index, surface->index + surface->numIndexes, surface->xyz,
01584             normals);
01585     _pico_vertices_combine_shared_normals(surface->xyz, surface->smoothingGroup, normals, surface->numVertexes);
01586 
01587     _pico_normals_normalize(normals, normals + surface->numVertexes);
01588 
01589     _pico_normals_assign_generated_normals(surface->normal, surface->normal + surface->numVertexes, normals);
01590 
01591     _pico_free(normals);
01592 }
01593 
01598 void PicoAddTriangleToModel (picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, int numSTs, picoVec2_t **st,
01599         int numColors, picoColor_t **colors, picoShader_t* shader, picoIndex_t* smoothingGroup)
01600 {
01601     int i, j;
01602     int vertDataIndex;
01603     picoSurface_t* workSurface = NULL;
01604 
01605     /* see if a surface already has the shader */
01606     for (i = 0; i < model->numSurfaces; i++) {
01607         workSurface = model->surface[i];
01608         if (workSurface->shader == shader) {
01609             break;
01610         }
01611     }
01612 
01613     /* no surface uses this shader yet, so create a new surface */
01614     if (!workSurface || i >= model->numSurfaces) {
01615         /* create a new surface in the model for the unique shader */
01616         workSurface = PicoNewSurface(model);
01617         if (!workSurface) {
01618             _pico_printf(PICO_ERROR, "Could not allocate a new surface!\n");
01619             return;
01620         }
01621 
01622         /* do surface setup */
01623         PicoSetSurfaceType(workSurface, PICO_TRIANGLES);
01624         PicoSetSurfaceName(workSurface, shader->name);
01625         PicoSetSurfaceShader(workSurface, shader);
01626     }
01627 
01628     /* add the triangle data to the surface */
01629     for (i = 0; i < 3; i++) {
01630         /* get the next free spot in the index array */
01631         int newVertIndex = PicoGetSurfaceNumIndexes(workSurface);
01632 
01633         /* get the index of the vertex that we're going to store at newVertIndex */
01634         vertDataIndex = PicoFindSurfaceVertexNum(workSurface, *xyz[i], *normals[i], numSTs, st[i], numColors,
01635                 colors[i], smoothingGroup[i]);
01636 
01637         /* the vertex wasn't found, so create a new vertex in the pool from the data we have */
01638         if (vertDataIndex == -1) {
01639             /* find the next spot for a new vertex */
01640             vertDataIndex = PicoGetSurfaceNumVertexes(workSurface);
01641 
01642             /* assign the data to it */
01643             PicoSetSurfaceXYZ(workSurface, vertDataIndex, *xyz[i]);
01644             PicoSetSurfaceNormal(workSurface, vertDataIndex, *normals[i]);
01645 
01646             /* make sure to copy over all available ST's and colors for the vertex */
01647             for (j = 0; j < numColors; j++) {
01648                 PicoSetSurfaceColor(workSurface, j, vertDataIndex, colors[i][j]);
01649             }
01650             for (j = 0; j < numSTs; j++) {
01651                 PicoSetSurfaceST(workSurface, j, vertDataIndex, st[i][j]);
01652             }
01653 
01654             PicoSetSurfaceSmoothingGroup(workSurface, vertDataIndex, smoothingGroup[i]);
01655         }
01656 
01657         /* add this vertex to the triangle */
01658         PicoSetSurfaceIndex(workSurface, newVertIndex, vertDataIndex);
01659     }
01660 }

Generated by  doxygen 1.6.2