Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/src/vlGraphics/plugins/ioMD2.cpp

Go to the documentation of this file.
00001 /**************************************************************************************/
00002 /*                                                                                    */
00003 /*  Visualization Library                                                             */
00004 /*  http://www.visualizationlibrary.org                                               */
00005 /*                                                                                    */
00006 /*  Copyright (c) 2005-2010, Michele Bosi                                             */
00007 /*  All rights reserved.                                                              */
00008 /*                                                                                    */
00009 /*  Redistribution and use in source and binary forms, with or without modification,  */
00010 /*  are permitted provided that the following conditions are met:                     */
00011 /*                                                                                    */
00012 /*  - Redistributions of source code must retain the above copyright notice, this     */
00013 /*  list of conditions and the following disclaimer.                                  */
00014 /*                                                                                    */
00015 /*  - Redistributions in binary form must reproduce the above copyright notice, this  */
00016 /*  list of conditions and the following disclaimer in the documentation and/or       */
00017 /*  other materials provided with the distribution.                                   */
00018 /*                                                                                    */
00019 /*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
00020 /*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
00021 /*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
00022 /*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
00023 /*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
00024 /*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
00025 /*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
00026 /*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
00027 /*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
00028 /*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
00029 /*                                                                                    */
00030 /**************************************************************************************/
00031 
00032 #include "ioMD2.hpp"
00033 #include <vlCore/Time.hpp>
00034 #include <vlCore/Log.hpp>
00035 #include <vlCore/Say.hpp>
00036 #include <vlCore/VisualizationLibrary.hpp>
00037 #include <vlCore/FileSystem.hpp>
00038 #include <vlCore/LoadWriterManager.hpp>
00039 #include <vlGraphics/DoubleVertexRemover.hpp>
00040 
00041 using namespace vl;
00042 
00043 namespace 
00044 {
00045   // MD2 structures and defines
00046   class LoaderMD2
00047   {
00048   public:
00049     LoaderMD2(): verbose(false) {} 
00050 
00051     enum {
00052       MD2_MAX_TRIANGLES = 4096,
00053       MD2_MAX_VERTICES  = 2048,
00054       MD2_MAX_TEXCOORDS = 2048,
00055       MD2_MAX_FRAMES    = 512,
00056       MD2_MAX_SKINS     = 32,
00057       MD2_MAX_FRAMESIZE = MD2_MAX_VERTICES * 4 + 128
00058     };
00059 
00060     class md2_header_info
00061     {
00062     public:
00063        int magic;
00064        int version;
00065        int skinWidth;
00066        int skinHeight;
00067        int frameSize;
00068        int numSkins;
00069        int numVertices;
00070        int numTexCoords;
00071        int numTriangles;
00072        int numGlCommands;
00073        int numFrames;
00074        int offsetSkins;
00075        int offsetTexCoords;
00076        int offsetTriangles;
00077        int offsetFrames;
00078        int offsetGlCommands;
00079        int offsetEnd;
00080     };
00081 
00082     class md2_vertex_info
00083     {
00084     public:
00085       unsigned char vertex[3];
00086       unsigned char light_norm_index;
00087     };
00088 
00089     class md2_triangle_info
00090     {
00091     public:
00092        short vert_idx[3];
00093        short uv_idx[3];
00094     };
00095 
00096     class md2_uv_info
00097     {
00098     public:
00099        short u, v;
00100     };
00101 
00102     class md2_frame_info
00103     {
00104     public:
00105        float scale[3];
00106        float translate[3];
00107        char name[16];
00108        md2_vertex_info vertices[1];
00109     };
00110 
00111     class md2_skin_info
00112     {
00113     public:
00114       unsigned char name[64];
00115     };
00116 
00117     md2_header_info header;
00118     std::vector<md2_frame_info*> md2_frame;
00119     std::vector<md2_uv_info> md2_uv;
00120     std::vector<md2_triangle_info> md2_triangle;
00121     std::vector<md2_skin_info> md2_skin;
00122     bool verbose;
00123   };
00124 }
00125 //-----------------------------------------------------------------------------
00126 ref<ResourceDatabase> vl::loadMD2(const String& path)
00127 {
00128   ref<VirtualFile> file = defFileSystem()->locateFile(path);
00129 
00130   if (file)
00131     return loadMD2( file.get() );
00132   else
00133   {
00134     Log::error( Say("Could not locate '%s'.\n") << path );
00135     return NULL;
00136   }
00137 }
00138 //-----------------------------------------------------------------------------
00139 ref<ResourceDatabase> vl::loadMD2(VirtualFile* file)
00140 {
00141   ref<ResourceDatabase> res_db = new ResourceDatabase;
00142   ref<Geometry> geometry = new Geometry;
00143   res_db->resources().push_back( geometry.get() );
00144 
00145   if (!file->open(OM_ReadOnly))
00146   {
00147     Log::error( Say("Error opening '%s'\n") << file->path() );
00148     return NULL;
00149   }
00150     
00151   LoaderMD2 loader;
00152   file->read( &loader.header, sizeof(loader.header) );
00153   
00154   if (loader.verbose)
00155   {
00156     Log::print( Say("tris  %n:\n") <<  loader.header.numTriangles);
00157     Log::print( Say("verts %n:\n") <<  loader.header.numVertices);
00158     Log::print( Say("uvs   %n:\n") <<  loader.header.numTexCoords);
00159     Log::print( Say("offs skins %n:\n") <<  loader.header.offsetSkins);
00160     Log::print( Say("offs end %n:\n") <<  loader.header.offsetEnd);
00161     Log::print( Say("offs frames %n:\n") <<  loader.header.offsetFrames);
00162     Log::print( Say("offs gl comm %n:\n") <<  loader.header.offsetGlCommands);
00163     Log::print( Say("offs tex coor %n:\n") <<  loader.header.offsetTexCoords);
00164     Log::print( Say("offs tri %n:\n") <<  loader.header.offsetTriangles);
00165     Log::print( Say("skinh %n:\n") <<  loader.header.skinHeight);
00166     Log::print( Say("skinw %n:\n") <<  loader.header.skinWidth);
00167   }
00168 
00169   // load data into memory
00170   file->seekSet(loader.header.offsetFrames);
00171   loader.md2_frame.resize(loader.header.numFrames);
00172   for(unsigned i=0; i<loader.md2_frame.size(); ++i) 
00173   {
00174     loader.md2_frame[i] = (LoaderMD2::md2_frame_info*)malloc(loader.header.frameSize * sizeof(char) );
00175     file->read(loader.md2_frame[i], loader.header.frameSize);
00176   }
00177     
00178   // uv
00179   loader.md2_uv.resize(loader.header.numTexCoords);
00180   file->seekSet( loader.header.offsetTexCoords );
00181   file->read(&loader.md2_uv[0], loader.header.numTexCoords*sizeof(LoaderMD2::md2_uv_info) );  
00182   
00183   // triangles
00184   loader.md2_triangle.resize(loader.header.numTriangles);
00185   file->seekSet(loader.header.offsetTriangles );
00186   file->read(&loader.md2_triangle[0], loader.header.numTriangles*sizeof(LoaderMD2::md2_triangle_info) );  
00187   
00188   // textures 
00189   if (loader.header.numSkins) 
00190   {
00191     loader.md2_skin.resize(loader.header.numSkins);
00192     file->seekSet( loader.header.offsetSkins );
00193     file->read(&loader.md2_skin[0], loader.header.numSkins*sizeof(LoaderMD2::md2_skin_info) );
00194   }
00195   
00196   // fclose(fin);
00197   file->close();
00198   
00199   // conversion
00200 
00201   std::vector< ref<ArrayFloat3> > vertex_frames;
00202   std::vector< ref<ArrayFloat3> > normal_frames;
00203 
00204   // allocate frames
00205   for(int i=0; i<loader.header.numFrames; ++i)
00206   {
00207     vertex_frames.push_back( new ArrayFloat3 );
00208     vertex_frames[i]->resize( 3 * loader.header.numTriangles );
00209     // normals are computed later
00210   }
00211 
00212   ref<DrawElementsUInt> polygons = new DrawElementsUInt;
00213   ref<ArrayFloat2> tex_coords = new ArrayFloat2;
00214   tex_coords->resize( 3 * loader.header.numTriangles );
00215   polygons->indexBuffer()->resize( 3 * loader.header.numTriangles );
00216   geometry->setTexCoordArray(0, tex_coords.get());
00217   geometry->drawCalls()->push_back( polygons.get() );
00218 
00219   int vert_idx = 0;
00220   VL_CHECK( (int)loader.md2_triangle.size() == loader.header.numTriangles )
00221   for(int itri=0; itri<loader.header.numTriangles; itri++) 
00222   {
00223     for( int ivert=3; ivert--; ++vert_idx )
00224     {
00225       // add uv
00226       float u = (float)loader.md2_uv[ loader.md2_triangle[itri].uv_idx[ivert] ].u / loader.header.skinWidth;
00227       float v = 1.0f - (float)loader.md2_uv[ loader.md2_triangle[itri].uv_idx[ivert] ].v / loader.header.skinHeight;
00228       tex_coords->at(vert_idx) = fvec2(u, v);
00229 
00230       // add vert
00231       for(int iframe=0; iframe<loader.header.numFrames; iframe++) 
00232       {
00233         fvec3 vec;
00234         vec.x() =      loader.md2_frame[iframe]->vertices[ loader.md2_triangle[itri].vert_idx[ivert] ].vertex[0] * loader.md2_frame[iframe]->scale[0] + loader.md2_frame[iframe]->translate[0];
00235         vec.y() =      loader.md2_frame[iframe]->vertices[ loader.md2_triangle[itri].vert_idx[ivert] ].vertex[2] * loader.md2_frame[iframe]->scale[2] + loader.md2_frame[iframe]->translate[2];
00236         vec.z() = -1 *(loader.md2_frame[iframe]->vertices[ loader.md2_triangle[itri].vert_idx[ivert] ].vertex[1] * loader.md2_frame[iframe]->scale[1] + loader.md2_frame[iframe]->translate[1]);
00237         vertex_frames[iframe]->at( vert_idx ) = vec;
00238       }
00239       
00240       // add index
00241       polygons->indexBuffer()->at( vert_idx ) = vert_idx;
00242     }
00243   }
00244 
00245   for(int iframe=0; iframe<loader.header.numFrames; iframe++) 
00246     free(loader.md2_frame[iframe]);
00247 
00248   // remove double vertices using the first vertex frame
00249   geometry->setVertexArray( vertex_frames[0].get() );
00250   geometry->setNormalArray( NULL ); // don't count the normals
00251   geometry->setTexCoordArray( 0, tex_coords.get() ); // count the texture coords
00252 
00253   // this takes away the 66% of the vertices!
00254   DoubleVertexRemover remover;
00255   remover.removeDoubles( geometry.get() );
00256 
00257   // install the newly created and simplified arrays
00258   vertex_frames[0] = cast<ArrayFloat3>(geometry->vertexArray()); VL_CHECK(vertex_frames[0]);
00259   tex_coords       = cast<ArrayFloat2>(geometry->texCoordArray(0)); VL_CHECK(tex_coords);
00260   polygons         = cast<DrawElementsUInt>(geometry->drawCalls()->at(0)); VL_CHECK(polygons);
00261 
00262   // simplify the remaining frames based on the translation table remover.oldToNewIndexMap()
00263   for(int iframe=1; iframe<loader.header.numFrames; ++iframe)
00264   {
00265     ArrayFloat3* new_vertex_frame = new ArrayFloat3;
00266     new_vertex_frame->resize( vertex_frames[0]->size() );
00267 
00268     for(size_t ivert=0; ivert<vertex_frames[iframe]->size(); ++ivert)
00269     {
00270       VL_CHECK( remover.mapOldToNew()[ivert] < new_vertex_frame->size() )
00271       new_vertex_frame->at( remover.mapOldToNew()[ivert] ) = vertex_frames[iframe]->at(ivert);
00272     }
00273     vertex_frames[iframe] = new_vertex_frame;
00274   }
00275 
00276   // compute normals
00277   normal_frames.resize( loader.header.numFrames );
00278   for(int iframe=0; iframe<loader.header.numFrames; iframe++) 
00279   {
00280     geometry->setVertexArray( vertex_frames[iframe].get() );
00281     geometry->computeNormals();
00282     normal_frames[iframe] = cast<ArrayFloat3>(geometry->normalArray()); VL_CHECK(normal_frames[iframe]);
00283     VL_CHECK( normal_frames[iframe] )
00284   }
00285 
00286   for(unsigned i=0; i<vertex_frames.size(); ++i)
00287   {
00288     vertex_frames[i]->setObjectName("vertex_frame");
00289     res_db->resources().push_back(vertex_frames[i].get());
00290   }
00291 
00292   for(unsigned i=0; i<normal_frames.size(); ++i)
00293   {
00294     normal_frames[i]->setObjectName("normal_frame");
00295     res_db->resources().push_back(normal_frames[i].get());
00296   }
00297 
00298   return res_db;
00299 }
00300 //-----------------------------------------------------------------------------
00301 
00302 /* Quick MD2 Animation Map
00303  * stand 0,39
00304  * run 40,45
00305  * attack 46,53
00306  * wave 112, 122
00307  * die 190 197
00308  */
00309 

Visualization Library 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:39.
Permission is granted to use this page to write and publish articles regarding Visualization Library.