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

OpenGL

开发平台:

Visual C++

  1. // 3dsmesh.cpp
  2. // 
  3. // Copyright (C) 2001, 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 <algorithm>
  10. #include <iostream>
  11. #include "gl.h"
  12. #ifndef MACOSX
  13. #include "glext.h"
  14. #endif /* MACOSX */
  15. #include "vertexprog.h"
  16. #include "texmanager.h"
  17. #include "3dsmesh.h"
  18. using namespace std;
  19. static VertexList* convertToVertexList(M3DTriangleMesh& mesh,
  20.                                        const M3DScene& scene,
  21.                                        const string& texturePath);
  22. // Function to sort vertex lists so that transparent ones are rendered
  23. // after the opaque ones, and vertex lists with the same material properties
  24. // are grouped together.
  25. static int compareVertexLists(VertexList* vl0, VertexList* vl1)
  26. {
  27.     float a0 = vl0->getDiffuseColor().alpha();
  28.     float a1 = vl1->getDiffuseColor().alpha();
  29. #if _MSC_VER <= 1200
  30.     // In some cases, sorting with this comparison function hangs on Celestia
  31.     // executables built with MSVC.  For some reason, adding the following crud
  32.     // fixes the problem, but I haven't looked at the generated assembly
  33.     // instructions to figure out what's going on.  In any case, the output
  34.     // should never be printed because alpha is always >= 0.  Blah.
  35.     if (a0 == -50.0f)
  36.         cout << "Stupid MSVC compiler bug workaround!  (This line will never be printed)n";
  37. #endif
  38.     if (a0 == a1)
  39.     {
  40.         return vl0->getTexture() < vl1->getTexture();
  41.     }
  42.     else
  43.     {
  44.         return (a0 > a1);
  45.     }
  46. }
  47. Mesh3DS::Mesh3DS(const M3DScene& scene, const string& texturePath)
  48. {
  49.     for (unsigned int i = 0; i < scene.getModelCount(); i++)
  50.     {
  51.         M3DModel* model = scene.getModel(i);
  52.         if (model != NULL)
  53.         {
  54.             for (unsigned int j = 0; j < model->getTriMeshCount(); j++)
  55.             {
  56.                 M3DTriangleMesh* mesh = model->getTriMesh(j);
  57.                 if (mesh != NULL)
  58.                 {
  59.                     vertexLists.insert(vertexLists.end(),
  60.                                        convertToVertexList(*mesh, scene, texturePath));
  61.                 }
  62.             }
  63.         }
  64.     }
  65.     // Sort the vertex lists to make sure that the transparent ones are
  66.     // rendered after the opaque ones and material state changes are minimized.
  67.     sort(vertexLists.begin(), vertexLists.end(), compareVertexLists);
  68. }
  69. Mesh3DS::~Mesh3DS()
  70. {
  71.     for (VertexListVec::iterator i = vertexLists.begin(); i != vertexLists.end(); i++)
  72.         if (*i != NULL)
  73.             delete *i;
  74. }
  75. void Mesh3DS::render(float lod)
  76. {
  77.     render(Normals | Colors, lod);
  78. }
  79. void Mesh3DS::render(unsigned int attributes, float)
  80. {
  81.     TextureManager* textureManager = GetTextureManager();
  82.     ResourceHandle currentTexture = InvalidResource;
  83.     bool specularOn = false;
  84.     bool blendOn = false;
  85.     Color black(0.0f, 0.0f, 0.0f);
  86.     int count = 0;
  87.     for (VertexListVec::iterator i = vertexLists.begin(); i != vertexLists.end(); i++)
  88.     {
  89.         // Don't mess with the material, texture, blend function, etc. if the
  90.         // multipass attribute is set--when the multipass flag is on, all this
  91.         // state will have been set up by the caller in order to produce some
  92.         // effect (e.g. shadows).
  93.         if ((attributes & Multipass) == 0)
  94.         {
  95.             // Ugly hack to set the diffuse color parameters when vertex
  96.             // programs are enabled.
  97.             if (attributes & VertexProgParams)
  98.                 vp::parameter(20, (*i)->getDiffuseColor());
  99.             // All the vertex lists should have been sorted so that the
  100.             // transparent ones are after the opaque ones.  Thus we can assume
  101.             // that once we find a transparent vertext list, it's ok to leave
  102.             // blending on.
  103.             if (!blendOn && (*i)->getDiffuseColor().alpha() <= 254.0f / 255.0f)
  104.             {
  105.                 glEnable(GL_BLEND);
  106.                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  107.             }
  108.             Color specular = (*i)->getSpecularColor();
  109.             float shininess = (*i)->getShininess();
  110.             ResourceHandle texture = (*i)->getTexture();
  111.             bool useSpecular = (specular != black);
  112.             if (specularOn && !useSpecular)
  113.             {
  114.                 float matSpecular[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
  115.                 float zero = 0.0f;
  116.                 glMaterialfv(GL_FRONT, GL_SPECULAR, matSpecular);
  117.                 glMaterialfv(GL_FRONT, GL_SHININESS, &zero);
  118.             }
  119.             if (useSpecular)
  120.             {
  121.                 float matSpecular[4] = { specular.red(), specular.green(),
  122.                                              specular.blue(), 1.0f };
  123.                 glMaterialfv(GL_FRONT, GL_SPECULAR, matSpecular);
  124.                 glMaterialfv(GL_FRONT, GL_SHININESS, &shininess);
  125.             }
  126.             specularOn = useSpecular;
  127.             if (currentTexture != texture)
  128.             {
  129.                 if (texture == InvalidResource)
  130.                 {
  131.                     glDisable(GL_TEXTURE_2D);
  132.                 }
  133.                 else
  134.                 {
  135.                     if (currentTexture == InvalidResource)
  136.                         glEnable(GL_TEXTURE_2D);
  137.                     Texture* t = textureManager->find(texture);
  138.                     if (t != NULL)
  139.                         t->bind();
  140.                 }
  141.                 currentTexture = texture;
  142.             }
  143.         }
  144.         
  145.         (*i)->render();
  146.     }
  147.     if (specularOn)
  148.     {
  149.         float matSpecular[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
  150.         float zero = 0.0f;
  151.         glMaterialfv(GL_FRONT, GL_SPECULAR, matSpecular);
  152.         glMaterialfv(GL_FRONT, GL_SHININESS, &zero);
  153.     }
  154.     if (blendOn)
  155.     {
  156.         glDisable(GL_BLEND);
  157.         glBlendFunc(GL_SRC_ALPHA, GL_ONE);
  158.     }
  159. }
  160. void Mesh3DS::render(unsigned int attributes, const Frustum&, float lod)
  161. {
  162.     render(attributes, lod);
  163. }
  164. bool Mesh3DS::pick(const Ray3d& r, double& distance)
  165. {
  166.     double maxDistance = 1.0e30;
  167.     double closest = maxDistance;
  168.     for (VertexListVec::const_iterator iter = vertexLists.begin();
  169.          iter != vertexLists.end(); iter++)
  170.     {
  171.         double d = maxDistance;
  172.         if ((*iter)->pick(r, d) && d < closest)
  173.             closest = d;
  174.     }    
  175.     if (closest != maxDistance)
  176.     {
  177.         distance = closest;
  178.         return true;
  179.     }
  180.     else
  181.     {
  182.         return false;
  183.     }
  184. }
  185. // Transform and scale the model so that it fits into an axis aligned bounding
  186. // box with corners at (1, 1, 1) and (-1, -1, -1)
  187. void Mesh3DS::normalize(const Vec3f& centerOffset)
  188. {
  189.     AxisAlignedBox bbox;
  190.     VertexListVec::iterator i;
  191.     for (i = vertexLists.begin(); i != vertexLists.end(); i++)
  192.         bbox.include((*i)->getBoundingBox());
  193.     Point3f center = bbox.getCenter() + centerOffset;
  194.     Vec3f extents = bbox.getExtents();
  195.     float maxExtent = extents.x;
  196.     if (extents.y > maxExtent)
  197.         maxExtent = extents.y;
  198.     if (extents.z > maxExtent)
  199.         maxExtent = extents.z;
  200.     for (i = vertexLists.begin(); i != vertexLists.end(); i++)
  201.         (*i)->transform(Point3f(0, 0, 0) - center, 2.0f / maxExtent);
  202. }
  203. static VertexList* convertToVertexList(M3DTriangleMesh& mesh,
  204.                                        const M3DScene& scene,
  205.                                        const string& texturePath)
  206. {
  207.     int nFaces = mesh.getFaceCount();
  208.     int nVertices = mesh.getVertexCount();
  209.     int nTexCoords = mesh.getTexCoordCount();
  210.     bool smooth = (mesh.getSmoothingGroupCount() == nFaces);
  211.     int i;
  212.     uint32 parts = VertexList::VertexNormal;
  213.     if (nTexCoords == nVertices)
  214.         parts |= VertexList::TexCoord0;
  215.     VertexList* vl = new VertexList(parts);
  216.     
  217.     Vec3f* faceNormals = new Vec3f[nFaces];
  218.     Vec3f* vertexNormals = new Vec3f[nFaces * 3];
  219.     int* faceCounts = new int[nVertices];
  220.     int** vertexFaces = new int*[nVertices];
  221.     for (i = 0; i < nVertices; i++)
  222.     {
  223.         faceCounts[i] = 0;
  224.         vertexFaces[i] = NULL;
  225.     }
  226.     // generate face normals
  227.     for (i = 0; i < nFaces; i++)
  228.     {
  229.         uint16 v0, v1, v2;
  230.         mesh.getFace(i, v0, v1, v2);
  231.         faceCounts[v0]++;
  232.         faceCounts[v1]++;
  233.         faceCounts[v2]++;
  234.         Point3f p0 = mesh.getVertex(v0);
  235.         Point3f p1 = mesh.getVertex(v1);
  236.         Point3f p2 = mesh.getVertex(v2);
  237.         faceNormals[i] = cross(p1 - p0, p2 - p1);
  238.         faceNormals[i].normalize();
  239.     }
  240.     if (!smooth && 0)
  241.     {
  242.         for (i = 0; i < nFaces; i++)
  243.         {
  244.             vertexNormals[i * 3] = faceNormals[i];
  245.             vertexNormals[i * 3 + 1] = faceNormals[i];
  246.             vertexNormals[i * 3 + 2] = faceNormals[i];
  247.         }
  248.     }
  249.     else
  250.     {
  251.         // allocate space for vertex face indices
  252.         for (i = 0; i < nVertices; i++)
  253.         {
  254.             vertexFaces[i] = new int[faceCounts[i] + 1];
  255.             vertexFaces[i][0] = faceCounts[i];
  256.         }
  257.         for (i = 0; i < nFaces; i++)
  258.         {
  259.             uint16 v0, v1, v2;
  260.             mesh.getFace(i, v0, v1, v2);
  261.             vertexFaces[v0][faceCounts[v0]--] = i;
  262.             vertexFaces[v1][faceCounts[v1]--] = i;
  263.             vertexFaces[v2][faceCounts[v2]--] = i;
  264.         }
  265.         // average face normals to compute the vertex normals
  266.         for (i = 0; i < nFaces; i++)
  267.         {
  268.             uint16 v0, v1, v2;
  269.             mesh.getFace(i, v0, v1, v2);
  270.             // uint32 smoothingGroups = mesh.getSmoothingGroups(i);
  271.             int j;
  272.             Vec3f v = Vec3f(0, 0, 0);
  273.             for (j = 1; j <= vertexFaces[v0][0]; j++)
  274.             {
  275.                 int k = vertexFaces[v0][j];
  276.                 // if (k == i || (smoothingGroups & mesh.getSmoothingGroups(k)) != 0)
  277.                 if (faceNormals[i] * faceNormals[k] > 0.5f)
  278.                     v += faceNormals[k];
  279.             }
  280.             v.normalize();
  281.             vertexNormals[i * 3] = v;
  282.             v = Vec3f(0, 0, 0);
  283.             for (j = 1; j <= vertexFaces[v1][0]; j++)
  284.             {
  285.                 int k = vertexFaces[v1][j];
  286.                 // if (k == i || (smoothingGroups & mesh.getSmoothingGroups(k)) != 0)
  287.                 if (faceNormals[i] * faceNormals[k] > 0.5f)
  288.                     v += faceNormals[k];
  289.             }
  290.             v.normalize();
  291.             vertexNormals[i * 3 + 1] = v;
  292.             v = Vec3f(0, 0, 0);
  293.             for (j = 1; j <= vertexFaces[v2][0]; j++)
  294.             {
  295.                 int k = vertexFaces[v2][j];
  296.                 // if (k == i || (smoothingGroups & mesh.getSmoothingGroups(k)) != 0)
  297.                 if (faceNormals[i] * faceNormals[k] > 0.5f)
  298.                     v += faceNormals[k];
  299.             }
  300.             v.normalize();
  301.             vertexNormals[i * 3 + 2] = v;
  302.         }
  303.     }
  304.     // build the triangle list
  305.     for (i = 0; i < nFaces; i++)
  306.     {
  307.         uint16 triVert[3];
  308.         mesh.getFace(i, triVert[0], triVert[1], triVert[2]);
  309.         for (int j = 0; j < 3; j++)
  310.         {
  311.             VertexList::Vertex v;
  312.             v.point = mesh.getVertex(triVert[j]);
  313.             v.normal = vertexNormals[i * 3 + j];
  314.             if ((parts & VertexList::TexCoord0) != 0)
  315.                 v.texCoords[0] = mesh.getTexCoord(triVert[j]);
  316.             vl->addVertex(v);
  317.         }
  318.     }
  319.     // Set the material properties
  320.     {
  321.         string materialName = mesh.getMaterialName();
  322.         if (materialName.length() > 0)
  323.         {
  324.             int nMaterials = scene.getMaterialCount();
  325.             for (i = 0; i < nMaterials; i++)
  326.             {
  327.                 M3DMaterial* material = scene.getMaterial(i);
  328.                 if (materialName == material->getName())
  329.                 {
  330.                     M3DColor diffuse = material->getDiffuseColor();
  331.                     vl->setDiffuseColor(Color(diffuse.red, diffuse.green, diffuse.blue, material->getOpacity()));
  332.                     M3DColor specular = material->getSpecularColor();
  333.                     vl->setSpecularColor(Color(specular.red, specular.green, specular.blue));
  334.                     float shininess = material->getShininess();
  335.                     
  336.                     // Map the shininess from the 3DS file into the 0-128
  337.                     // range that OpenGL uses for the specular exponent.
  338.                     shininess = (float) pow(2, 10.0 * shininess);
  339.                     if (shininess > 128.0f)
  340.                         shininess = 128.0f;
  341.                     vl->setShininess(128.0f);
  342.                     if (material->getTextureMap() != "")
  343.                     {
  344.                         ResourceHandle tex = GetTextureManager()->getHandle(TextureInfo(material->getTextureMap(), texturePath, TextureInfo::WrapTexture));
  345.                         vl->setTexture(tex);
  346.                     }
  347.                     break;
  348.                 }
  349.             }
  350.         }
  351.     }
  352.     // clean up
  353.     if (faceNormals != NULL)
  354.         delete[] faceNormals;
  355.     if (vertexNormals != NULL)
  356.         delete[] vertexNormals;
  357.     if (faceCounts != NULL)
  358.         delete[] faceCounts;
  359.     if (vertexFaces != NULL)
  360.     {
  361.         for (i = 0; i < nVertices; i++)
  362.         {
  363.             if (vertexFaces[i] != NULL)
  364.                 delete[] vertexFaces[i];
  365.         }
  366.         delete[] vertexFaces;
  367.     }
  368.     return vl;
  369. }