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

OpenGL

开发平台:

Visual C++

  1. // 3dsread.cpp
  2. //
  3. // Copyright (C) 2000, 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 <iomanip>
  10. #include "3dschunk.h"
  11. #include "3dsmodel.h"
  12. #include "3dsread.h"
  13. #include <celutil/bytes.h>
  14. #include <celutil/debug.h>
  15. using namespace std;
  16. typedef bool (*ProcessChunkFunc)(ifstream& in,
  17.                                  unsigned short chunkType,
  18.                                  int contentSize,
  19.                                  void*);
  20. static int read3DSChunk(ifstream& in,
  21.                         ProcessChunkFunc chunkFunc,
  22.                         void* obj);
  23. // For pretty printing debug info
  24. static int logIndent = 0;
  25. static int32 readInt(ifstream& in)
  26. {
  27.     int32 ret;
  28.     in.read((char *) &ret, sizeof(int32));
  29.     LE_TO_CPU_INT32(ret, ret);
  30.     return ret;
  31. }
  32. static int16 readShort(ifstream& in)
  33. {
  34.     int16 ret;
  35.     in.read((char *) &ret, sizeof(int16));
  36.     LE_TO_CPU_INT16(ret, ret);
  37.     return ret;
  38. }
  39. static uint16 readUshort(ifstream& in)
  40. {
  41.     uint16 ret;
  42.     in.read((char *) &ret, sizeof(uint16));
  43.     LE_TO_CPU_INT16(ret, ret);
  44.     return ret;
  45. }
  46. static float readFloat(ifstream& in)
  47. {
  48.     float f;
  49.     in.read((char*) &f, sizeof(float));
  50.     LE_TO_CPU_FLOAT(f, f);
  51.     return f;
  52. }
  53. static char readChar(ifstream& in)
  54. {
  55.     char c;
  56.     in.read(&c, 1);
  57.     return c;
  58. }
  59. /* Not currently used
  60. static int readString(ifstream& in, char* s, int maxLength)
  61. {
  62.     int count;
  63.     for (count = 0; count < maxLength; count++)
  64.     {
  65.         in.read(s + count, 1);
  66.         if (s[count] == '')
  67.             break;
  68.     }
  69.     return count;
  70. }*/
  71. static string readString(ifstream& in)
  72. {
  73.     char s[1024];
  74.     int maxLength = sizeof(s);
  75.     for (int count = 0; count < maxLength; count++)
  76.     {
  77.         in.read(s + count, 1);
  78.         if (s[count] == '')
  79.             break;
  80.     }
  81.     return string(s);
  82. }
  83. static void skipBytes(ifstream& in, int count)
  84. {
  85.     char c;
  86.     while (count-- > 0)
  87.         in.get(c);
  88. }
  89. void indent()
  90. {
  91.     for (int i = 0; i < logIndent; i++)
  92.         cout << "  ";
  93. }
  94. void logChunk(uint16 chunkType/*, int chunkSize*/)
  95. {
  96.     const char* name = NULL;
  97.     switch (chunkType)
  98.     {
  99.     case M3DCHUNK_NULL:
  100.         name = "M3DCHUNK_NULL"; break;
  101.     case M3DCHUNK_VERSION:
  102.         name = "M3DCHUNK_VERSION"; break;
  103.     case M3DCHUNK_COLOR_FLOAT:
  104.         name = "M3DCHUNK_COLOR_FLOAT"; break;
  105.     case M3DCHUNK_COLOR_24:
  106.         name = "M3DCHUNK_COLOR_24"; break;
  107.     case M3DCHUNK_LIN_COLOR_F:
  108.         name = "M3DCHUNK_LIN_COLOR_F"; break;
  109.     case M3DCHUNK_INT_PERCENTAGE:
  110.         name = "M3DCHUNK_INT_PERCENTAGE"; break;
  111.     case M3DCHUNK_FLOAT_PERCENTAGE:
  112.         name = "M3DCHUNK_FLOAT_PERCENTAGE"; break;
  113.     case M3DCHUNK_MASTER_SCALE:
  114.         name = "M3DCHUNK_MASTER_SCALE"; break;
  115.     case M3DCHUNK_BACKGROUND_COLOR:
  116.         name = "M3DCHUNK_BACKGROUND_COLOR"; break;
  117.     case M3DCHUNK_MESHDATA:
  118.         name = "M3DCHUNK_MESHDATA"; break;
  119.     case M3DCHUNK_MESH_VERSION:
  120.         name = "M3DCHUNK_MESHVERSION"; break;
  121.     case M3DCHUNK_NAMED_OBJECT:
  122.         name = "M3DCHUNK_NAMED_OBJECT"; break;
  123.     case M3DCHUNK_TRIANGLE_MESH:
  124.         name = "M3DCHUNK_TRIANGLE_MESH"; break;
  125.     case M3DCHUNK_POINT_ARRAY:
  126.         name = "M3DCHUNK_POINT_ARRAY"; break;
  127.     case M3DCHUNK_POINT_FLAG_ARRAY:
  128.         name = "M3DCHUNK_POINT_FLAG_ARRAY"; break;
  129.     case M3DCHUNK_FACE_ARRAY:
  130.         name = "M3DCHUNK_FACE_ARRAY"; break;
  131.     case M3DCHUNK_MESH_MATERIAL_GROUP:
  132.         name = "M3DCHUNK_MESH_MATERIAL_GROUP"; break;
  133.     case M3DCHUNK_MESH_TEXTURE_COORDS:
  134.         name = "M3DCHUNK_MESH_TEXTURE_COORDS"; break;
  135.     case M3DCHUNK_MESH_SMOOTH_GROUP:
  136.         name = "M3DCHUNK_MESH_SMOOTH_GROUP"; break;
  137.     case M3DCHUNK_MESH_MATRIX:
  138.         name = "M3DCHUNK_MESH_MATRIX"; break;
  139.     case M3DCHUNK_MAGIC:
  140.         name = "M3DCHUNK_MAGIC"; break;
  141.     case M3DCHUNK_MATERIAL_NAME:
  142.         name = "M3DCHUNK_MATERIAL_NAME"; break;
  143.     case M3DCHUNK_MATERIAL_AMBIENT:
  144.         name = "M3DCHUNK_MATERIAL_AMBIENT"; break;
  145.     case M3DCHUNK_MATERIAL_DIFFUSE:
  146.         name = "M3DCHUNK_MATERIAL_DIFFUSE"; break;
  147.     case M3DCHUNK_MATERIAL_SPECULAR:
  148.         name = "M3DCHUNK_MATERIAL_SPECULAR"; break;
  149.     case M3DCHUNK_MATERIAL_SHININESS:
  150.         name = "M3DCHUNK_MATERIAL_SHININESS"; break;
  151.     case M3DCHUNK_MATERIAL_SHIN2PCT:
  152.         name = "M3DCHUNK_MATERIAL_SHIN2PCT"; break;
  153.     case M3DCHUNK_MATERIAL_TRANSPARENCY:
  154.         name = "M3DCHUNK_MATERIAL_TRANSPARENCY"; break;
  155.     case M3DCHUNK_MATERIAL_XPFALL:
  156.         name = "M3DCHUNK_MATERIAL_XPFALL"; break;
  157.     case M3DCHUNK_MATERIAL_REFBLUR:
  158.         name = "M3DCHUNK_MATERIAL_REFBLUR"; break;
  159.     case M3DCHUNK_MATERIAL_TEXMAP:
  160.         name = "M3DCHUNK_MATERIAL_TEXMAP"; break;
  161.     case M3DCHUNK_MATERIAL_MAPNAME:
  162.         name = "M3DCHUNK_MATERIAL_MAPNAME"; break;
  163.     case M3DCHUNK_MATERIAL_ENTRY:
  164.         name = "M3DCHUNK_MATERIAL_ENTRY"; break;
  165.     case M3DCHUNK_KFDATA:
  166.         name = "M3DCHUNK_KFDATA";
  167.     default:
  168.         break;
  169.     }
  170. #if 0
  171.     indent();
  172.     if (name == NULL)
  173.     {
  174.         cout << "Chunk ID " << setw(4) << hex << setfill('0') << chunkType;
  175.         cout << setw(0) << dec << ", size = " << chunkSize << 'n';
  176.     }
  177.     else
  178.     {
  179.         cout << name << ", size = " << chunkSize << 'n';
  180.     }
  181.     cout.flush();
  182. #endif
  183. }
  184. int read3DSChunk(ifstream& in,
  185.                  ProcessChunkFunc chunkFunc,
  186.                  void* obj)
  187. {
  188.     unsigned short chunkType = readUshort(in);
  189.     int32 chunkSize = readInt(in);
  190.     int contentSize = chunkSize - 6;
  191.     //logChunk(chunkType/*, chunkSize*/);
  192.     bool chunkWasRead = chunkFunc(in, chunkType, contentSize, obj);
  193.     if (!chunkWasRead)
  194.     {
  195.         skipBytes(in, contentSize);
  196.     }
  197.     return chunkSize;
  198. }
  199. int read3DSChunks(ifstream& in,
  200.                   int nBytes,
  201.                   ProcessChunkFunc chunkFunc,
  202.                   void* obj)
  203. {
  204.     int bytesRead = 0;
  205.     logIndent++;
  206.     while (bytesRead < nBytes)
  207.         bytesRead += read3DSChunk(in, chunkFunc, obj);
  208.     logIndent--;
  209.     if (bytesRead != nBytes)
  210.         cout << "Expected " << nBytes << " bytes but read " << bytesRead << 'n';
  211.     return bytesRead;
  212. }
  213. M3DColor readColor(ifstream& in/*, int nBytes*/)
  214. {
  215.     unsigned char r = (unsigned char) readChar(in);
  216.     unsigned char g = (unsigned char) readChar(in);
  217.     unsigned char b = (unsigned char) readChar(in);
  218.     return M3DColor((float) r / 255.0f,
  219.                     (float) g / 255.0f,
  220.                     (float) b / 255.0f);
  221. }
  222. M3DColor readFloatColor(ifstream& in/*, int nBytes*/)
  223. {
  224.     float r = readFloat(in);
  225.     float g = readFloat(in);
  226.     float b = readFloat(in);
  227.     return M3DColor((float) r / 255.0f,
  228.                     (float) g / 255.0f,
  229.                     (float) b / 255.0f);
  230. }
  231. Mat4f readMeshMatrix(ifstream& in/*, int nBytes*/)
  232. {
  233.     float m00 = readFloat(in);
  234.     float m01 = readFloat(in);
  235.     float m02 = readFloat(in);
  236.     float m10 = readFloat(in);
  237.     float m11 = readFloat(in);
  238.     float m12 = readFloat(in);
  239.     float m20 = readFloat(in);
  240.     float m21 = readFloat(in);
  241.     float m22 = readFloat(in);
  242.     float m30 = readFloat(in);
  243.     float m31 = readFloat(in);
  244.     float m32 = readFloat(in);
  245. #if 0
  246.     cout << m00 << "   " << m01 << "   " << m02 << 'n';
  247.     cout << m10 << "   " << m11 << "   " << m12 << 'n';
  248.     cout << m20 << "   " << m21 << "   " << m22 << 'n';
  249.     cout << m30 << "   " << m31 << "   " << m32 << 'n';
  250. #endif
  251.     return Mat4f(Vec4f(m00, m01, m02, 0),
  252.                  Vec4f(m10, m11, m12, 0),
  253.                  Vec4f(m20, m21, m22, 0),
  254.                  Vec4f(m30, m31, m32, 1));
  255. }
  256. bool stubProcessChunk(/* ifstream& in,
  257.                          unsigned short chunkType,
  258.                          int contentSize,
  259.                          void* obj */)
  260. {
  261.     return false;
  262. }
  263. void readPointArray(ifstream& in, M3DTriangleMesh* triMesh)
  264. {
  265.     uint16 nPoints = readUshort(in);
  266.     for (int i = 0; i < (int) nPoints; i++)
  267.     {
  268.         float x = readFloat(in);
  269.         float y = readFloat(in);
  270.         float z = readFloat(in);
  271.         triMesh->addVertex(Point3f(x, y, z));
  272.     }
  273. }
  274. void readTextureCoordArray(ifstream& in, M3DTriangleMesh* triMesh)
  275. {
  276.     uint16 nPoints = readUshort(in);
  277.     for (int i = 0; i < (int) nPoints; i++)
  278.     {
  279.         float u = readFloat(in);
  280.         float v = readFloat(in);
  281.         triMesh->addTexCoord(Point2f(u, -v));
  282.     }
  283. }
  284. bool processFaceArrayChunk(ifstream& in,
  285.                            unsigned short chunkType,
  286.                            int /*contentSize*/,
  287.                            void* obj)
  288. {
  289.     M3DTriangleMesh* triMesh = (M3DTriangleMesh*) obj;
  290.     if (chunkType == M3DCHUNK_MESH_MATERIAL_GROUP)
  291.     {
  292.         // For now, we just assume that there is only one material group
  293.         // per triangle mesh, and that the material applies to all faces in
  294.         // the mesh.
  295.         string materialName = readString(in);
  296.         uint16 nFaces = readUshort(in);
  297.         for (uint16 i = 0; i < nFaces; i++)
  298.         {
  299.             readUshort(in);
  300.         }
  301.         triMesh->setMaterialName(materialName);
  302.         return true;
  303.     }
  304.     else if (chunkType == M3DCHUNK_MESH_SMOOTH_GROUP)
  305.     {
  306.         uint16 nFaces = triMesh->getFaceCount();
  307.         for (uint16 i = 0; i < nFaces; i++)
  308.         {
  309.             uint32 groups = (uint32) readInt(in);
  310.             //            cout << setw(8) << hex << setfill('0') << groups << dec << setw(0) << 'n';
  311.             triMesh->addSmoothingGroups(groups);
  312.         }
  313.         return true;
  314.     }
  315.     else
  316.     {
  317.         return false;
  318.     }
  319. }
  320. void readFaceArray(ifstream& in, M3DTriangleMesh* triMesh, int contentSize)
  321. {
  322.     uint16 nFaces = readUshort(in);
  323.     for (int i = 0; i < (int) nFaces; i++)
  324.     {
  325.         uint16 v0 = readUshort(in);
  326.         uint16 v1 = readUshort(in);
  327.         uint16 v2 = readUshort(in);
  328.         /*uint16 flags = */ readUshort(in);
  329.         triMesh->addFace(v0, v1, v2);
  330.     }
  331.     int bytesLeft = contentSize - (8 * nFaces + 2);
  332.     if (bytesLeft > 0)
  333.     {
  334.         read3DSChunks(in,
  335.                       bytesLeft,
  336.                       processFaceArrayChunk,
  337.                       (void*) triMesh);
  338.     }
  339. }
  340. bool processTriMeshChunk(ifstream& in,
  341.                          unsigned short chunkType,
  342.                          int contentSize,
  343.                          void* obj)
  344. {
  345.     M3DTriangleMesh* triMesh = (M3DTriangleMesh*) obj;
  346.     if (chunkType == M3DCHUNK_POINT_ARRAY)
  347.     {
  348.         readPointArray(in, triMesh);
  349.         return true;
  350.     }
  351.     else if (chunkType == M3DCHUNK_MESH_TEXTURE_COORDS)
  352.     {
  353.         readTextureCoordArray(in, triMesh);
  354.         return true;
  355.     }
  356.     else if (chunkType == M3DCHUNK_FACE_ARRAY)
  357.     {
  358.         readFaceArray(in, triMesh, contentSize);
  359.         return true;
  360.     }
  361.     else if (chunkType == M3DCHUNK_MESH_MATRIX)
  362.     {
  363.         triMesh->setMatrix(readMeshMatrix(in/*, contentSize*/));
  364.         return true;
  365.     }
  366.     else
  367.     {
  368.         return false;
  369.     }
  370. }
  371. bool processModelChunk(ifstream& in,
  372.                        unsigned short chunkType,
  373.                        int contentSize,
  374.                        void* obj)
  375. {
  376.     M3DModel* model = (M3DModel*) obj;
  377.     if (chunkType == M3DCHUNK_TRIANGLE_MESH)
  378.     {
  379.         M3DTriangleMesh* triMesh = new M3DTriangleMesh();
  380.         read3DSChunks(in, contentSize, processTriMeshChunk, (void*) triMesh);
  381.         model->addTriMesh(triMesh);
  382.         return true;
  383.     }
  384.     else
  385.     {
  386.         return false;
  387.     }
  388. }
  389. bool processColorChunk(ifstream& in,
  390.                        unsigned short chunkType,
  391.                        int /*contentSize*/,
  392.                        void* obj)
  393. {
  394.     M3DColor* color = (M3DColor*) obj;
  395.     if (chunkType == M3DCHUNK_COLOR_24)
  396.     {
  397.         *color = readColor(in/*, contentSize*/);
  398.         return true;
  399.     }
  400.     else if (chunkType == (M3DCHUNK_COLOR_FLOAT))
  401.     {
  402.         *color = readFloatColor(in/*, contentSize*/);
  403.         return true;
  404.     }
  405.     else
  406.     {
  407.         return false;
  408.     }
  409. }
  410. static bool processPercentageChunk(ifstream& in,
  411.                                    unsigned short chunkType,
  412.                                    int /*contentSize*/,
  413.                                    void* obj)
  414. {
  415.     float* percent = (float*) obj;
  416.     if (chunkType == M3DCHUNK_INT_PERCENTAGE)
  417.     {
  418.         *percent = readShort(in);
  419.         return true;
  420.     }
  421.     else if (chunkType == M3DCHUNK_FLOAT_PERCENTAGE)
  422.     {
  423.         *percent = readFloat(in);
  424.         return true;
  425.     }
  426.     else
  427.     {
  428.         return false;
  429.     }
  430. }
  431. static bool processTexmapChunk(ifstream& in,
  432.                                unsigned short chunkType,
  433.                                int /*contentSize*/,
  434.                                void* obj)
  435. {
  436.     M3DMaterial* material = (M3DMaterial*) obj;
  437.     if (chunkType == M3DCHUNK_MATERIAL_MAPNAME)
  438.     {
  439.         string name = readString(in);
  440.         material->setTextureMap(name);
  441.         return true;
  442.     }
  443.     else
  444.     {
  445.         return false;
  446.     }
  447. }
  448. bool processMaterialChunk(ifstream& in,
  449.                           unsigned short chunkType,
  450.                           int contentSize,
  451.                           void* obj)
  452. {
  453.     M3DMaterial* material = (M3DMaterial*) obj;
  454.     if (chunkType == M3DCHUNK_MATERIAL_NAME)
  455.     {
  456.         string name = readString(in);
  457.         material->setName(name);
  458.         return true;
  459.     }
  460.     else if (chunkType == M3DCHUNK_MATERIAL_AMBIENT)
  461.     {
  462.         M3DColor ambient;
  463.         read3DSChunks(in, contentSize, processColorChunk, (void*) &ambient);
  464.         material->setAmbientColor(ambient);
  465.         return true;
  466.     }
  467.     else if (chunkType == M3DCHUNK_MATERIAL_DIFFUSE)
  468.     {
  469.         M3DColor diffuse;
  470.         read3DSChunks(in, contentSize, processColorChunk, (void*) &diffuse);
  471.         material->setDiffuseColor(diffuse);
  472.         return true;
  473.     }
  474.     else if (chunkType == M3DCHUNK_MATERIAL_SPECULAR)
  475.     {
  476.         M3DColor specular;
  477.         read3DSChunks(in, contentSize, processColorChunk, (void*) &specular);
  478.         material->setSpecularColor(specular);
  479.         return true;
  480.     }
  481.     else if (chunkType == M3DCHUNK_MATERIAL_SHININESS)
  482.     {
  483.         float shininess;
  484.         read3DSChunks(in, contentSize, processPercentageChunk,
  485.                       (void*) &shininess);
  486.         material->setShininess(shininess);
  487.         return true;
  488.     }
  489.     else if (chunkType == M3DCHUNK_MATERIAL_TRANSPARENCY)
  490.     {
  491.         float transparency;
  492.         read3DSChunks(in, contentSize, processPercentageChunk,
  493.                       (void*) &transparency);
  494.         material->setOpacity(1.0f - transparency / 100.0f);
  495.         return true;
  496.     }
  497.     else if (chunkType == M3DCHUNK_MATERIAL_TEXMAP)
  498.     {
  499.         read3DSChunks(in, contentSize, processTexmapChunk, (void*) material);
  500.         return true;
  501.     }
  502.     else
  503.     {
  504.         return false;
  505.     }
  506. }
  507. bool processSceneChunk(ifstream& in,
  508.                        unsigned short chunkType,
  509.                        int contentSize,
  510.                        void* obj)
  511. {
  512.     M3DScene* scene = (M3DScene*) obj;
  513.     if (chunkType == M3DCHUNK_NAMED_OBJECT)
  514.     {
  515.         string name = readString(in);
  516.         M3DModel* model = new M3DModel();
  517.         model->setName(name);
  518.         // indent(); cout << "  [" << name << "]n";
  519.         read3DSChunks(in,
  520.                       contentSize - (name.length() + 1),
  521.                       processModelChunk,
  522.                       (void*) model);
  523.         scene->addModel(model);
  524.         return true;
  525.     }
  526.     else if (chunkType == M3DCHUNK_MATERIAL_ENTRY)
  527.     {
  528.         M3DMaterial* material = new M3DMaterial();
  529.         read3DSChunks(in,
  530.                       contentSize,
  531.                       processMaterialChunk,
  532.                       (void*) material);
  533.         scene->addMaterial(material);
  534.         return true;
  535.     }
  536.     else if (chunkType == M3DCHUNK_BACKGROUND_COLOR)
  537.     {
  538.         M3DColor color;
  539.         read3DSChunks(in, contentSize, processColorChunk, (void*) &color);
  540.         scene->setBackgroundColor(color);
  541.         return true;
  542.     }
  543.     else
  544.     {
  545.         return false;
  546.     }
  547. }
  548. bool processTopLevelChunk(ifstream& in,
  549.                           unsigned short chunkType,
  550.                           int contentSize,
  551.                           void* obj)
  552. {
  553.     M3DScene* scene = (M3DScene*) obj;
  554.     if (chunkType == M3DCHUNK_MESHDATA)
  555.     {
  556.         read3DSChunks(in, contentSize, processSceneChunk, (void*) scene);
  557.         return true;
  558.     }
  559.     else
  560.     {
  561.         return false;
  562.     }
  563. }
  564. M3DScene* Read3DSFile(ifstream& in)
  565. {
  566.     unsigned short chunkType = readUshort(in);
  567.     if (chunkType != M3DCHUNK_MAGIC)
  568.     {
  569.         DPRINTF(0, "Read3DSFile: Wrong magic number in headern");
  570.         return NULL;
  571.     }
  572.     int32 chunkSize = readInt(in);
  573.     if (in.bad())
  574.     {
  575.         DPRINTF(0, "Read3DSFile: Error reading 3DS file.n");
  576.         return NULL;
  577.     }
  578.     DPRINTF(1, "3DS file, %d bytesn", chunkSize);
  579.     M3DScene* scene = new M3DScene();
  580.     int contentSize = chunkSize - 6;
  581.     read3DSChunks(in, contentSize, processTopLevelChunk, (void*) scene);
  582.     return scene;
  583. }
  584. M3DScene* Read3DSFile(const string& filename)
  585. {
  586.     ifstream in(filename.c_str(), ios::in | ios::binary);
  587.     if (!in.good())
  588.     {
  589.         DPRINTF(0, "Read3DSFile: Error opening %sn", filename.c_str());
  590.         return NULL;
  591.     }
  592.     else
  593.     {
  594.         M3DScene* scene = Read3DSFile(in);
  595.         in.close();
  596.         return scene;
  597.     }
  598. }
  599. #if 0
  600. int main(int argc, char* argv[])
  601. {
  602.     if (argc != 2)
  603.     {
  604.         cerr << "Usage: 3dsread <filename>n";
  605.         exit(1);
  606.     }
  607.     ifstream in(argv[1], ios::in | ios::binary);
  608.     if (!in.good())
  609.     {
  610.         cerr << "Error opening " << argv[1] << 'n';
  611.         exit(1);
  612.     }
  613.     else
  614.     {
  615.         read3DSFile(in);
  616.         in.close();
  617.     }
  618.     return 0;
  619. }
  620. #endif