model.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:11k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // model.cpp
  2. //
  3. // Copyright (C) 2004-2006, Chris Laurel <claurel@shatters.net>
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. #include "model.h"
  10. #include "rendcontext.h"
  11. #include <cassert>
  12. #include <functional>
  13. #include <algorithm>
  14. using namespace std;
  15. #if 0
  16. static GLenum GLPrimitiveModes[MaxPrimitiveType] =
  17. {
  18.     GL_TRIANGLES,
  19.     GL_TRIANGLE_STRIP,
  20.     GL_TRIANGLE_FAN,
  21.     GL_LINES,
  22.     GL_LINE_STRIP,
  23.     GL_POINTS
  24. };
  25. #endif
  26. #if 0
  27. static size_t VertexAttributeFormatSizes[Mesh::FormatMax] =
  28. {
  29.      4,  // Float1
  30.      8,  // Float2
  31.      12, // Float3
  32.      16, // Float4,
  33.      4,  // UByte4
  34. };
  35. #endif
  36. Model::Model() :
  37.     opaque(true),
  38.     normalized(false)
  39. {
  40.     for (int i = 0; i < Mesh::TextureSemanticMax; i++)
  41.         textureUsage[i] = false;
  42. }
  43. Model::~Model()
  44. {
  45.     {
  46.         for (vector<Mesh*>::iterator iter = meshes.begin();
  47.              iter != meshes.end(); iter++)
  48.             delete *iter;
  49.     }
  50. #if 0
  51.     {
  52.         for (vector<const Mesh::Material*>::iterator iter = materials.begin();
  53.              iter != materials.end(); iter++)
  54.             delete *iter;
  55.     }
  56. #endif
  57. }
  58. const Mesh::Material*
  59. Model::getMaterial(uint32 index) const
  60. {
  61.     if (index < materials.size())
  62.         return materials[index];
  63.     else
  64.         return NULL;
  65. }
  66. uint32
  67. Model::addMaterial(const Mesh::Material* m)
  68. {
  69.     // Update the texture map usage information for the model.  Since
  70.     // the material being added isn't necessarily used by a mesh within
  71.     // the model, we could potentially end up with false positives--this
  72.     // won't cause any rendering troubles, but could hurt performance
  73.     // if it forces multipass rendering when it's not required.
  74.     for (int i = 0; i < Mesh::TextureSemanticMax; i++)
  75.     {
  76.         if (m->maps[i] != InvalidResource)
  77.             textureUsage[i] = true;
  78.     }
  79.     materials.push_back(m);
  80.     return materials.size();
  81. }
  82. uint32
  83. Model::getMaterialCount() const
  84. {
  85.     return materials.size();
  86. }
  87. uint32
  88. Model::getVertexCount() const
  89. {
  90.     uint32 count = 0;
  91.     for (vector<Mesh*>::const_iterator iter = meshes.begin();
  92.          iter != meshes.end(); iter++)
  93.     {
  94.         count += (*iter)->getVertexCount();
  95.     }
  96.     return count;
  97. }
  98. uint32
  99. Model::getPrimitiveCount() const
  100. {
  101.     uint32 count = 0;
  102.     for (vector<Mesh*>::const_iterator iter = meshes.begin();
  103.          iter != meshes.end(); iter++)
  104.     {
  105.         count += (*iter)->getPrimitiveCount();
  106.     }
  107.     return count;
  108. }
  109. Mesh*
  110. Model::getMesh(uint32 index) const
  111. {
  112.     if (index < meshes.size())
  113.         return meshes[index];
  114.     else
  115.         return NULL;
  116. }
  117. uint32
  118. Model::addMesh(Mesh* m)
  119. {
  120.     meshes.push_back(m);
  121.     return meshes.size();
  122. }
  123. bool
  124. Model::pick(const Ray3d& r, double& distance) const
  125. {
  126.     double maxDistance = 1.0e30;
  127.     double closest = maxDistance;
  128.     for (vector<Mesh*>::const_iterator iter = meshes.begin();
  129.          iter != meshes.end(); iter++)
  130.     {
  131.         double d = maxDistance;
  132.         if ((*iter)->pick(r, d) && d < closest)
  133.             closest = d;
  134.     }
  135.     if (closest != maxDistance)
  136.     {
  137.         distance = closest;
  138.         return true;
  139.     }
  140.     else
  141.     {
  142.         return false;
  143.     }
  144. }
  145. /*! Render the model; the time parameter is ignored right now
  146.  *  since this class doesn't currently support animation.
  147.  */
  148. void
  149. Model::render(RenderContext& rc, double /* t */)
  150. {
  151.     for (vector<Mesh*>::const_iterator iter = meshes.begin();
  152.          iter != meshes.end(); iter++)
  153.     {
  154.         (*iter)->render(materials, rc);
  155.     }
  156. }
  157. /*! Translate and scale a model. The transformation applied to
  158.  *  each vertex in the model is:
  159.  *     v' = (v + translation) * scale
  160.  */
  161. void
  162. Model::transform(const Vec3f& translation, float scale)
  163. {
  164.     for (vector<Mesh*>::const_iterator iter = meshes.begin(); iter != meshes.end(); iter++)
  165.         (*iter)->transform(translation, scale);
  166. }
  167. void
  168. Model::normalize(const Vec3f& centerOffset)
  169. {
  170.     AxisAlignedBox bbox;
  171.     for (vector<Mesh*>::const_iterator iter = meshes.begin(); iter != meshes.end(); iter++)
  172.         bbox.include((*iter)->getBoundingBox());
  173.     Point3f center = bbox.getCenter() + centerOffset;
  174.     Vec3f extents = bbox.getExtents();
  175.     float maxExtent = extents.x;
  176.     if (extents.y > maxExtent)
  177.         maxExtent = extents.y;
  178.     if (extents.z > maxExtent)
  179.         maxExtent = extents.z;
  180.     
  181.     // clog << "Extents: " << extents.x << ", " << extents.y << ", " << extents.z << endl;
  182.     transform(Point3f(0, 0, 0) - center, 2.0f / maxExtent);
  183.     normalized = true;
  184. }
  185. static bool
  186. operator<(const Color& c0, const Color& c1)
  187. {
  188.     if (c0.red() < c1.red())
  189.         return true;
  190.     else if (c0.red() > c1.red())
  191.         return false;
  192.     if (c0.green() < c1.green())
  193.         return true;
  194.     else if (c0.green() > c1.green())
  195.         return false;
  196.     return c0.blue() < c1.blue();
  197. }
  198. // Define an ordering for materials; required for elimination of duplicate
  199. // materials.
  200. static bool
  201. operator<(const Mesh::Material& m0, const Mesh::Material& m1)
  202. {
  203.     // Checking opacity first and doing it backwards is deliberate. It means
  204.     // that after sorting, translucent materials will end up with higher
  205.     // material indices than opaque ones. Ultimately, after sorting
  206.     // mesh primitive groups by material, translucent groups will end up
  207.     // rendered after opaque ones.
  208.     if (m0.opacity < m1.opacity)
  209.         return true;
  210.     else if (m0.opacity > m1.opacity)
  211.         return false;
  212.     // Reverse sense of comparison here--additive blending is 1, normal
  213.     // blending is 0, and we'd prefer to render additively blended submeshes
  214.     // last.
  215.     if (m0.blend > m1.blend)
  216.         return true;
  217.     else if (m0.blend < m1.blend)
  218.         return false;
  219.     if (m0.diffuse < m1.diffuse)
  220.         return true;
  221.     else if (m1.diffuse < m0.diffuse)
  222.         return false;
  223.     if (m0.emissive < m1.emissive)
  224.         return true;
  225.     else if (m1.emissive < m0.emissive)
  226.         return false;
  227.     if (m0.specular < m1.specular)
  228.         return true;
  229.     else if (m1.specular < m0.specular)
  230.         return false;
  231.     if (m0.specularPower < m1.specularPower)
  232.         return true;
  233.     else if (m0.specularPower > m1.specularPower)
  234.         return false;
  235.     for (unsigned int i = 0; i < Mesh::TextureSemanticMax; i++)
  236.     {
  237.         if (m0.maps[i] < m1.maps[i])
  238.             return true;
  239.         else if (m0.maps[i] > m1.maps[i])
  240.             return false;
  241.     }
  242.     // Materials are identical
  243.     return false;
  244. }
  245. // Simple struct that pairs an index with a material; the index is used to
  246. // keep track of the original material index after sorting.
  247. struct IndexedMaterial
  248. {
  249.     int originalIndex;
  250.     const Mesh::Material* material;
  251. };
  252. static bool
  253. operator<(const IndexedMaterial& im0, const IndexedMaterial& im1)
  254. {
  255.     return *(im0.material) < *(im1.material);
  256. }
  257. static bool
  258. operator!=(const IndexedMaterial& im0, const IndexedMaterial& im1)
  259. {
  260.     return im0 < im1 || im1 < im0;
  261. }
  262. void
  263. Model::uniquifyMaterials()
  264. {
  265.     // No work to do if there's just a single material
  266.     if (materials.size() <= 1)
  267.         return;
  268.     // Create an array of materials with the indices attached
  269.     vector<IndexedMaterial> indexedMaterials;
  270.     unsigned int i;
  271.     for (i = 0; i < materials.size(); i++)
  272.     {
  273.         IndexedMaterial im;
  274.         im.originalIndex = i;
  275.         im.material = materials[i];
  276.         indexedMaterials.push_back(im);
  277.     }
  278.     // Sort the indexed materials so that we can uniquify them
  279.     sort(indexedMaterials.begin(), indexedMaterials.end());
  280.     vector<const Mesh::Material*> uniqueMaterials;
  281.     vector<uint32> materialMap(materials.size());
  282.     vector<uint32> duplicateMaterials;
  283.     // From the sorted material list construct the list of unique materials
  284.     // and a map to convert old material indices into indices that can be
  285.     // used with the uniquified material list.
  286.     unsigned int uniqueMaterialCount = 0;
  287.     for (i = 0; i < indexedMaterials.size(); i++)
  288.     {
  289.         if (i == 0 || indexedMaterials[i] != indexedMaterials[i - 1])
  290.         {
  291.             uniqueMaterialCount++;
  292.             uniqueMaterials.push_back(indexedMaterials[i].material);
  293.         }
  294.         else
  295.         {
  296.             duplicateMaterials.push_back(i);
  297.         }
  298.         materialMap[indexedMaterials[i].originalIndex] = uniqueMaterialCount - 1;
  299.     }
  300.     // Remap all the material indices in the model. Even if no materials have
  301.     // been eliminated we've still sorted them by opacity, which is useful
  302.     // when reordering meshes so that translucent ones are rendered last.
  303.     for (vector<Mesh*>::iterator iter = meshes.begin();
  304.          iter != meshes.end(); iter++)
  305.     {
  306.         (*iter)->remapMaterials(materialMap);
  307.     }
  308.     vector<uint32>::const_iterator dupIter;
  309.     for (dupIter = duplicateMaterials.begin();
  310.          dupIter != duplicateMaterials.end(); ++dupIter)
  311.     {
  312.         delete indexedMaterials[*dupIter].material;
  313.     }
  314.     materials = uniqueMaterials;
  315. }
  316. void
  317. Model::determineOpacity()
  318. {
  319.     for (unsigned int i = 0; i < materials.size(); i++)
  320.     {
  321.         if ((materials[i]->opacity > 0.01f && materials[i]->opacity < 1.0f) ||
  322.             materials[i]->blend == Mesh::AdditiveBlend)
  323.         {
  324.             opaque = false;
  325.             return;
  326.         }
  327.     }
  328.     opaque = true;
  329. }
  330. bool
  331. Model::usesTextureType(Mesh::TextureSemantic t) const
  332. {
  333.     return textureUsage[static_cast<int>(t)];
  334. }
  335. class MeshComparatorAdapter : public std::binary_function<const Mesh*, const Mesh*, bool>
  336. {
  337. public:
  338.     MeshComparatorAdapter(const Model::MeshComparator& c) :
  339.         comparator(c)
  340.     {
  341.     }
  342.     bool operator()(const Mesh* a, const Mesh* b) const
  343.     {
  344.         return comparator(*a, *b);
  345.     }
  346. private:
  347.     const Model::MeshComparator& comparator;
  348. };
  349. Model::OpacityComparator::OpacityComparator()
  350. {
  351. }
  352. // Look at the material used by last primitive group in the mesh for the
  353. // opacity of the whole model.  This is a very crude way to check the opacity
  354. // of a mesh and misses many cases.
  355. static uint32
  356. getMeshMaterialIndex(const Mesh& mesh)
  357. {
  358.     if (mesh.getGroupCount() == 0)
  359.         return 0;
  360.     else
  361.         return mesh.getGroup(mesh.getGroupCount() - 1)->materialIndex;
  362. }
  363. bool
  364. Model::OpacityComparator::operator()(const Mesh& a, const Mesh& b) const
  365. {
  366.     // Because materials are sorted by opacity, we can just compare
  367.     // the material index.
  368.     return getMeshMaterialIndex(a) > getMeshMaterialIndex(b);
  369. }
  370. void
  371. Model::sortMeshes(const MeshComparator& comparator)
  372. {
  373.     // Sort submeshes by material; if materials have been uniquified,
  374.     // then the submeshes will be ordered so that opaque ones are first.
  375.     for (vector<Mesh*>::const_iterator iter = meshes.begin();
  376.          iter != meshes.end(); iter++)
  377.     {
  378.         (*iter)->aggregateByMaterial();
  379.     }
  380.     // Sort the meshes so that completely opaque ones are first
  381.     sort(meshes.begin(), meshes.end(), MeshComparatorAdapter(comparator));
  382. }