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

mesh.cpp

Go to the documentation of this file.
00001 // mesh.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 "mesh.h"
00011 #include "rendcontext.h"
00012 #include "gl.h"
00013 #include "glext.h"
00014 #include <cassert>
00015 #include <iostream>
00016 using namespace std;
00017 
00018 
00019 static size_t VertexAttributeFormatSizes[Mesh::FormatMax] = 
00020 {
00021      4,  // Float1
00022      8,  // Float2
00023      12, // Float3
00024      16, // Float4,
00025      4,  // UByte4
00026 };
00027 
00028 
00029 // Vertex buffer object support
00030 
00031 // VBO optimization is only worthwhile for large enough vertex lists
00032 static const unsigned int MinVBOSize = 4096;
00033 static bool VBOSupportTested = false;
00034 static bool VBOSupported = false;
00035 
00036 static bool isVBOSupported()
00037 {
00038     if (!VBOSupportTested)
00039     {
00040         VBOSupportTested = true;
00041         VBOSupported = ExtensionSupported("GL_ARB_vertex_buffer_object");
00042     }
00043 
00044     return VBOSupported;
00045 }
00046 
00047 
00048 Mesh::Material::Material() :
00049     diffuse(0.0f, 0.0f, 0.0f),
00050     emissive(0.0f, 0.0f, 0.0f),
00051     specular(0.0f, 0.0f, 0.0f),
00052     specularPower(1.0f),
00053     opacity(1.0f)
00054 {
00055     for (int i = 0; i < TextureSemanticMax; i++)
00056         maps[i] = InvalidResource;
00057         
00058 }
00059 
00060 
00061 Mesh::VertexDescription::VertexDescription(uint32 _stride,
00062                                            uint32 _nAttributes,
00063                                            VertexAttribute* _attributes) :
00064             stride(_stride),
00065             nAttributes(_nAttributes),
00066             attributes(NULL)
00067 {
00068     if (nAttributes != 0)
00069     {
00070         attributes = new VertexAttribute[nAttributes];
00071         for (uint32 i = 0; i < nAttributes; i++)
00072             attributes[i] = _attributes[i];
00073         buildSemanticMap();
00074     }
00075 }
00076 
00077 
00078 Mesh::VertexDescription::VertexDescription(const VertexDescription& desc) :
00079     stride(desc.stride),
00080     nAttributes(desc.nAttributes),
00081     attributes(NULL)
00082 {
00083     if (nAttributes != 0)
00084     {
00085         attributes = new VertexAttribute[nAttributes];
00086         for (uint32 i = 0; i < nAttributes; i++)
00087             attributes[i] = desc.attributes[i];
00088         buildSemanticMap();
00089     }
00090 }
00091 
00092 
00093 Mesh::VertexDescription&
00094 Mesh::VertexDescription::operator=(const Mesh::VertexDescription& desc)
00095 {
00096     if (nAttributes < desc.nAttributes)
00097     {
00098         if (attributes != NULL)
00099             delete[] attributes;
00100         attributes = new VertexAttribute[desc.nAttributes];
00101     }
00102 
00103     nAttributes = desc.nAttributes;
00104     stride = desc.stride;
00105     for (uint32 i = 0; i < nAttributes; i++)
00106         attributes[i] = desc.attributes[i];
00107     clearSemanticMap();
00108     buildSemanticMap();
00109 
00110     return *this;
00111 }
00112 
00113 
00114 // TODO: This should be called in the constructor; we should start using
00115 // exceptions in Celestia.
00116 bool
00117 Mesh::VertexDescription::validate() const
00118 {
00119     for (uint32 i = 0; i < nAttributes; i++)
00120     {
00121         VertexAttribute& attr = attributes[i];
00122 
00123         // Validate the attribute
00124         if (attr.semantic >= SemanticMax || attr.format >= FormatMax)
00125             return false;
00126         if (attr.offset % 4 != 0)
00127             return false;
00128         if (attr.offset + VertexAttributeFormatSizes[attr.format] > stride)
00129             return false;
00130         // TODO: check for repetition of attributes
00131         // if (vertexAttributeMap[attr->semantic].format != InvalidFormat)
00132         //   return false;
00133     }
00134 
00135     return true;
00136 }
00137 
00138 
00139 Mesh::VertexDescription::~VertexDescription()
00140 {
00141     delete[] attributes;
00142 }
00143 
00144 
00145 void
00146 Mesh::VertexDescription::buildSemanticMap()
00147 {
00148     for (uint32 i = 0; i < nAttributes; i++)
00149         semanticMap[attributes[i].semantic] = attributes[i];
00150 }
00151 
00152 
00153 void
00154 Mesh::VertexDescription::clearSemanticMap()
00155 {
00156     for (uint32 i = 0; i < SemanticMax; i++)
00157         semanticMap[i] = VertexAttribute();
00158 }
00159 
00160 
00161 Mesh::PrimitiveGroup::PrimitiveGroup()
00162 {
00163 }
00164 
00165 
00166 Mesh::PrimitiveGroup::~PrimitiveGroup()
00167 {
00168     // TODO: probably should free index list; need to sort out
00169     // ownership issues.
00170 }
00171 
00172 
00173 Mesh::Mesh() :
00174     vertexDesc(0, 0, NULL),
00175     nVertices(0),
00176     vertices(NULL),
00177     vbObject(0),
00178     vbInitialized(false)
00179 {
00180 }
00181 
00182 
00183 Mesh::~Mesh()
00184 {
00185     for (vector<PrimitiveGroup*>::iterator iter = groups.begin();
00186          iter != groups.end(); iter++)
00187     {
00188         delete *iter;
00189     }
00190 
00191     if (vertices != NULL)
00192         delete vertices;
00193 
00194     if (vbObject != 0)
00195     {
00196         glx::glDeleteBuffersARB(1, &vbObject);
00197     }
00198 }
00199 
00200 
00201 void
00202 Mesh::setVertices(uint32 _nVertices, void* vertexData)
00203 {
00204     nVertices = _nVertices;
00205     vertices = vertexData;
00206 }
00207 
00208 
00209 bool
00210 Mesh::setVertexDescription(const VertexDescription& desc)
00211 {
00212     if (!desc.validate())
00213         return false;
00214 
00215     vertexDesc = desc;
00216 
00217     return true;
00218 }
00219 
00220 
00221 const Mesh::VertexDescription& Mesh::getVertexDescription() const
00222 {
00223     return vertexDesc;
00224 }
00225 
00226 
00227 const Mesh::PrimitiveGroup*
00228 Mesh::getGroup(uint32 index) const
00229 {
00230     if (index >= groups.size())
00231         return NULL;
00232     else
00233         return groups[index];
00234 }
00235 
00236 
00237 uint32
00238 Mesh::addGroup(PrimitiveGroup* group)
00239 {
00240     groups.push_back(group);
00241     return groups.size();
00242 }
00243 
00244 
00245 uint32
00246 Mesh::addGroup(PrimitiveGroupType prim,
00247                uint32 materialIndex,
00248                uint32 nIndices,
00249                uint32* indices)
00250 {
00251     PrimitiveGroup* g = new PrimitiveGroup();
00252     g->prim = prim;
00253     g->materialIndex = materialIndex;
00254     g->nIndices = nIndices;
00255     g->indices = indices;
00256     
00257     return addGroup(g);
00258 }
00259 
00260 
00261 void
00262 Mesh::clearGroups()
00263 {
00264     for (vector<PrimitiveGroup*>::iterator iter = groups.begin();
00265          iter != groups.end(); iter++)
00266     {
00267         delete *iter;
00268     }
00269 
00270     groups.clear();
00271 }
00272 
00273 
00274 const string&
00275 Mesh::getName() const
00276 {
00277     return name;
00278 }
00279 
00280 
00281 void
00282 Mesh::setName(const string& _name)
00283 {
00284     name = _name;
00285 }
00286 
00287 
00288 void
00289 Mesh::remapIndices(const vector<uint32>& indexMap)
00290 {
00291     for (vector<PrimitiveGroup*>::iterator iter = groups.begin();
00292          iter != groups.end(); iter++)
00293     {
00294         PrimitiveGroup* group = *iter;
00295         for (uint32 i = 0; i < group->nIndices; i++)
00296         {
00297             group->indices[i] = indexMap[group->indices[i]];
00298         }
00299     }
00300 }
00301 
00302 
00303 bool
00304 Mesh::pick(const Ray3d& ray, double& distance) const
00305 {
00306     double maxDistance = 1.0e30;
00307     double closest = maxDistance;
00308 
00309     // Pick will automatically fail without vertex positions--no reasonable
00310     // mesh should lack these.
00311     if (vertexDesc.getAttribute(Position).semantic != Position ||
00312         vertexDesc.getAttribute(Position).format != Float3)
00313     {
00314         return false;
00315     }
00316 
00317     uint posOffset = vertexDesc.getAttribute(Position).offset;
00318     char* vdata = reinterpret_cast<char*>(vertices);
00319 
00320     // Iterate over all primitive groups in the mesh
00321     for (vector<PrimitiveGroup*>::const_iterator iter = groups.begin();
00322          iter != groups.end(); iter++)
00323     {
00324         Mesh::PrimitiveGroupType primType = (*iter)->prim;
00325         uint32 nIndices = (*iter)->nIndices;
00326 
00327         // Only attempt to compute the intersection of the ray with triangl
00328         // groups.
00329         if ((primType == TriList || primType == TriStrip || primType == TriFan) &&
00330             (nIndices >= 3) &&
00331             !(primType == TriList && nIndices % 3 != 0))
00332         {
00333             uint32 index = 0;
00334             uint32 i0 = (*iter)->indices[0];
00335             uint32 i1 = (*iter)->indices[1];
00336             uint32 i2 = (*iter)->indices[2];
00337             
00338             // Iterate over the triangles in the primitive group
00339             do
00340             {
00341                 // Get the triangle vertices v0, v1, and v2
00342                 float* f0 = reinterpret_cast<float*>(vdata + i0 * vertexDesc.stride + posOffset);
00343                 float* f1 = reinterpret_cast<float*>(vdata + i1 * vertexDesc.stride + posOffset);
00344                 float* f2 = reinterpret_cast<float*>(vdata + i2 * vertexDesc.stride + posOffset);
00345                 Point3d v0(f0[0], f0[1], f0[2]);
00346                 Point3d v1(f1[0], f1[1], f1[2]);
00347                 Point3d v2(f2[0], f2[1], f2[2]);
00348 
00349                 // Compute the edge vectors e0 and e1, and the normal n
00350                 Vec3d e0 = v1 - v0;
00351                 Vec3d e1 = v2 - v0;
00352                 Vec3d n = e0 ^ e1;
00353 
00354                 // c is the cosine of the angle between the ray and triangle normal
00355                 double c = n * ray.direction;
00356 
00357                 // If the ray is parallel to the triangle, it either misses the
00358                 // triangle completely, or is contained in the triangle's plane.
00359                 // If it's contained in the plane, we'll still call it a miss.
00360                 if (c != 0.0)
00361                 {
00362                     double t = (n * (v0 - ray.origin)) / c;
00363                     if (t < closest && t > 0.0)
00364                     {
00365                         double m00 = e0 * e0;
00366                         double m01 = e0 * e1;
00367                         double m10 = e1 * e0;
00368                         double m11 = e1 * e1;
00369                         double det = m00 * m11 - m01 * m10;
00370                         if (det != 0.0)
00371                         {
00372                             Point3d p = ray.point(t);
00373                             Vec3d q = p - v0;
00374                             double q0 = e0 * q;
00375                             double q1 = e1 * q;
00376                             double d = 1.0 / det;
00377                             double s0 = (m11 * q0 - m01 * q1) * d;
00378                             double s1 = (m00 * q1 - m10 * q0) * d;
00379                             if (s0 >= 0.0 && s1 >= 0.0 && s0 + s1 <= 1.0)
00380                                 closest = t;
00381                         }
00382                     }
00383                 }
00384 
00385                 // Get the indices for the next triangle
00386                 if (primType == TriList)
00387                 {
00388                     index += 3;
00389                     if (index < nIndices)
00390                     {
00391                         i0 = (*iter)->indices[index + 0];
00392                         i1 = (*iter)->indices[index + 1];
00393                         i2 = (*iter)->indices[index + 2];
00394                     }
00395                 }
00396                 else if (primType == TriStrip)
00397                 {
00398                     index += 1;
00399                     if (index < nIndices)
00400                     {
00401                         i0 = i1;
00402                         i1 = i2;
00403                         i2 = (*iter)->indices[index];
00404                         // TODO: alternate orientation of triangles in a strip
00405                     }
00406                 }
00407                 else // primType == TriFan
00408                 {
00409                     index += 1;
00410                     if (index < nIndices)
00411                     {
00412                         index += 1;
00413                         i1 = i2;
00414                         i2 = (*iter)->indices[index];
00415                     }
00416                 }
00417 
00418             } while (index < nIndices);
00419         }
00420     }
00421 
00422     if (closest != maxDistance)
00423     {
00424         distance = closest;
00425         return true;
00426     }
00427     else
00428     {
00429         return false;
00430     }
00431 }
00432 
00433 
00434 void
00435 Mesh::render(const std::vector<const Material*>& materials,
00436              RenderContext& rc) const
00437 {
00438     // The first time the mesh is rendered, we will try and place the
00439     // vertex data in a vertex buffer object and potentially get a huge
00440     // rendering performance boost.  This can consume a great deal of
00441     // memory, since we're duplicating the vertex data.  TODO: investigate
00442     // the possibility of deleting the original data.  We can always map
00443     // read-only later on for things like picking, but this could be a low
00444     // performance path.
00445     if (!vbInitialized && isVBOSupported())
00446     {
00447         vbInitialized = true;
00448 
00449         if (nVertices * vertexDesc.stride > MinVBOSize)
00450         {
00451             glx::glGenBuffersARB(1, &vbObject);
00452             if (vbObject != 0)
00453             {
00454                 glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbObject);
00455                 glx::glBufferDataARB(GL_ARRAY_BUFFER_ARB,
00456                                      nVertices * vertexDesc.stride,
00457                                      vertices,
00458                                      GL_STATIC_DRAW_ARB);
00459             }
00460         }
00461     }
00462 
00463     if (vbObject != 0)
00464     {
00465         glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbObject);
00466         rc.setVertexArrays(vertexDesc, NULL);
00467     }
00468     else
00469     {
00470         rc.setVertexArrays(vertexDesc, vertices);
00471     }
00472 
00473     uint32 lastMaterial = ~0;
00474 
00475     // Iterate over all primitive groups in the mesh
00476     for (vector<PrimitiveGroup*>::const_iterator iter = groups.begin();
00477          iter != groups.end(); iter++)
00478     {
00479         // Set up the material
00480         const Material* mat = NULL;
00481         uint32 materialIndex = (*iter)->materialIndex;
00482         if (materialIndex != lastMaterial && materialIndex < materials.size())
00483             mat = materials[materialIndex];
00484 
00485         rc.setMaterial(mat);
00486         rc.drawGroup(**iter);
00487     }
00488 
00489     if (vbObject != 0)
00490         glx::glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
00491 }
00492 
00493 
00494 AxisAlignedBox
00495 Mesh::getBoundingBox() const
00496 {
00497     AxisAlignedBox bbox;
00498 
00499     // Return an empty box if there's no position info
00500     if (vertexDesc.getAttribute(Position).format != Float3)
00501         return bbox;
00502 
00503     char* vdata = reinterpret_cast<char*>(vertices) + vertexDesc.getAttribute(Position).offset;
00504     
00505     for (uint32 i = 0; i < nVertices; i++, vdata += vertexDesc.stride)
00506         bbox.include(Point3f(reinterpret_cast<float*>(vdata)));
00507 
00508     return bbox;
00509 }
00510 
00511 
00512 void
00513 Mesh::transform(Vec3f translation, float scale)
00514 {
00515     if (vertexDesc.getAttribute(Position).format != Float3)
00516         return;
00517 
00518     char* vdata = reinterpret_cast<char*>(vertices) + vertexDesc.getAttribute(Position).offset;
00519     for (uint32 i = 0; i < nVertices; i++, vdata += vertexDesc.stride)
00520     {
00521         Vec3f tv = (Vec3f(reinterpret_cast<float*>(vdata)) + translation) * scale;
00522         reinterpret_cast<float*>(vdata)[0] = tv.x;
00523         reinterpret_cast<float*>(vdata)[1] = tv.y;
00524         reinterpret_cast<float*>(vdata)[2] = tv.z;
00525     }
00526 }
00527 
00528 
00529 Mesh::PrimitiveGroupType
00530 Mesh::parsePrimitiveGroupType(const string& name)
00531 {
00532     if (name == "trilist")
00533         return TriList;
00534     else if (name == "tristrip")
00535         return TriStrip;
00536     else if (name == "trifan")
00537         return TriFan;
00538     else if (name == "linelist")
00539         return LineList;
00540     else if (name == "linestrip")
00541         return LineStrip;
00542     else if (name == "points")
00543         return PointList;
00544     else
00545         return InvalidPrimitiveGroupType;
00546 }
00547 
00548 
00549 Mesh::VertexAttributeSemantic
00550 Mesh::parseVertexAttributeSemantic(const string& name)
00551 {
00552     if (name == "position")
00553         return Position;
00554     else if (name == "normal")
00555         return Normal;
00556     else if (name == "color0")
00557         return Color0;
00558     else if (name == "color1")
00559         return Color1;
00560     else if (name == "tangent")
00561         return Tangent;
00562     else if (name == "texcoord0")
00563         return Texture0;
00564     else if (name == "texcoord1")
00565         return Texture1;
00566     else if (name == "texcoord2")
00567         return Texture2;
00568     else if (name == "texcoord3")
00569         return Texture3;
00570     else
00571         return InvalidSemantic;
00572 }
00573 
00574 
00575 Mesh::VertexAttributeFormat
00576 Mesh::parseVertexAttributeFormat(const string& name)
00577 {
00578     if (name == "f1")
00579         return Float1;
00580     else if (name == "f2")
00581         return Float2;
00582     else if (name == "f3")
00583         return Float3;
00584     else if (name == "f4")
00585         return Float4;
00586     else if (name == "ub4")
00587         return UByte4;
00588     else
00589         return InvalidFormat;
00590 }
00591 
00592 
00593 Mesh::TextureSemantic
00594 Mesh::parseTextureSemantic(const string& name)
00595 {
00596     if (name == "texture0")
00597         return DiffuseMap;
00598     else if (name == "normalmap")
00599         return NormalMap;
00600     else if (name == "specularmap")
00601         return SpecularMap;
00602     else if (name == "emissivemap")
00603         return EmissiveMap;
00604     else
00605         return InvalidTextureSemantic;
00606 }
00607 
00608 
00609 uint32
00610 Mesh::getVertexAttributeSize(VertexAttributeFormat fmt)
00611 {
00612     switch (fmt)
00613     {
00614     case Float1:
00615     case UByte4:
00616         return 4;
00617     case Float2:
00618         return 8;
00619     case Float3:
00620         return 12;
00621     case Float4:
00622         return 16;
00623     default:
00624         return 0;
00625     }
00626 }

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