Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://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 "ioAC3D.hpp" 00033 #include <vlCore/checks.hpp> 00034 #include <vlGraphics/Effect.hpp> 00035 #include <vlGraphics/Geometry.hpp> 00036 #include <vlCore/Image.hpp> 00037 #include <vlGraphics/Texture.hpp> 00038 #include <vlCore/Log.hpp> 00039 #include <vlCore/Say.hpp> 00040 #include <vlCore/VisualizationLibrary.hpp> 00041 #include <vlCore/FileSystem.hpp> 00042 #include <vlCore/TextStream.hpp> 00043 #include <vlCore/VirtualFile.hpp> 00044 #include <vlGraphics/DoubleVertexRemover.hpp> 00045 #include <map> 00046 #include <vlCore/LoadWriterManager.hpp> 00047 00048 using namespace vl; 00049 00050 namespace 00051 { 00052 class LoaderAC3D 00053 { 00054 public: 00055 00056 class vert_info 00057 { 00058 public: 00059 int Vert; 00060 float U; 00061 float V; 00062 }; 00063 00064 class material_info 00065 { 00066 public: 00067 String Name; 00068 fvec3 Diffuse; 00069 fvec3 Ambient; 00070 fvec3 Emission; 00071 fvec3 Specular; 00072 float Shininess; 00073 float Trans; 00074 }; 00075 00076 class surface_info 00077 { 00078 public: 00079 int Flags; 00080 int materials; 00081 int VertCount; 00082 std::vector<vert_info> Vertex; 00083 }; 00084 00085 class mesh_info 00086 { 00087 public: 00088 mesh_info(); 00089 00090 String Name; 00091 String Data; 00092 String Texture; 00093 float TexRep[2]; 00094 dmat4 Matrix; 00095 String Url; 00096 int NumVert; 00097 std::vector<fvec3> Vert; 00098 int NumSurf; 00099 std::vector<surface_info> Surface; 00100 int NumKids; 00101 }; 00102 00103 LoaderAC3D(); 00104 bool parseAC3D(VirtualFile* file); 00105 00106 fvec3 readColor(); 00107 fvec3 readVector(); 00108 float readFloat(); 00109 int readInt(); 00110 int readHex(); 00111 String readLine(); 00112 String readWord(); 00113 String readName(); 00114 void readMaterial(); 00115 void readObject(); 00116 00117 std::vector<material_info> materials; 00118 std::vector<mesh_info> meshes; 00119 bool verbose; 00120 00121 protected: 00122 ref<TextStream> mTokenizer; 00123 String mTmpStr; 00124 bool mEOF; 00125 }; 00126 } 00127 //----------------------------------------------------------------------------- 00128 // mesh_info 00129 //----------------------------------------------------------------------------- 00130 LoaderAC3D::mesh_info::mesh_info() 00131 { 00132 TexRep[0] = 1; 00133 TexRep[1] = 1; 00134 NumVert = 0; 00135 NumSurf = 0; 00136 NumKids = 0; 00137 } 00138 //----------------------------------------------------------------------------- 00139 // LoaderAC3D 00140 //----------------------------------------------------------------------------- 00141 LoaderAC3D::LoaderAC3D() 00142 { 00143 verbose = true; 00144 } 00145 //----------------------------------------------------------------------------- 00146 bool LoaderAC3D::parseAC3D(VirtualFile* file) 00147 { 00148 mEOF = false; 00149 00150 mTokenizer = new TextStream; 00151 mTokenizer->setInputFile( file ); 00152 String token; 00153 00154 mTokenizer->readString(token); 00155 00156 if (token != "AC3Db") 00157 { 00158 Log::error("Not an AC3Db file!\n"); 00159 file->close(); 00160 return false; 00161 } 00162 00163 while( mTokenizer->readString(token) ) 00164 { 00165 if (token == "MATERIAL") 00166 readMaterial(); 00167 else 00168 if (token == "OBJECT") 00169 readObject(); 00170 else 00171 { 00172 Log::error("AC3D parse error.\n"); 00173 file->close(); 00174 return false; 00175 } 00176 } 00177 00178 file->close(); 00179 return true; 00180 } 00181 //----------------------------------------------------------------------------- 00182 fvec3 LoaderAC3D::readColor() 00183 { 00184 bool ok = true; 00185 ok &= mTokenizer->readString(mTmpStr); float r = mTmpStr.toFloat(); 00186 ok &= mTokenizer->readString(mTmpStr); float g = mTmpStr.toFloat(); 00187 ok &= mTokenizer->readString(mTmpStr); float b = mTmpStr.toFloat(); 00188 mEOF = !ok; 00189 if ( !ok ) 00190 Log::error("LoaderAC3D::readColor() IO error.\n"); 00191 return fvec3(r,g,b); 00192 } 00193 //----------------------------------------------------------------------------- 00194 fvec3 LoaderAC3D::readVector() 00195 { 00196 bool ok = true; 00197 ok &= mTokenizer->readString(mTmpStr); float x = mTmpStr.toFloat(); 00198 ok &= mTokenizer->readString(mTmpStr); float y = mTmpStr.toFloat(); 00199 ok &= mTokenizer->readString(mTmpStr); float z = mTmpStr.toFloat(); 00200 mEOF = !ok; 00201 if ( !ok ) 00202 Log::error("LoaderAC3D::readVector() IO error.\n"); 00203 return fvec3(x,y,z); 00204 } 00205 //----------------------------------------------------------------------------- 00206 float LoaderAC3D::readFloat() 00207 { 00208 bool ok = true; 00209 ok &= mTokenizer->readString(mTmpStr); float f = mTmpStr.toFloat(); 00210 mEOF = !ok; 00211 if ( !ok ) 00212 Log::error("LoaderAC3D::readFloat() IO error.\n"); 00213 return f; 00214 } 00215 //----------------------------------------------------------------------------- 00216 int LoaderAC3D::readInt() 00217 { 00218 bool ok = true; 00219 ok &= mTokenizer->readString(mTmpStr); int i = mTmpStr.toInt(); 00220 mEOF = !ok; 00221 if ( !ok ) 00222 Log::error("LoaderAC3D::readInt() IO error.\n"); 00223 return i; 00224 } 00225 //----------------------------------------------------------------------------- 00226 int LoaderAC3D::readHex() 00227 { 00228 bool ok = true; 00229 ok &= mTokenizer->readString(mTmpStr); 00230 mEOF = !ok; 00231 if ( !ok ) 00232 { 00233 Log::error("I/O error reading hex.\n"); 00234 return 0; 00235 } 00236 else 00237 { 00238 mTmpStr[0] = ' '; 00239 mTmpStr[1] = ' '; 00240 return mTmpStr.toInt(true); 00241 } 00242 } 00243 //----------------------------------------------------------------------------- 00244 String LoaderAC3D::readWord() 00245 { 00246 bool ok = true; 00247 ok &= mTokenizer->readString( mTmpStr ); 00248 mEOF = !ok; 00249 if ( !ok ) 00250 { 00251 Log::error("I/O error reading word.\n"); 00252 return ""; 00253 } 00254 else 00255 { 00256 if ( mTmpStr.count('"') == 1 ) 00257 { 00258 Log::error( Say("The string '%s' contains a single '\"'.\n") << mTmpStr ); 00259 } 00260 00261 mTmpStr.remove('"'); 00262 return mTmpStr; 00263 } 00264 } 00265 //----------------------------------------------------------------------------- 00266 String LoaderAC3D::readName() 00267 { 00268 bool ok = true; 00269 ok &= mTokenizer->readQuotedString( mTmpStr ); 00270 mEOF = !ok; 00271 if ( !ok ) 00272 { 00273 Log::error("I/O error reading word.\n"); 00274 return ""; 00275 } 00276 else 00277 { 00278 if ( mTmpStr.count('"') == 1 ) 00279 { 00280 Log::error( Say("The string '%s' contains a single '\"'.\n") << mTmpStr ); 00281 } 00282 00283 mTmpStr.remove('"'); 00284 return mTmpStr; 00285 } 00286 } 00287 //----------------------------------------------------------------------------- 00288 String LoaderAC3D::readLine() 00289 { 00290 bool ok = true; 00291 ok &= mTokenizer->readLine( mTmpStr ); 00292 if ( !ok ) 00293 { 00294 Log::error("I/O error reading line.\n"); 00295 return ""; 00296 } 00297 else 00298 { 00299 return mTmpStr; 00300 } 00301 } 00302 //----------------------------------------------------------------------------- 00303 void LoaderAC3D::readMaterial() 00304 { 00305 // MATERIAL %s rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f 00306 material_info material; 00307 00308 material.Name = readName(); 00309 readWord(); // rgb 00310 material.Diffuse = readColor(); 00311 readWord(); // amb 00312 material.Ambient = readColor(); 00313 readWord(); // emis 00314 material.Emission = readColor(); 00315 readWord(); // spec 00316 material.Specular = readColor(); 00317 readWord(); // shi 00318 material.Shininess = readFloat(); 00319 readWord(); // trans 00320 material.Trans = 1 - readFloat(); 00321 00322 materials.push_back(material); 00323 } 00324 //----------------------------------------------------------------------------- 00325 void LoaderAC3D::readObject() 00326 { 00327 mesh_info mesh; 00328 String block; 00329 00330 block = readWord(); 00331 00332 do 00333 { 00334 block = readWord(); 00335 00336 if (mEOF) 00337 break; 00338 00339 if (block == "name") 00340 { 00341 mesh.Name = readName(); 00342 } else 00343 if (block == "data") 00344 { 00345 // needed to safely skip to the next line 00346 int data_size=0; 00347 mTokenizer->readLine(mTmpStr); 00348 data_size = mTmpStr.toInt(); 00349 00350 // skip data_size bytes 00351 unsigned char ch = 0; 00352 for (int i=0; i<data_size; i++ ) 00353 mTokenizer->readToken(&ch); 00354 } 00355 else 00356 if (block == "texture") 00357 { 00358 mesh.Texture = readName(); 00359 } else 00360 if (block == "texrep") 00361 { 00362 mesh.TexRep[0] = readFloat(); 00363 mesh.TexRep[1] = readFloat(); 00364 } else 00365 if (block == "rot") 00366 { 00367 mesh.Matrix.setX( (dvec3)readVector() ); 00368 mesh.Matrix.setY( (dvec3)readVector() ); 00369 mesh.Matrix.setZ( (dvec3)readVector() ); 00370 } else 00371 if (block == "loc") 00372 { 00373 mesh.Matrix.setT( (dvec3)readVector() ); 00374 } else 00375 if (block == "url") 00376 { 00377 mesh.Url = readName(); 00378 } else 00379 if (block == "numvert") 00380 { 00381 mesh.NumVert = readInt(); 00382 for(int i=0; i<mesh.NumVert; ++i) 00383 { 00384 mesh.Vert.push_back( readVector() ); 00385 } 00386 } else 00387 if (block == "numsurf") 00388 { 00389 mesh.NumSurf = readInt(); 00390 for(int i=0; i<mesh.NumSurf; ++i) 00391 { 00392 surface_info surf; 00393 String tmp; 00394 do 00395 { 00396 tmp = readWord(); 00397 00398 if (tmp == "SURF") 00399 { 00400 surf.Flags = readHex(); 00401 } 00402 if (tmp == "mat") 00403 { 00404 surf.materials = readInt(); 00405 } 00406 if (tmp == "refs") 00407 { 00408 surf.VertCount = readInt(); 00409 for(int j=0; j<surf.VertCount; ++j) 00410 { 00411 vert_info vert; 00412 vert.Vert = readInt(); 00413 vert.U = readFloat(); 00414 vert.V = readFloat(); 00415 surf.Vertex.push_back( vert ); 00416 } 00417 } 00418 } 00419 while (tmp != "refs"); 00420 mesh.Surface.push_back(surf); 00421 } 00422 } 00423 else 00424 if (block == "kids") 00425 { 00426 mesh.NumKids = readInt(); 00427 meshes.push_back(mesh); 00428 } 00429 else 00430 { 00431 if (verbose) 00432 Log::warning( Say("unknown block '%s'\n") << block ); 00433 // skip line 00434 mTokenizer->readLine(mTmpStr); 00435 } 00436 } 00437 while(block != "kids"); 00438 } 00439 //----------------------------------------------------------------------------- 00440 ref<ResourceDatabase> vl::loadAC3D(const String& path) 00441 { 00442 ref<VirtualFile> file = defFileSystem()->locateFile(path); 00443 if ( !file ) 00444 { 00445 Log::error( Say("Could not locate '%s'.\n") << path ); 00446 return NULL; 00447 } 00448 else 00449 { 00450 return loadAC3D(file.get() ); 00451 } 00452 } 00453 //----------------------------------------------------------------------------- 00454 ref<ResourceDatabase> vl::loadAC3D( VirtualFile* file) 00455 { 00456 ref<ResourceDatabase> res_db = new ResourceDatabase; 00457 00458 LoaderAC3D loader; 00459 if ( !loader.parseAC3D(file) ) 00460 return NULL; 00461 00462 // compile the material map 00463 std::vector< ref<Effect> > mat_map; 00464 for(unsigned imat=0; imat<loader.materials.size(); imat++) 00465 { 00466 ref<Effect> effect = new Effect; 00467 mat_map.push_back(effect.get()); 00468 00469 // apply material 00470 effect->shader()->enable(EN_DEPTH_TEST); 00471 00472 effect->shader()->gocMaterial()->setAmbient( fvec4(loader.materials[ imat ].Ambient, 1.0f) ); 00473 effect->shader()->gocMaterial()->setDiffuse( fvec4(loader.materials[ imat ].Diffuse, 1.0f) ); 00474 effect->shader()->gocMaterial()->setEmission( fvec4(loader.materials[ imat ].Emission, 1.0f) ); 00475 effect->shader()->gocMaterial()->setSpecular( fvec4(loader.materials[ imat ].Specular, 1.0f) ); 00476 effect->shader()->gocMaterial()->setShininess( loader.materials[ imat ].Shininess ); 00477 effect->shader()->gocMaterial()->setTransparency( loader.materials[ imat ].Trans ); 00478 00479 if ( loader.materials[ imat ].Trans < 1.0f ) 00480 { 00481 effect->shader()->enable(EN_CULL_FACE); 00482 effect->shader()->enable(EN_BLEND); 00483 effect->shader()->gocBlendFunc()->set(BF_SRC_ALPHA, BF_ONE_MINUS_SRC_ALPHA); 00484 } 00485 } 00486 00487 // dumps the objects 00488 for(unsigned imesh=0; imesh<loader.meshes.size(); imesh++) 00489 { 00490 if ( loader.meshes[imesh].Surface.empty() ) 00491 continue; 00492 00493 ref<Actor> act = new Actor; 00494 act->setObjectName( loader.meshes[imesh].Name.toStdString().c_str() ); 00495 00496 ref<Geometry> geom = new Geometry; 00497 geom->setObjectName( loader.meshes[imesh].Name.toStdString().c_str() ); 00498 00499 ref<ArrayFloat3> verts = new ArrayFloat3; 00500 ref<ArrayFloat2> uv = new ArrayFloat2; 00501 ref<DrawElementsUInt> polys = new DrawElementsUInt; 00502 geom->drawCalls()->push_back( polys.get() ); 00503 geom->setVertexArray( verts.get() ); 00504 geom->setTexCoordArray(0, uv.get()); 00505 act->setLod(0, geom.get()); 00506 00507 // we handle only one material per surface 00508 int mat_index = loader.meshes[imesh].Surface[0].materials; 00509 00510 act->setEffect( mat_map[ mat_index ].get() ); 00511 00512 // polygons + vertices 00513 int vert_count = 0; 00514 for(unsigned isurf=0; isurf<loader.meshes[imesh].Surface.size(); isurf++) 00515 { 00516 if ( (loader.meshes[imesh].Surface[isurf].Flags & 0xF) != 0 ) 00517 continue; 00518 for( int ivert=1; ivert<loader.meshes[imesh].Surface[isurf].VertCount-1; ivert++) 00519 for(int i=0; i<3; ++i) 00520 ++vert_count; 00521 } 00522 00523 verts->resize( vert_count ); 00524 uv->resize( vert_count ); 00525 00526 if (!vert_count) 00527 continue; 00528 00529 // add when we are sure we have some content 00530 00531 res_db->resources().push_back( act.get() ); 00532 res_db->resources().push_back( geom.get() ); 00533 00534 // warning: this is a quite experimental importer. 00535 00536 // !!! FIX !!! i vertici dovrebbero essere < degli indici in generale, vedi sotto 00537 polys->indexBuffer()->resize( vert_count ); 00538 00539 int idx = 0; 00540 for(unsigned isurf=0; isurf<loader.meshes[imesh].Surface.size(); isurf++) 00541 { 00542 if ( (loader.meshes[imesh].Surface[isurf].Flags & 0xF) != 0 ) // not a poly 00543 continue; 00544 VL_CHECK( loader.meshes[imesh].Surface[isurf].VertCount >= 3 ) 00545 for( int ivert=1; ivert<loader.meshes[imesh].Surface[isurf].VertCount-1; ivert++) 00546 { 00547 int vert_idx[] = { 0, ivert, ivert+1 }; 00548 for(int i=0; i<3; ++i, idx++) 00549 { 00550 // FIXME: a quanto pare i vertici non sono condivisi, ma lo dovrebbero essere 00551 polys->indexBuffer()->at( idx ) = idx; 00552 int iv = loader.meshes[imesh].Surface[isurf].Vertex[ vert_idx[i] ].Vert; 00553 verts->at( idx ) = loader.meshes[imesh].Vert[ iv ]; 00554 uv->at( idx ) = fvec2(loader.meshes[imesh].Surface[isurf].Vertex[ vert_idx[i] ].U, loader.meshes[imesh].Surface[isurf].Vertex[ vert_idx[i] ].V); 00555 } 00556 } 00557 } 00558 00559 // FIXME 00560 /*DoubleVertexRemover dvr; 00561 dvr.removeDoubles(geom.get());*/ 00562 geom->transform( (mat4)loader.meshes[imesh].Matrix ); 00563 // geom->computeNormals(); 00564 00565 // !!! FIX !!! texture e double-side sono specificati per mesh e non per materiale, VL dovrebbe creare 00566 // combinazioni uniche di materiali/texture/double-side 00567 00568 // !!! FIX !!! texture - ci dovrebbe essere un unico materiale per ogni combinazione di double-side/texture 00569 if ( loader.meshes[imesh].Texture.length() ) 00570 { 00571 ref<Texture> texture = new Texture; 00572 // locate texture 00573 String tex_path = loader.meshes[imesh].Texture; 00574 ref<VirtualFile> tex_file = defFileSystem()->locateFile(tex_path,file->path().extractPath()); 00575 if (tex_file) 00576 tex_path = tex_file->path(); 00577 texture->prepareTexture2D(tex_path, TF_RGBA); 00578 act->effect()->shader()->gocTextureSampler(0)->setTexture( texture.get() ); 00579 } 00580 00581 // !!! FIX !!! double-side - ci dovrebbe essere un unico materiale per ogni combinazione di double-side/texture 00582 if ( (loader.meshes[imesh].Surface[0].Flags & 0x20) ) 00583 { 00584 act->effect()->shader()->gocLightModel()->setTwoSide(true); 00585 /* effect->shader()->disable(EN_CULL_FACE); */ 00586 } 00587 00588 } 00589 00590 return res_db; 00591 } 00592 //-----------------------------------------------------------------------------