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

AsciiModelLoader Class Reference

Inheritance diagram for AsciiModelLoader:

Inheritance graph
Collaboration diagram for AsciiModelLoader:

Collaboration graph
List of all members.

Public Member Functions

 AsciiModelLoader (istream &_in)
virtual Modelload ()
Mesh::MaterialloadMaterial ()
MeshloadMesh ()
Mesh::VertexDescriptionloadVertexDescription ()
char * loadVertices (const Mesh::VertexDescription &vertexDesc, uint32 &vertexCount)
virtual void reportError (const string &)
 ~AsciiModelLoader ()

Private Attributes

Tokenizer tok

Detailed Description

This is an approximate Backus Naur form for the contents of ASCII cmod files. For brevity, the categories <unsigned_int> and <float> aren't defined here--they have the obvious definitions.
<modelfile>           ::= <header> <model>

<header>              ::= #celmodel__ascii

<model>               ::= { <material_definition> } { <mesh_definition> }

<material_definition> ::= material
                          { <material_attribute> }
                          end_material

<texture_semantic>    ::= texture0       |
                          normalmap      |
                          specularmap    |
                          emissivemap

<texture>             ::= <texture_semantic> <string>

<material_attribute>  ::= diffuse <color>   |
                          specular <color>  |
                          emissive <color>  |
                          specpower <float> |
                          opacity <float>   |
                          <texture>

<color>               ::= <float> <float> <float>

<string>              ::= """ { letter } """

<mesh_definition>     ::= mesh
                          <vertex_description>
                          <vertex_pool>
                          { <prim_group> }
                          end_mesh

<vertex_description>  ::= vertexdesc
                          { <vertex_attribute> }
                          end_vertexdesc

<vertex_attribute>    ::= <vertex_semantic> <vertex_format>

<vertex_semantic>     ::= position | normal | color0 | color1 | tangent |
                          texcoord0 | texcoord1 | texcoord2 | texcoord3

<vertex_format>       ::= f1 | f2 | f3 | f4 | ub4

<vertex_pool>         ::= vertices <count>
                          { <float> }

<count>               ::= <unsigned_int>

<prim_group>          ::= <prim_group_type> <material_index> <count>
                          { <unsigned_int> }

<prim_group_type>     ::= trilist | tristrip | trifan |
                          linelist | linestrip | points

<material_index>      :: <unsigned_int> | -1

Definition at line 95 of file modelfile.cpp.


Constructor & Destructor Documentation

AsciiModelLoader::AsciiModelLoader istream &  _in  ) 
 

Definition at line 286 of file modelfile.cpp.

00286                                                :
00287     tok(&_in)
00288 {
00289 }

AsciiModelLoader::~AsciiModelLoader  ) 
 

Definition at line 292 of file modelfile.cpp.

00293 {
00294 }


Member Function Documentation

Model * AsciiModelLoader::load  )  [virtual]
 

Implements ModelLoader.

Definition at line 676 of file modelfile.cpp.

References Model::addMaterial(), Model::addMesh(), Tokenizer::getNameValue(), loadMaterial(), loadMesh(), Tokenizer::nextToken(), Tokenizer::pushBack(), reportError(), and tok.

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 }

Mesh::Material * AsciiModelLoader::loadMaterial  ) 
 

Definition at line 307 of file modelfile.cpp.

References DefaultDiffuse(), DefaultEmissive(), DefaultOpacity, DefaultSpecular(), DefaultSpecularPower, Mesh::Material::diffuse, Mesh::Material::emissive, ResourceManager< T >::getHandle(), Tokenizer::getNameValue(), Tokenizer::getNumberValue(), Tokenizer::getStringValue(), GetTextureManager(), ModelLoader::getTexturePath(), Tokenizer::getTokenType(), Mesh::Material::maps, Tokenizer::nextToken(), Mesh::Material::opacity, Mesh::parseTextureSemantic(), reportError(), Mesh::Material::specular, Mesh::Material::specularPower, and tok.

Referenced by load().

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 }

Mesh * AsciiModelLoader::loadMesh  ) 
 

Definition at line 582 of file modelfile.cpp.

References Mesh::addGroup(), Tokenizer::getNameValue(), Tokenizer::getNumberValue(), loadVertexDescription(), loadVertices(), Tokenizer::nextToken(), Mesh::parsePrimitiveGroupType(), reportError(), Mesh::setVertexDescription(), Mesh::setVertices(), and tok.

Referenced by load().

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 }

Mesh::VertexDescription * AsciiModelLoader::loadVertexDescription  ) 
 

Definition at line 393 of file modelfile.cpp.

References Mesh::VertexAttribute::format, Tokenizer::getNameValue(), Tokenizer::getTokenType(), Mesh::getVertexAttributeSize(), Tokenizer::nextToken(), Mesh::VertexAttribute::offset, Mesh::parseVertexAttributeFormat(), Mesh::parseVertexAttributeSemantic(), reportError(), Mesh::VertexAttribute::semantic, and tok.

Referenced by loadMesh().

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 }

char * AsciiModelLoader::loadVertices const Mesh::VertexDescription vertexDesc,
uint32 vertexCount
 

Definition at line 485 of file modelfile.cpp.

References Tokenizer::getNameValue(), Tokenizer::getNumberValue(), Mesh::getVertexAttributeSize(), Tokenizer::nextToken(), reportError(), and tok.

Referenced by loadMesh().

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 }

void AsciiModelLoader::reportError const string  )  [virtual]
 

Definition at line 298 of file modelfile.cpp.

References Tokenizer::getLineNumber(), ModelLoader::reportError(), and tok.

Referenced by load(), loadMaterial(), loadMesh(), loadVertexDescription(), and loadVertices().

00299 {
00300     char buf[32];
00301     sprintf(buf, " (line %d)", tok.getLineNumber());
00302     ModelLoader::reportError(msg + string(buf));
00303 }


Member Data Documentation

Tokenizer AsciiModelLoader::tok [private]
 

Definition at line 111 of file modelfile.cpp.

Referenced by load(), loadMaterial(), loadMesh(), loadVertexDescription(), loadVertices(), and reportError().


The documentation for this class was generated from the following file:
Generated on Sat Jan 14 22:33:06 2006 for Celestia by  doxygen 1.4.1