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 "ioPLY.hpp" 00033 #include <vlCore/Log.hpp> 00034 #include <vlCore/Say.hpp> 00035 #include <vlCore/VisualizationLibrary.hpp> 00036 #include <vlCore/FileSystem.hpp> 00037 #include <vlCore/TextStream.hpp> 00038 #include <vlCore/VirtualFile.hpp> 00039 #include <vlGraphics/Effect.hpp> 00040 #include <vlGraphics/Actor.hpp> 00041 #include <vlCore/LoadWriterManager.hpp> 00042 00043 using namespace vl; 00044 //----------------------------------------------------------------------------- 00045 ref<ResourceDatabase> vl::loadPLY(const String& path) 00046 { 00047 ref<VirtualFile> file = defFileSystem()->locateFile(path); 00048 00049 if (file) 00050 return loadPLY( file.get() ); 00051 else 00052 { 00053 Log::error( Say("Could not locate '%s'.\n") << path ); 00054 return NULL; 00055 } 00056 } 00057 //----------------------------------------------------------------------------- 00058 ref<ResourceDatabase> vl::loadPLY(VirtualFile* file) 00059 { 00060 PlyLoader ply; 00061 ref<ResourceDatabase> res_db = ply.loadPly(file); 00062 return res_db; 00063 } 00064 //----------------------------------------------------------------------------- 00065 void PlyLoader::PlyScalar::read(VirtualFile* file, bool le) 00066 { 00067 switch(scalarType()) 00068 { 00069 case PlyChar: mData.mChar = file->readSInt8(); break; 00070 case PlyUChar: mData.mUChar = file->readUInt8(); break; 00071 case PlyShort: mData.mShort = file->readSInt16(le); break; 00072 case PlyUShort: mData.mUShort = file->readUInt16(le); break; 00073 case PlyInt: mData.mInt = file->readSInt32(le); break; 00074 case PlyUInt: mData.mUInt = file->readUInt32(le); break; 00075 case PlyFloat: mData.mFloat = file->readFloat(le); break; 00076 case PlyDouble: mData.mDouble = file->readDouble(le); break; 00077 default: 00078 Log::error("PlyLoader: scalar read error.\n"); 00079 } 00080 } 00081 void PlyLoader::PlyScalar::read(TextStream* text) 00082 { 00083 int idata; 00084 double ddata; 00085 switch(scalarType()) 00086 { 00087 case PlyChar: text->readInt(idata); mData.mChar = (char)idata; break; 00088 case PlyUChar: text->readInt(idata); mData.mUChar = (unsigned char)idata; break; 00089 case PlyShort: text->readInt(idata); mData.mShort = (short)idata; break; 00090 case PlyUShort: text->readInt(idata); mData.mUShort = (unsigned short)idata; break; 00091 case PlyInt: text->readInt(idata); mData.mInt = (int)idata; break; 00092 case PlyUInt: text->readInt(idata); mData.mUInt = (unsigned int)idata; break; 00093 case PlyFloat: text->readDouble(ddata); mData.mFloat = (float)ddata; break; 00094 case PlyDouble: text->readDouble(ddata); mData.mDouble = (double)ddata; break; 00095 default: 00096 Log::error("PlyLoader: scalar read error.\n"); 00097 } 00098 } 00099 float PlyLoader::PlyScalar::getAsFloat() const 00100 { 00101 switch(scalarType()) 00102 { 00103 case PlyChar: return (float)mData.mChar; 00104 case PlyUChar: return (float)mData.mUChar; 00105 case PlyShort: return (float)mData.mShort; 00106 case PlyUShort: return (float)mData.mUShort; 00107 case PlyInt: return (float)mData.mInt; 00108 case PlyUInt: return (float)mData.mUInt; 00109 case PlyFloat: return mData.mFloat; 00110 case PlyDouble: return (float)mData.mDouble; 00111 default: 00112 Log::error("PlyLoader: getAsFloat() error.\n"); 00113 return 0.0f; 00114 } 00115 } 00116 int PlyLoader::PlyScalar::getAsInt() const 00117 { 00118 switch(scalarType()) 00119 { 00120 case PlyChar: return (int)mData.mChar; 00121 case PlyUChar: return (int)mData.mUChar; 00122 case PlyShort: return (int)mData.mShort; 00123 case PlyUShort: return (int)mData.mUShort; 00124 case PlyInt: return (int)mData.mInt; 00125 case PlyUInt: return (int)mData.mUInt; 00126 case PlyFloat: return (int)mData.mFloat; 00127 case PlyDouble: return (int)mData.mDouble; 00128 default: 00129 Log::error("PlyLoader: getAsFloat() error.\n"); 00130 return 0; 00131 } 00132 } 00133 void PlyLoader::PlyElement::analyze() 00134 { 00135 mVertex.resize(3); 00136 mNormal.resize(3); 00137 mColor.resize(4); 00138 if (name() == "vertex") 00139 { 00140 for(unsigned int j=0; j<properties().size(); ++j) 00141 { 00142 PlyScalar* scalar = cast<PlyScalar>(properties()[j].get()); VL_CHECK(scalar) 00143 if (scalar) 00144 { 00145 if (scalar->name() == "x") 00146 mVertex[0] = scalar; 00147 else 00148 if (scalar->name() == "y") 00149 mVertex[1] = scalar; 00150 else 00151 if (scalar->name() == "z") 00152 mVertex[2] = scalar; 00153 else 00154 if (scalar->name() == "nx") 00155 mNormal[0] = scalar; 00156 else 00157 if (scalar->name() == "ny") 00158 mNormal[1] = scalar; 00159 else 00160 if (scalar->name() == "nz") 00161 mNormal[2] = scalar; 00162 else 00163 if (scalar->name() == "red") 00164 mColor[0] = scalar; 00165 else 00166 if (scalar->name() == "green") 00167 mColor[1] = scalar; 00168 else 00169 if (scalar->name() == "blue") 00170 mColor[2] = scalar; 00171 else 00172 if (scalar->name() == "alpha") 00173 mColor[3] = scalar; 00174 } 00175 } 00176 } 00177 } 00178 void PlyLoader::readElements(VirtualFile* file) 00179 { 00180 // reposition to the correct location 00181 file->seekSet(0); 00182 std::string str; 00183 do 00184 { 00185 unsigned char ch = file->readUInt8(); 00186 if (ch == '\n' && str == "end_header") 00187 break; 00188 if (ch == '\n') 00189 { 00190 str.clear(); 00191 continue; 00192 } 00193 str.push_back( ch ); 00194 } while(true); 00195 00196 for(unsigned i=0; i<mElements.size(); ++i) 00197 for(int j=0; j<mElements[i]->elemCount(); ++j) 00198 { 00199 mElements[i]->read(file, littleEndian()); 00200 newElement(mElements[i].get()); 00201 } 00202 } 00203 void PlyLoader::readElements(TextStream* text) 00204 { 00205 for(unsigned i=0; i<mElements.size(); ++i) 00206 for(int j=0; j<mElements[i]->elemCount(); ++j) 00207 { 00208 mElements[i]->read(text); 00209 newElement(mElements[i].get()); 00210 } 00211 } 00212 void PlyLoader::newElement(PlyElement*el) 00213 { 00214 if (el->name() == "vertex") 00215 { 00216 for(unsigned int j=0; j<el->properties().size(); ++j) 00217 { 00218 if (mVerts) 00219 mVerts->at(mVertexIndex) = el->getVertex(); 00220 if (mNormals) 00221 mNormals->at(mVertexIndex) = el->getNormal(); 00222 if (mColors) 00223 mColors->at(mVertexIndex) = el->getColor(); 00224 } 00225 00226 ++mVertexIndex; 00227 } 00228 else 00229 if (el->name() == "face") 00230 { 00231 for(unsigned int j=0; j<el->properties().size(); ++j) 00232 { 00233 PlyScalarList* list = cast<PlyScalarList>(el->properties()[j].get()); VL_CHECK(list) 00234 if (list && list->name() == "vertex_indices") 00235 { 00236 for(int i=1; i<(int)list->scalars().size()-1; ++i) 00237 { 00238 if (mIndices.capacity() - mIndices.size() == 0) 00239 mIndices.reserve( mIndices.capacity() * 2 ); 00240 mIndices.push_back( list->scalars()[0].getAsInt()); 00241 mIndices.push_back( list->scalars()[i].getAsInt()); 00242 mIndices.push_back( list->scalars()[i+1].getAsInt()); 00243 } 00244 } 00245 } 00246 } 00247 } 00248 PlyLoader::EType PlyLoader::translateType(const String& type) 00249 { 00250 if (type == "int8") return PlyChar; else 00251 if (type == "char") return PlyChar; else 00252 if (type == "uint8") return PlyChar; else 00253 if (type == "uchar") return PlyUChar; else 00254 if (type == "ushort") return PlyUShort; else 00255 if (type == "uint16") return PlyUShort; else 00256 if (type == "short") return PlyShort; else 00257 if (type == "int16") return PlyShort; else 00258 if (type == "int") return PlyInt; else 00259 if (type == "int32") return PlyInt; else 00260 if (type == "uint") return PlyUInt; else 00261 if (type == "uint32") return PlyUInt; else 00262 if (type == "float") return PlyFloat; else 00263 if (type == "float32") return PlyFloat; else 00264 if (type == "float64") return PlyDouble; else 00265 if (type == "double") return PlyDouble; 00266 else 00267 { 00268 Log::error("PlyLoader: type parse error.\n"); 00269 return PlyError; 00270 } 00271 } 00272 void PlyLoader::analyzeHeader() 00273 { 00274 // allocate space for vertices, normals and colors. 00275 for(unsigned int i=0; i<elements().size(); ++i) 00276 { 00277 if (elements()[i]->name() == "vertex") 00278 { 00279 for(unsigned int j=0; j<elements()[i]->properties().size(); ++j) 00280 { 00281 if (elements()[i]->properties()[j]->name() == "x") 00282 { 00283 mVerts = new ArrayFloat3; 00284 mVerts->resize( elements()[i]->elemCount() ); 00285 } 00286 if (elements()[i]->properties()[j]->name() == "nx") 00287 { 00288 mNormals = new ArrayFloat3; 00289 mNormals->resize( elements()[i]->elemCount() ); 00290 } 00291 if (elements()[i]->properties()[j]->name() == "red") 00292 { 00293 mColors = new ArrayUByte4; 00294 mColors->resize( elements()[i]->elemCount() ); 00295 memset(mColors->ptr(), 0xFF, sizeof(mColors->at(0))*mColors->size()); 00296 } 00297 } 00298 elements()[i]->analyze(); 00299 } 00300 } 00301 if (mVerts->size() == 0) 00302 { 00303 Log::error("PlyLoader: no vertices found.\n"); 00304 } 00305 } 00306 bool PlyLoader::readHeader(TextStream* line_reader) 00307 { 00308 mVerts = NULL; 00309 mNormals = NULL; 00310 mColors = NULL; 00311 mIndices.reserve(100); 00312 bool ok = true; 00313 elements().clear(); 00314 String str; 00315 // ply loader 00316 line_reader->readLineLF(str); 00317 if (str.trim() != "ply") 00318 return false; 00319 // format 00320 line_reader->readLineLF(str); 00321 if (str.trim() == "format ascii 1.0") 00322 { 00323 mBinary = false; 00324 } 00325 else 00326 if (str.trim() == "format binary_little_endian 1.0") 00327 { 00328 mBinary = true; 00329 mLittleEndian = true; 00330 } 00331 else 00332 if (str.trim() == "format binary_big_endian 1.0") 00333 { 00334 mBinary = true; 00335 mLittleEndian = false; 00336 } 00337 else 00338 return false; 00339 // read elements 00340 while ( (line_reader->readLineLF(str)) && str.trim() != "end_header") 00341 { 00342 if (str.startsWith("comment")) 00343 continue; 00344 else 00345 if (str.startsWith("element")) 00346 { 00347 elements().push_back(new PlyElement); 00348 elements().back()->setName( str.field(' ',1) ); 00349 elements().back()->setElemCount( str.field(' ',2).toInt() ); 00350 } 00351 else 00352 if (str.startsWith("property")) 00353 { 00354 String prop_type = str.field(' ',1); 00355 ref<PlyScalar> prop; 00356 ref<PlyScalarList> scalar_list; 00357 if (prop_type == "list") 00358 { 00359 String num_type = str.field(' ',2); 00360 String idx_type = str.field(' ',3); 00361 String name = str.field(' ',4); 00362 if (name.empty()) 00363 { 00364 Log::error("PLY parse error #5.\n"); 00365 return false; 00366 } 00367 00368 scalar_list = new PlyScalarList; 00369 elements().back()->properties().push_back(scalar_list); 00370 00371 scalar_list->setCountType(translateType(num_type)); 00372 scalar_list->setScalarType(translateType(idx_type)); 00373 scalar_list->setName(name); 00374 } 00375 else 00376 { 00377 prop = new PlyScalar; 00378 elements().back()->properties().push_back(prop); 00379 prop->setName( str.field(' ',2) ); 00380 prop->setScalarType(translateType(prop_type)); 00381 } 00382 } 00383 else 00384 { 00385 Log::error("PLY parse error #2.\n"); 00386 return false; 00387 } 00388 } 00389 analyzeHeader(); 00390 mVertexIndex = 0; 00391 return ok; 00392 } 00393 ref<ResourceDatabase> PlyLoader::loadPly(VirtualFile* file) 00394 { 00395 ref<TextStream> line_reader = new TextStream; 00396 00397 line_reader->setInputFile(file); 00398 00399 readHeader(line_reader.get()); 00400 00401 if (binary()) 00402 readElements(file); 00403 else 00404 readElements(line_reader.get()); 00405 file->close(); 00406 00407 if (mIndices.empty() || !mVerts) 00408 return NULL; 00409 00410 ref<Geometry> geom = new Geometry; 00411 geom->setVertexArray(mVerts.get()); 00412 geom->setNormalArray(mNormals.get()); 00413 geom->setColorArray(mColors.get()); 00414 ref<DrawElementsUInt> de = new DrawElementsUInt(PT_TRIANGLES); 00415 geom->drawCalls()->push_back(de.get()); 00416 de->indexBuffer()->resize(mIndices.size()); 00417 memcpy(de->indexBuffer()->ptr(), &mIndices[0], sizeof(unsigned int)*mIndices.size()); 00418 00419 // Effect 00420 ref<Effect> effect = new Effect; 00421 00422 // Detph test 00423 effect->shader()->enable(EN_DEPTH_TEST); 00424 00425 // Lighting 00426 if( mNormals ) 00427 effect->shader()->enable(EN_LIGHTING); 00428 00429 // note: we don't insert any light 00430 if (mColors) 00431 effect->shader()->gocMaterial()->setColorMaterialEnabled(true); 00432 00433 ref<ResourceDatabase> res_db = new ResourceDatabase; 00434 res_db->resources().push_back( new Actor(geom.get(), effect.get(), NULL ) ); 00435 return res_db; 00436 } 00437 //-----------------------------------------------------------------------------