Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

modelfile.cpp

Go to the documentation of this file.
00001 // modelfile.cpp
00002 //
00003 // Copyright (C) 2004, Chris Laurel <claurel@shatters.net>
00004 //
00005 // This program is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU General Public License
00007 // as published by the Free Software Foundation; either version 2
00008 // of the License, or (at your option) any later version.
00009 
00010 #include "modelfile.h"
00011 #include "tokenizer.h"
00012 #include "texmanager.h"
00013 #include <celutil/bytes.h>
00014 #include <cstring>
00015 #include <cassert>
00016 #include <cmath>
00017 #include <cstdio>
00018 
00019 using namespace std;
00020 
00021 
00022 
00023 // Material default values
00024 static Color DefaultDiffuse(0.0f, 0.0f, 0.0f);
00025 static Color DefaultSpecular(0.0f, 0.0f, 0.0f);
00026 static Color DefaultEmissive(0.0f, 0.0f, 0.0f);
00027 static float DefaultSpecularPower = 1.0f;
00028 static float DefaultOpacity = 1.0f;
00029 
00030 
00095 class AsciiModelLoader : public ModelLoader
00096 {
00097 public:
00098     AsciiModelLoader(istream& _in);
00099     ~AsciiModelLoader();
00100 
00101     virtual Model* load();
00102     virtual void reportError(const string&);
00103 
00104     Mesh::Material*          loadMaterial();
00105     Mesh::VertexDescription* loadVertexDescription();
00106     Mesh*                    loadMesh();
00107     char*                    loadVertices(const Mesh::VertexDescription& vertexDesc,
00108                                           uint32& vertexCount);
00109 
00110 private:
00111     Tokenizer tok;
00112 };
00113 
00114 
00115 class AsciiModelWriter : public ModelWriter
00116 {
00117 public:
00118     AsciiModelWriter(ostream&);
00119     ~AsciiModelWriter();
00120 
00121     virtual bool write(const Model&);
00122 
00123 private:
00124     void writeMesh(const Mesh&);
00125     void writeMaterial(const Mesh::Material&);
00126     void writeGroup(const Mesh::PrimitiveGroup&);
00127     void writeVertexDescription(const Mesh::VertexDescription&);
00128     void writeVertices(const void* vertexData,
00129                        uint32 nVertices,
00130                        uint32 stride,
00131                        const Mesh::VertexDescription& desc);
00132     
00133     ostream& out;
00134 };
00135 
00136 
00137 class BinaryModelLoader : public ModelLoader
00138 {
00139 public:
00140     BinaryModelLoader(istream& _in);
00141     ~BinaryModelLoader();
00142 
00143     virtual Model* load();
00144     virtual void reportError(const string&);
00145 
00146     Mesh::Material*          loadMaterial();
00147     Mesh::VertexDescription* loadVertexDescription();
00148     Mesh*                    loadMesh();
00149     char*                    loadVertices(const Mesh::VertexDescription& vertexDesc,
00150                                           uint32& vertexCount);
00151 
00152 private:
00153     istream& in;
00154 };
00155 
00156 
00157 class BinaryModelWriter : public ModelWriter
00158 {
00159 public:
00160     BinaryModelWriter(ostream&);
00161     ~BinaryModelWriter();
00162 
00163     virtual bool write(const Model&);
00164 
00165 private:
00166     void writeMesh(const Mesh&);
00167     void writeMaterial(const Mesh::Material&);
00168     void writeGroup(const Mesh::PrimitiveGroup&);
00169     void writeVertexDescription(const Mesh::VertexDescription&);
00170     void writeVertices(const void* vertexData,
00171                        uint32 nVertices,
00172                        uint32 stride,
00173                        const Mesh::VertexDescription& desc);
00174     
00175     ostream& out;
00176 };
00177 
00178 
00179 ModelLoader::ModelLoader()
00180 {
00181 }
00182 
00183 
00184 ModelLoader::~ModelLoader()
00185 {
00186 }
00187 
00188 
00189 void
00190 ModelLoader::reportError(const string& msg)
00191 {
00192     errorMessage = msg;
00193 }
00194 
00195 
00196 const string& 
00197 ModelLoader::getErrorMessage() const
00198 {
00199     return errorMessage;
00200 }
00201 
00202 
00203 void
00204 ModelLoader::setTexturePath(const string& _texPath)
00205 {
00206     texPath = _texPath;
00207 }
00208 
00209 
00210 const string&
00211 ModelLoader::getTexturePath() const
00212 {
00213     return texPath;
00214 }
00215 
00216 
00217 Model* LoadModel(istream& in)
00218 {
00219     return LoadModel(in, "");
00220 }
00221 
00222 
00223 Model* LoadModel(istream& in, const string& texPath)
00224 {
00225     ModelLoader* loader = ModelLoader::OpenModel(in);
00226     if (loader == NULL)
00227         return NULL;
00228 
00229     loader->setTexturePath(texPath);
00230 
00231     Model* model = loader->load();
00232     if (model == NULL)
00233         cerr << "Error in model file: " << loader->getErrorMessage() << '\n';
00234 
00235     delete loader;
00236 
00237     return model;
00238 }
00239 
00240 
00241 ModelLoader*
00242 ModelLoader::OpenModel(istream& in)
00243 {
00244     char header[CEL_MODEL_HEADER_LENGTH + 1];
00245     memset(header, '\0', sizeof(header));
00246 
00247     in.read(header, CEL_MODEL_HEADER_LENGTH);
00248     if (strcmp(header, CEL_MODEL_HEADER_ASCII) == 0)
00249     {
00250         return new AsciiModelLoader(in);
00251     }
00252     else if (strcmp(header, CEL_MODEL_HEADER_BINARY) == 0)
00253     {
00254         return new BinaryModelLoader(in);
00255     }
00256     else
00257     {
00258         cerr << "Model file has invalid header.\n";
00259         return NULL;
00260     }
00261 }
00262 
00263 
00264 bool SaveModelAscii(const Model* model, std::ostream& out)
00265 {
00266     if (model == NULL)
00267         return false;
00268 
00269     AsciiModelWriter(out).write(*model);
00270 
00271     return true;
00272 }
00273 
00274 
00275 bool SaveModelBinary(const Model* model, std::ostream& out)
00276 {
00277     if (model == NULL)
00278         return false;
00279 
00280     BinaryModelWriter(out).write(*model);
00281 
00282     return true;
00283 }
00284 
00285 
00286 AsciiModelLoader::AsciiModelLoader(istream& _in) :
00287     tok(&_in)
00288 {
00289 }
00290 
00291 
00292 AsciiModelLoader::~AsciiModelLoader()
00293 {
00294 }
00295 
00296 
00297 void
00298 AsciiModelLoader::reportError(const string& msg)
00299 {
00300     char buf[32];
00301     sprintf(buf, " (line %d)", tok.getLineNumber());
00302     ModelLoader::reportError(msg + string(buf));
00303 }
00304 
00305 
00306 Mesh::Material*
00307 AsciiModelLoader::loadMaterial()
00308 {
00309     if (tok.nextToken() != Tokenizer::TokenName ||
00310         tok.getNameValue() != "material")
00311     {
00312         reportError("Material definition expected");
00313         return NULL;
00314     }
00315 
00316     Mesh::Material* material = new Mesh::Material();
00317 
00318     material->diffuse = DefaultDiffuse;
00319     material->specular = DefaultSpecular;
00320     material->emissive = DefaultEmissive;
00321     material->specularPower = DefaultSpecularPower;
00322     material->opacity = DefaultOpacity;
00323 
00324     while (tok.nextToken() == Tokenizer::TokenName &&
00325            tok.getNameValue() != "end_material")
00326     {
00327         string property = tok.getNameValue();
00328         Mesh::TextureSemantic texType = Mesh::parseTextureSemantic(property);
00329 
00330         if (texType != Mesh::InvalidTextureSemantic)
00331         {
00332             if (tok.nextToken() != Tokenizer::TokenString)
00333             {
00334                 reportError("Texture name expected");
00335                 delete material;
00336                 return NULL;
00337             }
00338 
00339             ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(tok.getStringValue(), getTexturePath(), TextureInfo::WrapTexture));
00340 
00341             material->maps[texType] = tex;
00342         }
00343         else
00344         {
00345             // All non-texture material properties are 3-vectors except
00346             // specular power and opacity
00347             double data[3];
00348             int nValues = 3;
00349             if (property == "specpower" || property == "opacity")
00350                 nValues = 1;
00351 
00352             for (int i = 0; i < nValues; i++)
00353             {
00354                 if (tok.nextToken() != Tokenizer::TokenNumber)
00355                 {
00356                     reportError("Bad property value in material");
00357                     delete material;
00358                     return NULL;
00359                 }
00360                 data[i] = tok.getNumberValue();
00361             }
00362 
00363             Color colorVal;
00364             if (nValues == 3)
00365                 colorVal = Color((float) data[0], (float) data[1], (float) data[2]);
00366             
00367             if (property == "diffuse")
00368                 material->diffuse = colorVal;
00369             else if (property == "specular")
00370                 material->specular = colorVal;
00371             else if (property == "emissive")
00372                 material->emissive = colorVal;
00373             else if (property == "opacity")
00374                 material->opacity = (float) data[0];
00375             else if (property == "specpower")
00376                 material->specularPower = (float) data[0];
00377         }
00378     }    
00379 
00380     if (tok.getTokenType() != Tokenizer::TokenName)
00381     {
00382         delete material;
00383         return NULL;
00384     }
00385     else
00386     {
00387         return material;
00388     }
00389 }
00390 
00391 
00392 Mesh::VertexDescription*
00393 AsciiModelLoader::loadVertexDescription()
00394 {
00395     if (tok.nextToken() != Tokenizer::TokenName ||
00396         tok.getNameValue() != "vertexdesc")
00397     {
00398         reportError("Vertex description expected");
00399         return NULL;
00400     }
00401 
00402     int maxAttributes = 16;
00403     int nAttributes = 0;
00404     uint32 offset = 0;
00405     Mesh::VertexAttribute* attributes = new Mesh::VertexAttribute[maxAttributes];
00406 
00407     while (tok.nextToken() == Tokenizer::TokenName &&
00408            tok.getNameValue() != "end_vertexdesc")
00409     {
00410         string semanticName;
00411         string formatName;
00412         bool valid = false;
00413 
00414         if (nAttributes == maxAttributes)
00415         {
00416             // TODO: Should eliminate the attribute limit, though no real vertex
00417             // will ever exceed it.
00418             reportError("Attribute limit exceeded in vertex description");
00419             delete[] attributes;
00420             return NULL;
00421         }
00422 
00423         semanticName = tok.getNameValue();
00424 
00425         if (tok.nextToken() == Tokenizer::TokenName)
00426         {
00427             formatName = tok.getNameValue();
00428             valid = true;
00429         }
00430 
00431         if (!valid)
00432         {
00433             reportError("Invalid vertex description");
00434             delete[] attributes;
00435             return NULL;
00436         }
00437 
00438         Mesh::VertexAttributeSemantic semantic =
00439             Mesh::parseVertexAttributeSemantic(semanticName);
00440         if (semantic == Mesh::InvalidSemantic)
00441         {
00442             reportError(string("Invalid vertex attribute semantic '") +
00443                         semanticName + "'");
00444             delete[] attributes;
00445             return NULL;
00446         }
00447 
00448         Mesh::VertexAttributeFormat format = 
00449             Mesh::parseVertexAttributeFormat(formatName);
00450         if (format == Mesh::InvalidFormat)
00451         {
00452             reportError(string("Invalid vertex attribute format '") +
00453                         formatName + "'");
00454             delete[] attributes;
00455             return NULL;
00456         }
00457 
00458         attributes[nAttributes].semantic = semantic;
00459         attributes[nAttributes].format = format;
00460         attributes[nAttributes].offset = offset;
00461 
00462         offset += Mesh::getVertexAttributeSize(format);
00463         nAttributes++;
00464     }
00465 
00466     if (tok.getTokenType() != Tokenizer::TokenName)
00467     {
00468         reportError("Invalid vertex description");
00469         delete[] attributes;
00470         return NULL;
00471     }
00472 
00473     if (nAttributes == 0)
00474     {
00475         reportError("Vertex definitition cannot be empty");
00476         delete[] attributes;
00477         return NULL;
00478     }
00479 
00480     return new Mesh::VertexDescription(offset, nAttributes, attributes);
00481 }
00482 
00483 
00484 char*
00485 AsciiModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
00486                                uint32& vertexCount)
00487 {
00488     if (tok.nextToken() != Tokenizer::TokenName ||
00489         tok.getNameValue() != "vertices")
00490     {
00491         reportError("Vertex data expected");
00492         return NULL;
00493     }
00494 
00495     if (tok.nextToken() != Tokenizer::TokenNumber)
00496     {
00497         reportError("Vertex count expected");
00498         return NULL;
00499     }
00500 
00501     double num = tok.getNumberValue();
00502     if (num != floor(num) || num <= 0.0)
00503     {
00504         reportError("Bad vertex count for mesh");
00505         return NULL;
00506     }
00507 
00508     vertexCount = (uint32) num;
00509     uint32 vertexDataSize = vertexDesc.stride * vertexCount;
00510     char* vertexData = new char[vertexDataSize];
00511     if (vertexData == NULL)
00512     {
00513         reportError("Not enough memory to hold vertex data");
00514         return NULL;
00515     }
00516 
00517     uint32 offset = 0;
00518     double data[4];
00519     for (uint32 i = 0; i < vertexCount; i++, offset += vertexDesc.stride)
00520     {
00521         assert(offset < vertexDataSize);
00522         for (uint32 attr = 0; attr < vertexDesc.nAttributes; attr++)
00523         {
00524             Mesh::VertexAttributeFormat fmt = vertexDesc.attributes[attr].format;
00525             uint32 nBytes = Mesh::getVertexAttributeSize(fmt);
00526             int readCount = 0;
00527             switch (fmt)
00528             {
00529             case Mesh::Float1:
00530                 readCount = 1;
00531                 break;
00532             case Mesh::Float2:
00533                 readCount = 2;
00534                 break;
00535             case Mesh::Float3:
00536                 readCount = 3;
00537                 break;
00538             case Mesh::Float4:
00539             case Mesh::UByte4:
00540                 readCount = 4;
00541                 break;
00542             default:
00543                 assert(0);
00544                 delete[] vertexData;
00545                 return NULL;
00546             }
00547 
00548             for (int j = 0; j < readCount; j++)
00549             {
00550                 if (tok.nextToken() != Tokenizer::TokenNumber)
00551                 {
00552                     reportError("Error in vertex data");
00553                     delete[] vertexData;
00554                 }
00555                 data[j] = tok.getNumberValue();
00556 
00557                 // TODO: range check unsigned byte values
00558             }
00559 
00560             uint32 base = offset + vertexDesc.attributes[attr].offset;
00561             if (fmt == Mesh::UByte4)
00562             {
00563                 for (int k = 0; k < readCount; k++)
00564                 {
00565                     reinterpret_cast<unsigned char*>(vertexData + base)[k] =
00566                         (unsigned char) (data[k]);
00567                 }
00568             }
00569             else
00570             {
00571                 for (int k = 0; k < readCount; k++)
00572                     reinterpret_cast<float*>(vertexData + base)[k] = (float) data[k];
00573             }
00574         }
00575     }
00576 
00577     return vertexData;
00578 }
00579 
00580                                
00581 Mesh*
00582 AsciiModelLoader::loadMesh()
00583 {
00584     if (tok.nextToken() != Tokenizer::TokenName ||
00585         tok.getNameValue() != "mesh")
00586     {
00587         reportError("Mesh definition expected");
00588         return NULL;
00589     }
00590     
00591     Mesh::VertexDescription* vertexDesc = loadVertexDescription();
00592     if (vertexDesc == NULL)
00593         return NULL;
00594 
00595     uint32 vertexCount = 0;
00596     char* vertexData = loadVertices(*vertexDesc, vertexCount);
00597     if (vertexData == NULL)
00598         return NULL;
00599 
00600     Mesh* mesh = new Mesh();
00601     mesh->setVertexDescription(*vertexDesc);
00602     mesh->setVertices(vertexCount, vertexData);
00603 
00604     while (tok.nextToken() == Tokenizer::TokenName &&
00605            tok.getNameValue() != "end_mesh")
00606     {
00607         Mesh::PrimitiveGroupType type =
00608             Mesh::parsePrimitiveGroupType(tok.getNameValue());
00609         if (type == Mesh::InvalidPrimitiveGroupType)
00610         {
00611             reportError("Bad primitive group type: " + tok.getNameValue());
00612             delete mesh;
00613             return NULL;
00614         }
00615 
00616         if (tok.nextToken() != Tokenizer::TokenNumber)
00617         {
00618             reportError("Material index expected in primitive group");
00619             delete mesh;
00620             return NULL;
00621         }
00622 
00623         uint32 materialIndex;
00624         if (tok.getNumberValue() == -1.0)
00625             materialIndex = ~0;
00626         else
00627             materialIndex = (uint32) tok.getNumberValue();
00628 
00629         if (tok.nextToken() != Tokenizer::TokenNumber)
00630         {
00631             reportError("Index count expected in primitive group");
00632             delete mesh;
00633             return NULL;
00634         }
00635 
00636         uint32 indexCount = (uint32) tok.getNumberValue();
00637         
00638         uint32* indices = new uint32[indexCount];
00639         if (indices == NULL)
00640         {
00641             reportError("Not enough memory to hold indices");
00642             delete mesh;
00643             return NULL;
00644         }
00645 
00646         for (uint32 i = 0; i < indexCount; i++)
00647         {
00648             if (tok.nextToken() != Tokenizer::TokenNumber)
00649             {
00650                 reportError("Incomplete index list in primitive group");
00651                 delete indices;
00652                 delete mesh;
00653                 return NULL;
00654             }
00655 
00656             uint32 index = (uint32) tok.getNumberValue();
00657             if (index >= vertexCount)
00658             {
00659                 reportError("Index out of range");
00660                 delete indices;
00661                 delete mesh;
00662                 return NULL;
00663             }
00664 
00665             indices[i] = index;
00666         }
00667 
00668         mesh->addGroup(type, materialIndex, indexCount, indices);
00669     }
00670 
00671     return mesh;
00672 }
00673 
00674 
00675 Model*
00676 AsciiModelLoader::load()
00677 {
00678     Model* model = new Model();
00679     bool seenMeshes = false;
00680 
00681     if (model == NULL)
00682     {
00683         reportError("Unable to allocate memory for model");
00684         return NULL;
00685     }
00686 
00687     // Parse material and mesh definitions
00688     for (;;)
00689     {
00690         Tokenizer::TokenType ttype = tok.nextToken();
00691 
00692         if (ttype == Tokenizer::TokenEnd)
00693         {
00694             break;
00695         }
00696         else if (ttype == Tokenizer::TokenName)
00697         {
00698             string name = tok.getNameValue();
00699             tok.pushBack();
00700 
00701             if (name == "material")
00702             {
00703                 if (seenMeshes)
00704                 {
00705                     reportError("Materials must be defined before meshes");
00706                     delete model;
00707                     return NULL;
00708                 }
00709 
00710                 Mesh::Material* material = loadMaterial();
00711                 if (material == NULL)
00712                 {
00713                     delete model;
00714                     return NULL;
00715                 }
00716 
00717                 model->addMaterial(material);
00718             }
00719             else if (name == "mesh")
00720             {
00721                 seenMeshes = true;
00722 
00723                 Mesh* mesh = loadMesh();
00724                 if (mesh == NULL)
00725                 {
00726                     delete model;
00727                     return NULL;
00728                 }
00729 
00730                 model->addMesh(mesh);
00731             }
00732             else
00733             {
00734                 reportError(string("Error: Unknown block type ") + name);
00735                 delete model;
00736                 return NULL;
00737             }
00738         }
00739         else
00740         {
00741             reportError("Block name expected");
00742             return NULL;
00743         }
00744     }
00745      
00746     return model;
00747 }
00748 
00749 
00750 
00751 AsciiModelWriter::AsciiModelWriter(ostream& _out) :
00752     out(_out)
00753 {
00754 }
00755 
00756 
00757 AsciiModelWriter::~AsciiModelWriter()
00758 {
00759 }
00760 
00761 
00762 bool
00763 AsciiModelWriter::write(const Model& model)
00764 {
00765     out << CEL_MODEL_HEADER_ASCII << "\n\n";
00766 
00767     for (uint32 matIndex = 0; model.getMaterial(matIndex); matIndex++)
00768     {
00769         writeMaterial(*model.getMaterial(matIndex));
00770         out << '\n';
00771     }
00772 
00773     for (uint32 meshIndex = 0; model.getMesh(meshIndex); meshIndex++)
00774     {
00775         writeMesh(*model.getMesh(meshIndex));
00776         out << '\n';
00777     }
00778 
00779     return true;
00780 }
00781 
00782 
00783 void
00784 AsciiModelWriter::writeGroup(const Mesh::PrimitiveGroup& group)
00785 {
00786     switch (group.prim)
00787     {
00788     case Mesh::TriList:
00789         out << "trilist"; break;
00790     case Mesh::TriStrip:
00791         out << "tristrip"; break;
00792     case Mesh::TriFan:
00793         out << "trifan"; break;
00794     case Mesh::LineList:
00795         out << "linelist"; break;
00796     case Mesh::LineStrip:
00797         out << "linestrip"; break;
00798     case Mesh::PointList:
00799         out << "points"; break;
00800     default:
00801         return;
00802     }
00803     
00804     out << ' ' << group.materialIndex << ' ' << group.nIndices << '\n';
00805 
00806     // Print the indices, twelve per line
00807     for (uint32 i = 0; i < group.nIndices; i++)
00808     {
00809         out << group.indices[i];
00810         if (i % 12 == 11 || i == group.nIndices - 1)
00811             out << '\n';
00812         else
00813             out << ' ';
00814     }
00815 }
00816 
00817 
00818 void
00819 AsciiModelWriter::writeMesh(const Mesh& mesh)
00820 {
00821     out << "mesh\n";
00822 
00823     if (!mesh.getName().empty())
00824         out << "# " << mesh.getName() << '\n';
00825 
00826     writeVertexDescription(mesh.getVertexDescription());
00827     out << '\n';
00828 
00829     writeVertices(mesh.getVertexData(),
00830                   mesh.getVertexCount(),
00831                   mesh.getVertexStride(),
00832                   mesh.getVertexDescription());
00833     out << '\n';
00834 
00835     for (uint32 groupIndex = 0; mesh.getGroup(groupIndex); groupIndex++)
00836     {
00837         writeGroup(*mesh.getGroup(groupIndex));
00838         out << '\n';
00839     }
00840 
00841     out << "end_mesh\n";
00842 }
00843 
00844 
00845 void
00846 AsciiModelWriter::writeVertices(const void* vertexData,
00847                                 uint32 nVertices,
00848                                 uint32 stride,
00849                                 const Mesh::VertexDescription& desc)
00850 {
00851     const unsigned char* vertex = reinterpret_cast<const unsigned char*>(vertexData);
00852 
00853     out << "vertices " << nVertices << '\n';
00854     for (uint32 i = 0; i < nVertices; i++, vertex += stride)
00855     {
00856         for (uint32 attr = 0; attr < desc.nAttributes; attr++)
00857         {
00858             const unsigned char* ubdata = vertex + desc.attributes[attr].offset;
00859             const float* fdata = reinterpret_cast<const float*>(ubdata);
00860 
00861             switch (desc.attributes[attr].format)
00862             {
00863             case Mesh::Float1:
00864                 out << fdata[0];
00865                 break;
00866             case Mesh::Float2:
00867                 out << fdata[0] << ' ' << fdata[1];
00868                 break;
00869             case Mesh::Float3:
00870                 out << fdata[0] << ' ' << fdata[1] << ' ' << fdata[2];
00871                 break;
00872             case Mesh::Float4:
00873                 out << fdata[0] << ' ' << fdata[1] << ' ' <<
00874                        fdata[2] << ' ' << fdata[3];
00875                 break;
00876             case Mesh::UByte4:
00877                 out << (int) ubdata[0] << ' ' << (int) ubdata[1] << ' ' <<
00878                        (int) ubdata[2] << ' ' << (int) ubdata[3];
00879                 break;
00880             default:
00881                 assert(0);
00882                 break;
00883             }
00884 
00885             out << ' ';
00886         }
00887 
00888         out << '\n';
00889     }
00890 }
00891 
00892 
00893 void
00894 AsciiModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc)
00895 {
00896     out << "vertexdesc\n";
00897     for (uint32 attr = 0; attr < desc.nAttributes; attr++)
00898     {
00899         // We should never have a vertex description with invalid
00900         // fields . . .
00901 
00902         switch (desc.attributes[attr].semantic)
00903         {
00904         case Mesh::Position:
00905             out << "position";
00906             break;
00907         case Mesh::Color0:
00908             out << "color0";
00909             break;
00910         case Mesh::Color1:
00911             out << "color1";
00912             break;
00913         case Mesh::Normal:
00914             out << "normal";
00915             break;
00916         case Mesh::Tangent:
00917             out << "tangent";
00918             break;
00919         case Mesh::Texture0:
00920             out << "texcoord0";
00921             break;
00922         case Mesh::Texture1:
00923             out << "texcoord1";
00924             break;
00925         case Mesh::Texture2:
00926             out << "texcoord2";
00927             break;
00928         case Mesh::Texture3:
00929             out << "texcoord3";
00930             break;
00931         default:
00932             assert(0);
00933             break;
00934         }
00935 
00936         out << ' ';
00937 
00938         switch (desc.attributes[attr].format)
00939         {
00940         case Mesh::Float1:
00941             out << "f1";
00942             break;
00943         case Mesh::Float2:
00944             out << "f2";
00945             break;
00946         case Mesh::Float3:
00947             out << "f3";
00948             break;
00949         case Mesh::Float4:
00950             out << "f4";
00951             break;
00952         case Mesh::UByte4:
00953             out << "ub4";
00954             break;
00955         default:
00956             assert(0);
00957             break;
00958         }
00959 
00960         out << '\n';
00961     }
00962     out << "end_vertexdesc\n";
00963 }
00964 
00965 
00966 void
00967 AsciiModelWriter::writeMaterial(const Mesh::Material& material)
00968 {
00969     out << "material\n";
00970     if (material.diffuse != DefaultDiffuse)
00971     {
00972         out << "diffuse " <<
00973             material.diffuse.red() << ' ' <<
00974             material.diffuse.green() << ' ' <<
00975             material.diffuse.blue() << '\n';
00976     }
00977 
00978     if (material.emissive != DefaultEmissive)
00979     {
00980         out << "emissive " <<
00981             material.emissive.red() << ' ' <<
00982             material.emissive.green() << ' ' <<
00983             material.emissive.blue() << '\n';
00984     }
00985 
00986     if (material.specular != DefaultSpecular)
00987     {
00988         out << "specular " <<
00989             material.specular.red() << ' ' <<
00990             material.specular.green() << ' ' <<
00991             material.specular.blue() << '\n';
00992     }
00993 
00994     if (material.specularPower != DefaultSpecularPower)
00995         out << "specpower " << material.specularPower << '\n';
00996 
00997     if (material.opacity != DefaultOpacity)
00998         out << "opacity " << material.opacity << '\n';
00999 
01000     for (int i = 0; i < Mesh::TextureSemanticMax; i++)
01001     {
01002         const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.maps[i]);
01003         if (texInfo != NULL)
01004         {
01005             switch (Mesh::TextureSemantic(i))
01006             {
01007             case Mesh::DiffuseMap:
01008                 out << "texture0";
01009                 break;
01010             case Mesh::NormalMap:
01011                 out << "normalmap";
01012                 break;
01013             case Mesh::SpecularMap:
01014                 out << "specularmap";
01015                 break;
01016             case Mesh::EmissiveMap:
01017                 out << "emissivemap";
01018                 break;
01019             default:
01020                 assert(0);
01021             }
01022             
01023             out << " \"" << texInfo->source << "\"\n";
01024         }
01025     }
01026 
01027 #if 0
01028     if (material.maps[Mesh::DiffuseMap] != InvalidResource)
01029     {
01030         const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.tex0);
01031         if (texInfo != NULL)
01032             out << "texture0 \"" << texInfo->source << "\"\n";
01033     }
01034 
01035     if (material.tex1 != InvalidResource)
01036     {
01037         const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.tex1);
01038         if (texInfo != NULL)
01039             out << "texture1 \"" << texInfo->source << "\"\n";
01040     }
01041 #endif
01042 
01043 
01044     out << "end_material\n";
01045 }
01046 
01047 
01048 /***** Binary loader *****/
01049 
01050 BinaryModelLoader::BinaryModelLoader(istream& _in) :
01051     in(_in)
01052 {
01053 }
01054 
01055 
01056 BinaryModelLoader::~BinaryModelLoader()
01057 {
01058 }
01059 
01060 
01061 void
01062 BinaryModelLoader::reportError(const string& msg)
01063 {
01064     char buf[32];
01065     sprintf(buf, " (offset %d)", 0);
01066     ModelLoader::reportError(msg + string(buf));
01067 }
01068 
01069 
01070 // Read a big-endian 32-bit unsigned integer
01071 static int32 readUint(istream& in)
01072 {
01073     int32 ret;
01074     in.read((char*) &ret, sizeof(int32));
01075     LE_TO_CPU_INT32(ret, ret);
01076     return (uint32) ret;
01077 }
01078 
01079 
01080 static float readFloat(istream& in)
01081 {
01082     int i = readUint(in);
01083     return *((float*) &i);
01084 }
01085 
01086 
01087 static int16 readInt16(istream& in)
01088 {
01089     int16 ret;
01090     in.read((char *) &ret, sizeof(int16));
01091     LE_TO_CPU_INT16(ret, ret);
01092     return ret;
01093 }
01094 
01095 
01096 static ModelFileToken readToken(istream& in)
01097 {
01098     return (ModelFileToken) readInt16(in);
01099 }
01100 
01101 
01102 static ModelFileType readType(istream& in)
01103 {
01104     return (ModelFileType) readInt16(in);
01105 }
01106 
01107 
01108 static bool readTypeFloat1(istream& in, float& f)
01109 {
01110     if (readType(in) != CMOD_Float1)
01111         return false;
01112     f = readFloat(in);
01113     return true;
01114 }
01115 
01116 
01117 static bool readTypeColor(istream& in, Color& c)
01118 {
01119     if (readType(in) != CMOD_Color)
01120         return false;
01121 
01122     float r = readFloat(in);
01123     float g = readFloat(in);
01124     float b = readFloat(in);
01125     c = Color(r, g, b);
01126 
01127     return true;
01128 }
01129 
01130 
01131 static bool readTypeString(istream& in, string& s)
01132 {
01133     if (readType(in) != CMOD_String)
01134         return false;
01135 
01136     uint16 len;
01137     in.read((char*) &len, sizeof(uint16));
01138     LE_TO_CPU_INT16(len, len);
01139 
01140     if (len == 0)
01141     {
01142         s = "";
01143     }
01144     else
01145     {
01146         char* buf = new char[len];
01147         in.read(buf, len);
01148         s = string(buf, len);
01149         delete[] buf;
01150     }
01151 
01152     return true;
01153 }
01154 
01155 
01156 static bool ignoreValue(istream& in)
01157 {
01158     ModelFileType type = readType(in);
01159     int size = 0;
01160 
01161     switch (type)
01162     {
01163     case CMOD_Float1:
01164         size = 4;
01165         break;
01166     case CMOD_Float2:
01167         size = 8;
01168         break;
01169     case CMOD_Float3:
01170         size = 12;
01171         break;
01172     case CMOD_Float4:
01173         size = 16;
01174         break;
01175     case CMOD_Uint32:
01176         size = 4;
01177         break;
01178     case CMOD_Color:
01179         size = 12;
01180         break;
01181     case CMOD_String:
01182         {
01183             uint16 len;
01184             in.read((char*) &len, sizeof(uint16));
01185             LE_TO_CPU_INT16(len, len);
01186             size = len;
01187         }
01188         break;
01189 
01190     default:
01191         return false;
01192     }
01193 
01194     in.ignore(size);
01195 
01196     return true;
01197 }
01198 
01199 
01200 Model*
01201 BinaryModelLoader::load()
01202 {
01203     Model* model = new Model();
01204     bool seenMeshes = false;
01205 
01206     if (model == NULL)
01207     {
01208         reportError("Unable to allocate memory for model");
01209         return NULL;
01210     }
01211 
01212     // Parse material and mesh definitions
01213     for (;;)
01214     {
01215         ModelFileToken tok = readToken(in);
01216 
01217         if (in.eof())
01218         {
01219             break;
01220         }
01221         else if (tok == CMOD_Material)
01222         {
01223             if (seenMeshes)
01224             {
01225                 reportError("Materials must be defined before meshes");
01226                 delete model;
01227                 return NULL;
01228             }
01229 
01230             Mesh::Material* material = loadMaterial();
01231             if (material == NULL)
01232             {
01233                 delete model;
01234                 return NULL;
01235             }
01236 
01237             model->addMaterial(material);
01238         }
01239         else if (tok == CMOD_Mesh)
01240         {
01241             seenMeshes = true;
01242 
01243             Mesh* mesh = loadMesh();
01244             if (mesh == NULL)
01245             {
01246                 delete model;
01247                 return NULL;
01248             }
01249 
01250             model->addMesh(mesh);
01251         }
01252         else
01253         {
01254             reportError("Error: Unknown block type in model");
01255             delete model;
01256             return NULL;
01257         }
01258     }
01259      
01260     return model;
01261 }
01262 
01263 
01264 Mesh::Material*
01265 BinaryModelLoader::loadMaterial()
01266 {
01267     Mesh::Material* material = new Mesh::Material();
01268 
01269     material->diffuse = DefaultDiffuse;
01270     material->specular = DefaultSpecular;
01271     material->emissive = DefaultEmissive;
01272     material->specularPower = DefaultSpecularPower;
01273     material->opacity = DefaultOpacity;
01274 
01275     for (;;)
01276     {
01277         ModelFileToken tok = readToken(in);
01278         switch (tok)
01279         {
01280         case CMOD_Diffuse:
01281             if (!readTypeColor(in, material->diffuse))
01282             {
01283                 reportError("Incorrect type for diffuse color");
01284                 delete material;
01285                 return NULL;
01286             }
01287             break;
01288 
01289         case CMOD_Specular:
01290             if (!readTypeColor(in, material->specular))
01291             {
01292                 reportError("Incorrect type for specular color");
01293                 delete material;
01294                 return NULL;
01295             }
01296             break;
01297 
01298         case CMOD_Emissive:
01299             if (!readTypeColor(in, material->emissive))
01300             {
01301                 reportError("Incorrect type for emissive color");
01302                 delete material;
01303                 return NULL;
01304             }
01305             break;
01306 
01307         case CMOD_SpecularPower:
01308             if (!readTypeFloat1(in, material->specularPower))
01309             {
01310                 reportError("Float expected for specularPower");
01311                 delete material;
01312                 return NULL;
01313             }
01314             break;
01315 
01316         case CMOD_Opacity:
01317             if (!readTypeFloat1(in, material->opacity))
01318             {
01319                 reportError("Float expected for opacity");
01320                 delete material;
01321                 return NULL;
01322             }
01323             break;
01324 
01325         case CMOD_Texture:
01326             {
01327                 int16 texType = readInt16(in);
01328                 if (texType < 0 || texType >= Mesh::TextureSemanticMax)
01329                 {
01330                     reportError("Bad texture type");
01331                     delete material;
01332                     return NULL;
01333                 }
01334 
01335                 string texfile;
01336                 if (!readTypeString(in, texfile))
01337                 {
01338                     reportError("String expected for texture filename");
01339                     delete material;
01340                     return NULL;
01341                 }
01342 
01343                 if (texfile.empty())
01344                 {
01345                     reportError("Zero length texture name in material definition");
01346                     delete material;
01347                     return NULL;
01348                 }
01349 
01350                 ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(texfile, getTexturePath(), TextureInfo::WrapTexture));
01351                 
01352                 material->maps[texType] = tex;
01353             }
01354             break;
01355             
01356         case CMOD_EndMaterial:
01357             return material;
01358 
01359         default:
01360             // Skip unrecognized tokens
01361             if (!ignoreValue(in))
01362             {
01363                 delete material;
01364                 return NULL;
01365             }
01366         } // switch
01367     } // for
01368 }
01369 
01370 
01371 Mesh::VertexDescription*
01372 BinaryModelLoader::loadVertexDescription()
01373 {
01374     if (readToken(in) != CMOD_VertexDesc)
01375     {
01376         reportError("Vertex description expected");
01377         return NULL;
01378     }
01379 
01380     int maxAttributes = 16;
01381     int nAttributes = 0;
01382     uint32 offset = 0;
01383     Mesh::VertexAttribute* attributes = new Mesh::VertexAttribute[maxAttributes];
01384 
01385     for (;;)
01386     {
01387         int16 tok = readInt16(in);
01388         
01389         if (tok == CMOD_EndVertexDesc)
01390         {
01391             break;
01392         }
01393         else if (tok >= 0 && tok < Mesh::SemanticMax)
01394         {
01395             int16 fmt = readInt16(in);
01396             if (fmt < 0 || fmt >= Mesh::FormatMax)
01397             {
01398                 reportError("Invalid vertex attribute type");
01399                 delete[] attributes;
01400                 return NULL;
01401             }
01402             else
01403             {
01404                 if (nAttributes == maxAttributes)
01405                 {
01406                     reportError("Too many attributes in vertex description");
01407                     delete[] attributes;
01408                     return NULL;
01409                 }
01410 
01411                 attributes[nAttributes].semantic =
01412                     static_cast<Mesh::VertexAttributeSemantic>(tok);
01413                 attributes[nAttributes].format = 
01414                     static_cast<Mesh::VertexAttributeFormat>(fmt);
01415                 attributes[nAttributes].offset = offset;
01416 
01417                 offset += Mesh::getVertexAttributeSize(attributes[nAttributes].format);
01418                 nAttributes++;
01419             }
01420         }
01421         else
01422         {
01423             reportError("Invalid semantic in vertex description");
01424             delete[] attributes;
01425             return NULL;
01426         }
01427     }
01428 
01429     if (nAttributes == 0)
01430     {
01431         reportError("Vertex definitition cannot be empty");
01432         delete[] attributes;
01433         return NULL;
01434     }
01435 
01436     return new Mesh::VertexDescription(offset, nAttributes, attributes);
01437 }
01438 
01439 
01440 Mesh*
01441 BinaryModelLoader::loadMesh()
01442 {
01443     Mesh::VertexDescription* vertexDesc = loadVertexDescription();
01444     if (vertexDesc == NULL)
01445         return NULL;
01446 
01447     uint32 vertexCount = 0;
01448     char* vertexData = loadVertices(*vertexDesc, vertexCount);
01449     if (vertexData == NULL)
01450         return NULL;
01451 
01452     Mesh* mesh = new Mesh();
01453     mesh->setVertexDescription(*vertexDesc);
01454     mesh->setVertices(vertexCount, vertexData);
01455 
01456     for (;;)
01457     {
01458         int16 tok = readInt16(in);
01459         
01460         if (tok == CMOD_EndMesh)
01461         {
01462             break;
01463         }
01464         else if (tok < 0 || tok >= Mesh::PrimitiveTypeMax)
01465         {
01466             reportError("Bad primitive group type");
01467             delete mesh;
01468             return NULL;
01469         }
01470 
01471         Mesh::PrimitiveGroupType type =
01472             static_cast<Mesh::PrimitiveGroupType>(tok);
01473         uint32 materialIndex = readUint(in);
01474         uint32 indexCount = readUint(in);
01475 
01476         uint32* indices = new uint32[indexCount];
01477         if (indices == NULL)
01478         {
01479             reportError("Not enough memory to hold indices");
01480             delete mesh;
01481             return NULL;
01482         }
01483 
01484         for (uint32 i = 0; i < indexCount; i++)
01485         {
01486             uint32 index = readUint(in);
01487             if (index >= vertexCount)
01488             {
01489                 reportError("Index out of range");
01490                 delete indices;
01491                 delete mesh;
01492                 return NULL;
01493             }
01494 
01495             indices[i] = index;
01496         }
01497 
01498         mesh->addGroup(type, materialIndex, indexCount, indices);
01499     }
01500 
01501     return mesh;
01502 }
01503 
01504 
01505 char*
01506 BinaryModelLoader::loadVertices(const Mesh::VertexDescription& vertexDesc,
01507                                 uint32& vertexCount)
01508 {
01509     if (readToken(in) != CMOD_Vertices)
01510     {
01511         reportError("Vertex data expected");
01512         return NULL;
01513     }
01514 
01515     vertexCount = readUint(in);
01516     uint32 vertexDataSize = vertexDesc.stride * vertexCount;
01517     char* vertexData = new char[vertexDataSize];
01518     if (vertexData == NULL)
01519     {
01520         reportError("Not enough memory to hold vertex data");
01521         return NULL;
01522     }
01523 
01524     uint32 offset = 0;
01525 
01526     for (uint32 i = 0; i < vertexCount; i++, offset += vertexDesc.stride)
01527     {
01528         assert(offset < vertexDataSize);
01529         for (uint32 attr = 0; attr < vertexDesc.nAttributes; attr++)
01530         {
01531             uint32 base = offset + vertexDesc.attributes[attr].offset;
01532             Mesh::VertexAttributeFormat fmt = vertexDesc.attributes[attr].format;
01533             int readCount = 0;
01534             switch (fmt)
01535             {
01536             case Mesh::Float1:
01537                 reinterpret_cast<float*>(vertexData + base)[0] = readFloat(in);
01538                 break;
01539             case Mesh::Float2:
01540                 reinterpret_cast<float*>(vertexData + base)[0] = readFloat(in);
01541                 reinterpret_cast<float*>(vertexData + base)[1] = readFloat(in);
01542                 break;
01543             case Mesh::Float3:
01544                 reinterpret_cast<float*>(vertexData + base)[0] = readFloat(in);
01545                 reinterpret_cast<float*>(vertexData + base)[1] = readFloat(in);
01546                 reinterpret_cast<float*>(vertexData + base)[2] = readFloat(in);
01547                 break;
01548             case Mesh::Float4:
01549                 reinterpret_cast<float*>(vertexData + base)[0] = readFloat(in);
01550                 reinterpret_cast<float*>(vertexData + base)[1] = readFloat(in);
01551                 reinterpret_cast<float*>(vertexData + base)[2] = readFloat(in);
01552                 reinterpret_cast<float*>(vertexData + base)[3] = readFloat(in);
01553                 break;
01554             case Mesh::UByte4:
01555                 in.get(reinterpret_cast<char*>(vertexData + base), 4);
01556                 break;
01557             default:
01558                 assert(0);
01559                 delete[] vertexData;
01560                 return NULL;
01561             }
01562         }
01563     }
01564 
01565     return vertexData;
01566 }
01567 
01568 
01569 
01570 /***** Binary writer *****/
01571 
01572 BinaryModelWriter::BinaryModelWriter(ostream& _out) :
01573     out(_out)
01574 {
01575 }
01576 
01577 
01578 BinaryModelWriter::~BinaryModelWriter()
01579 {
01580 }
01581 
01582 
01583 // Utility functions for writing binary values to a file
01584 static void writeUint(ostream& out, uint32 val)
01585 {
01586     LE_TO_CPU_INT32(val, val);
01587     out.write(reinterpret_cast<char*>(&val), sizeof(uint32));
01588 }
01589 
01590 static void writeFloat(ostream& out, float val)
01591 {
01592     LE_TO_CPU_FLOAT(val, val);
01593     out.write(reinterpret_cast<char*>(&val), sizeof(float));
01594 }
01595 
01596 static void writeInt16(ostream& out, int16 val)
01597 {
01598     LE_TO_CPU_INT16(val, val);
01599     out.write(reinterpret_cast<char*>(&val), sizeof(int16));
01600 }
01601 
01602 static void writeToken(ostream& out, ModelFileToken val)
01603 {
01604     writeInt16(out, static_cast<int16>(val));
01605 }
01606 
01607 static void writeType(ostream& out, ModelFileType val)
01608 {
01609     writeInt16(out, static_cast<int16>(val));
01610 }
01611 
01612 
01613 static void writeTypeFloat1(ostream& out, float f)
01614 {
01615     writeType(out, CMOD_Float1);
01616     writeFloat(out, f);
01617 }
01618 
01619 
01620 static void writeTypeColor(ostream& out, const Color& c)
01621 {
01622     writeType(out, CMOD_Color);
01623     writeFloat(out, c.red());
01624     writeFloat(out, c.green());
01625     writeFloat(out, c.blue());
01626 }
01627 
01628 
01629 static void writeTypeString(ostream& out, const string& s)
01630 {
01631     writeType(out, CMOD_String);
01632     writeInt16(out, static_cast<int16>(s.length()));
01633     out.write(s.c_str(), s.length());
01634 }
01635 
01636 
01637 bool
01638 BinaryModelWriter::write(const Model& model)
01639 {
01640     out << CEL_MODEL_HEADER_BINARY;
01641 
01642     for (uint32 matIndex = 0; model.getMaterial(matIndex); matIndex++)
01643         writeMaterial(*model.getMaterial(matIndex));
01644 
01645     for (uint32 meshIndex = 0; model.getMesh(meshIndex); meshIndex++)
01646         writeMesh(*model.getMesh(meshIndex));
01647 
01648     return true;
01649 }
01650 
01651 
01652 void
01653 BinaryModelWriter::writeGroup(const Mesh::PrimitiveGroup& group)
01654 {
01655     writeInt16(out, static_cast<int16>(group.prim));
01656     writeUint(out, group.materialIndex);
01657     writeUint(out, group.nIndices);
01658 
01659     // Print the indices, twelve per line
01660     for (uint32 i = 0; i < group.nIndices; i++)
01661         writeUint(out, group.indices[i]);
01662 }
01663 
01664 
01665 void
01666 BinaryModelWriter::writeMesh(const Mesh& mesh)
01667 {
01668     writeToken(out, CMOD_Mesh);
01669 
01670     writeVertexDescription(mesh.getVertexDescription());
01671 
01672     writeVertices(mesh.getVertexData(),
01673                   mesh.getVertexCount(),
01674                   mesh.getVertexStride(),
01675                   mesh.getVertexDescription());
01676 
01677     for (uint32 groupIndex = 0; mesh.getGroup(groupIndex); groupIndex++)
01678         writeGroup(*mesh.getGroup(groupIndex));
01679 
01680     writeToken(out, CMOD_EndMesh);
01681 }
01682 
01683 
01684 void
01685 BinaryModelWriter::writeVertices(const void* vertexData,
01686                                  uint32 nVertices,
01687                                  uint32 stride,
01688                                  const Mesh::VertexDescription& desc)
01689 {
01690     const char* vertex = reinterpret_cast<const char*>(vertexData);
01691 
01692     writeToken(out, CMOD_Vertices);
01693     writeUint(out, nVertices);
01694 
01695     for (uint32 i = 0; i < nVertices; i++, vertex += stride)
01696     {
01697         for (uint32 attr = 0; attr < desc.nAttributes; attr++)
01698         {
01699             const char* cdata = vertex + desc.attributes[attr].offset;
01700             const float* fdata = reinterpret_cast<const float*>(cdata);
01701 
01702             switch (desc.attributes[attr].format)
01703             {
01704             case Mesh::Float1:
01705                 writeFloat(out, fdata[0]);
01706                 break;
01707             case Mesh::Float2:
01708                 writeFloat(out, fdata[0]);
01709                 writeFloat(out, fdata[1]);
01710                 break;
01711             case Mesh::Float3:
01712                 writeFloat(out, fdata[0]);
01713                 writeFloat(out, fdata[1]);
01714                 writeFloat(out, fdata[2]);
01715                 break;
01716             case Mesh::Float4:
01717                 writeFloat(out, fdata[0]);
01718                 writeFloat(out, fdata[1]);
01719                 writeFloat(out, fdata[2]);
01720                 writeFloat(out, fdata[3]);
01721                 break;
01722             case Mesh::UByte4:
01723                 out.write(cdata, 4);
01724                 break;
01725             default:
01726                 assert(0);
01727                 break;
01728             }
01729         }
01730     }
01731 }
01732 
01733 
01734 void
01735 BinaryModelWriter::writeVertexDescription(const Mesh::VertexDescription& desc)
01736 {
01737     writeToken(out, CMOD_VertexDesc);
01738 
01739     for (uint32 attr = 0; attr < desc.nAttributes; attr++)
01740     {
01741         writeInt16(out, static_cast<int16>(desc.attributes[attr].semantic));
01742         writeInt16(out, static_cast<int16>(desc.attributes[attr].format));
01743     }
01744 
01745     writeToken(out, CMOD_EndVertexDesc);
01746 }
01747 
01748 
01749 void
01750 BinaryModelWriter::writeMaterial(const Mesh::Material& material)
01751 {
01752     writeToken(out, CMOD_Material);
01753 
01754     if (material.diffuse != DefaultDiffuse)
01755     {
01756         writeToken(out, CMOD_Diffuse);
01757         writeTypeColor(out, material.diffuse);
01758     }
01759 
01760     if (material.emissive != DefaultEmissive)
01761     {
01762         writeToken(out, CMOD_Emissive);
01763         writeTypeColor(out, material.emissive);
01764     }
01765 
01766     if (material.specular != DefaultSpecular)
01767     {
01768         writeToken(out, CMOD_Specular);
01769         writeTypeColor(out, material.specular);
01770     }
01771 
01772     if (material.specularPower != DefaultSpecularPower)
01773     {
01774         writeToken(out, CMOD_SpecularPower);
01775         writeTypeFloat1(out, material.specularPower);
01776     }
01777 
01778     if (material.opacity != DefaultOpacity)
01779     {
01780         writeToken(out, CMOD_Opacity);
01781         writeTypeFloat1(out, material.opacity);
01782     }
01783 
01784     for (int i = 0; i < Mesh::TextureSemanticMax; i++)
01785     {
01786         if (material.maps[i] != InvalidResource)
01787         {
01788             const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.maps[i]);
01789             if (texInfo != NULL)
01790             {
01791                 writeToken(out, CMOD_Texture);
01792                 writeInt16(out, (int16) i);
01793                 writeTypeString(out, texInfo->source);
01794             }
01795         }
01796     }
01797 #if 0
01798     if (material.tex1 != InvalidResource)
01799     {
01800         const TextureInfo* texInfo = GetTextureManager()->getResourceInfo(material.tex1);
01801         if (texInfo != NULL)
01802         {
01803             writeToken(out, CMOD_Texture1);
01804             writeTypeString(out, texInfo->source);
01805         }
01806     }
01807 #endif
01808 
01809     writeToken(out, CMOD_EndMaterial);
01810 }

Generated on Sat Jan 14 22:30:27 2006 for Celestia by  doxygen 1.4.1