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 #ifndef VLXVisitorExportToVLB_INCLUDE_ONCE 00033 #define VLXVisitorExportToVLB_INCLUDE_ONCE 00034 00035 #include <vlCore/VLXVisitor.hpp> 00036 #include <vlCore/VLXValue.hpp> 00037 #include <vlCore/VLXBinaryDefs.hpp> 00038 #include <vlCore/VirtualFile.hpp> 00039 00040 namespace vl 00041 { 00043 class VLXVisitorExportToVLB: public VLXVisitor 00044 { 00045 VL_INSTRUMENT_CLASS(vl::VLXVisitorExportToVLB, VLXVisitor) 00046 00047 public: 00048 VLXVisitorExportToVLB(VirtualFile* file = NULL) 00049 { 00050 mIDSet = NULL; 00051 setOutputFile(file); 00052 } 00053 00054 bool isUsed(const std::string& uid) 00055 { 00056 if (mIDSet) 00057 { 00058 std::map< std::string, int >::iterator it = mIDSet->find(uid); 00059 if (it != mIDSet->end()) 00060 return it->second > 1; 00061 else 00062 { 00063 // should not happen 00064 VL_TRAP() 00065 return false; 00066 } 00067 } 00068 else 00069 return true; 00070 } 00071 00072 void writeValue(VLXValue& value) 00073 { 00074 switch(value.type()) 00075 { 00076 00077 case VLXValue::Structure: 00078 value.getStructure()->acceptVisitor(this); 00079 break; 00080 00081 case VLXValue::List: 00082 value.getList()->acceptVisitor(this); 00083 break; 00084 00085 /* 00086 case VLXValue::ArrayString: 00087 break; 00088 00089 case VLXValue::ArrayIdentifier: 00090 break; 00091 00092 case VLXValue::ArrayID: 00093 break; 00094 */ 00095 00096 case VLXValue::ArrayInteger: 00097 value.getArrayInteger()->acceptVisitor(this); 00098 break; 00099 00100 case VLXValue::ArrayReal: 00101 value.getArrayReal()->acceptVisitor(this); 00102 break; 00103 00104 case VLXValue::RawtextBlock: 00105 { 00106 VLXRawtextBlock* fblock = value.getRawtextBlock(); 00107 // header 00108 mOutputFile->writeUInt8( VLB_ChunkRawtext ); 00109 // tag 00110 writeString( fblock->tag().c_str() ); 00111 // value 00112 writeString( fblock->value().c_str() ); // no decoding needed 00113 } 00114 break; 00115 00116 case VLXValue::String: 00117 // header 00118 mOutputFile->writeUInt8( VLB_ChunkString ); 00119 // value 00120 writeString( value.getString().c_str() ); 00121 break; 00122 00123 case VLXValue::Identifier: 00124 // header 00125 mOutputFile->writeUInt8( VLB_ChunkIdentifier ); 00126 // value 00127 writeString( value.getIdentifier().c_str() ); 00128 break; 00129 00130 case VLXValue::ID: 00131 // header 00132 mOutputFile->writeUInt8( VLB_ChunkID ); 00133 // value 00134 writeString( value.getID().c_str() ); 00135 break; 00136 00137 case VLXValue::Bool: 00138 // header 00139 mOutputFile->writeUInt8( VLB_ChunkBool ); 00140 // value 00141 mOutputFile->writeUInt8( value.getBool() ); 00142 break; 00143 00144 case VLXValue::Integer: 00145 // header 00146 mOutputFile->writeUInt8( VLB_ChunkInteger); 00147 // value 00148 writeInteger( value.getInteger() ); 00149 break; 00150 00151 case VLXValue::Real: 00152 // header 00153 mOutputFile->writeUInt8( VLB_ChunkRealDouble); 00154 // value 00155 mOutputFile->writeDouble( value.getReal() ); 00156 break; 00157 } 00158 } 00159 00160 virtual void visitStructure(VLXStructure* obj) 00161 { 00162 if (isVisited(obj)) 00163 { 00164 mOutputFile->writeUInt8( VLB_ChunkID ); 00165 writeString( obj->uid().c_str() ); 00166 return; 00167 } 00168 00169 // header 00170 mOutputFile->writeUInt8( VLB_ChunkStructure ); 00171 00172 // tag 00173 writeString( obj->tag().c_str() ); 00174 00175 // ID 00176 writeString( obj->uid().c_str() ); 00177 00178 // key/value count 00179 writeInteger( obj->value().size() ); 00180 00181 // values 00182 for(size_t i=0; i<obj->value().size(); ++i) 00183 { 00184 // key 00185 writeString(obj->value()[i].key().c_str()); 00186 00187 // value 00188 writeValue(obj->value()[i].value()); 00189 } 00190 } 00191 00192 virtual void visitList(VLXList* list) 00193 { 00194 // this should happen only if the user manually creates loops 00195 if (isVisited(list)) 00196 { 00197 Log::warning("VLXVisitorExportToVLT: cycle detected on VLXList.\n"); 00198 return; 00199 } 00200 00201 // header 00202 mOutputFile->writeUInt8( VLB_ChunkList ); 00203 00204 // tag 00205 writeString( list->tag().c_str() ); 00206 00207 // value count 00208 writeInteger( list->value().size() ); 00209 00210 // values 00211 for(size_t i=0; i<list->value().size(); ++i) 00212 writeValue(list->value()[i]); 00213 } 00214 00215 virtual void visitArray(VLXArrayInteger* arr) 00216 { 00217 // header 00218 mOutputFile->writeUInt8( VLB_ChunkArrayInteger ); 00219 00220 // tag 00221 writeString(arr->tag().c_str()); 00222 00223 // value count 00224 writeInteger(arr->value().size()); 00225 00226 // value 00227 if (arr->value().size() > 0) 00228 { 00229 std::vector<unsigned char> encoded; 00230 encodeIntegers(&arr->value()[0], (int)arr->value().size(), encoded); VL_CHECK(encoded.size()) 00231 writeInteger(encoded.size()); 00232 mOutputFile->writeUInt8(&encoded[0], encoded.size()); 00233 } 00234 } 00235 00236 bool needsDoublePrecision(const double* in, size_t count) 00237 { 00238 for(size_t i=0; i<count; ++i) 00239 { 00240 float f = (float)in[i]; 00241 if ((double)f != in[i]) 00242 return true; 00243 } 00244 00245 return false; 00246 } 00247 00248 virtual void visitArray(VLXArrayReal* arr) 00249 { 00250 bool needs_double = arr->value().empty() ? false : needsDoublePrecision(&arr->value()[0], arr->value().size()); 00251 00252 // header 00253 mOutputFile->writeUInt8( (unsigned char)(needs_double ? VLB_ChunkArrayRealDouble : VLB_ChunkArrayRealFloat) ); 00254 // tag 00255 writeString(arr->tag().c_str()); 00256 // count 00257 writeInteger(arr->value().size()); 00258 // value 00259 if (arr->value().size()) 00260 { 00261 #if 1 00262 if (needs_double) 00263 mOutputFile->writeDouble(&arr->value().front(), arr->value().size()); 00264 else 00265 { 00266 std::vector<float> floats; 00267 floats.resize(arr->value().size()); 00268 for(size_t i=0; i<arr->value().size(); ++i) 00269 floats[i] = (float)arr->value()[i]; 00270 mOutputFile->writeFloat(&floats[0], floats.size()); 00271 } 00272 #else 00273 std::vector<unsigned char> zipped; 00274 compress( &arr->value()[0], arr->value().size() * sizeof(arr->value()[0]), zipped, 1 ); 00275 writeInteger( zipped.size() ); 00276 mOutputFile->write(&zipped[0], zipped.size()); 00277 #endif 00278 } 00279 } 00280 00281 /* 00282 virtual void visitArray(VLXArrayString* arr) 00283 { 00284 } 00285 00286 virtual void visitArray(VLXArrayIdentifier* arr) 00287 { 00288 } 00289 00290 virtual void visitArray(VLXArrayID* arr) 00291 { 00292 } 00293 */ 00294 00295 void writeHeader() 00296 { 00297 // see http://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/ for more info on why I choose these characters. 00298 unsigned char vlx_identifier[] = { 0xAB, 'V', 'L', 'X', 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }; 00299 00300 mOutputFile->write(vlx_identifier, sizeof(vlx_identifier)); 00301 mOutputFile->writeUInt16(100); // "version" (16 bits uint) 00302 mOutputFile->write("ascii", 5+1); // "encoding" (zero terminated string) 00303 mOutputFile->writeUInt32(0); // "flags" (reserved for the future) 00304 } 00305 00306 void writeString(const char* str) 00307 { 00308 size_t len = strlen(str); 00309 writeInteger(len); 00310 mOutputFile->write(str, len); 00311 } 00312 00313 void writeInteger(long long n) 00314 { 00315 #if 0 00316 mOutputFile->writeSInt64(n); 00317 #else 00318 const unsigned char nxt_flag = 0x80; 00319 const unsigned char neg_flag = 0x40; 00320 unsigned char bytes[12]; memset(bytes, 0, sizeof(bytes)); // should take maximum 10 bytes 00321 unsigned char* byte = bytes; 00322 if (n < 0) 00323 { 00324 n = -n; 00325 *byte = neg_flag; 00326 } 00327 // lower 6 bits 00328 *byte |= n & 0x3F; n >>= 6; 00329 *byte |= n ? nxt_flag : 0; 00330 ++byte; // --> output 00331 // rest of the bytes 00332 while (n) 00333 { 00334 *byte = n & 0x7F; n >>= 7; 00335 *byte |= n ? nxt_flag : 0; 00336 ++byte; // --> output 00337 } 00338 mOutputFile->write(bytes, byte - bytes); 00339 #endif 00340 } 00341 00342 void encodeIntegers(long long* val, int count, std::vector<unsigned char>& out) 00343 { 00344 const unsigned char nxt_flag = 0x80; 00345 const unsigned char neg_flag = 0x40; 00346 out.reserve(count); 00347 for( int i=0; i<count; ++i) 00348 { 00349 unsigned char byte = 0; 00350 long long n = val[i]; 00351 if (n < 0) 00352 { 00353 n = -n; 00354 byte = neg_flag; 00355 } 00356 // lower 6 bits 00357 byte |= n & 0x3F; n >>= 6; 00358 byte |= n ? nxt_flag : 0; 00359 out.push_back(byte); 00360 // rest of the bytes 00361 while (n) 00362 { 00363 byte = n & 0x7F; n >>= 7; 00364 byte |= n ? nxt_flag : 0; 00365 out.push_back(byte); 00366 } 00367 } 00368 } 00369 00370 void setIDSet(std::map< std::string, int >* uids) { mIDSet = uids; } 00371 00372 std::map< std::string, int >* uidSet() { return mIDSet; } 00373 00374 const std::map< std::string, int >* uidSet() const { return mIDSet; } 00375 00376 void setOutputFile(VirtualFile* file) 00377 { 00378 mOutputFile = file; 00379 if (file) 00380 { 00381 file->close(); 00382 file->open(OM_WriteOnly); 00383 } 00384 } 00385 00386 VirtualFile* outputFile() { return mOutputFile.get(); } 00387 00388 const VirtualFile* outputFile() const { return mOutputFile.get(); } 00389 00390 private: 00391 std::map< std::string, int >* mIDSet; 00392 ref<VirtualFile> mOutputFile; 00393 }; 00394 } 00395 00396 #endif