|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372 |
- /*
- Open Asset Import Library (assimp)
- ----------------------------------------------------------------------
-
- Copyright (c) 2006-2012, assimp team
- All rights reserved.
-
- Redistribution and use of this software in source and binary forms,
- with or without modification, are permitted provided that the
- following conditions are met:
-
- * Redistributions of source code must retain the above
- copyright notice, this list of conditions and the
- following disclaimer.
-
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the
- following disclaimer in the documentation and/or other
- materials provided with the distribution.
-
- * Neither the name of the assimp team, nor the names of its
- contributors may be used to endorse or promote products
- derived from this software without specific prior
- written permission of the assimp team.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
- ----------------------------------------------------------------------
- */
-
- /** @file BlenderDNA.cpp
- * @brief Implementation of the Blender `DNA`, that is its own
- * serialized set of data structures.
- */
- #include "AssimpPCH.h"
-
- #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER
- #include "BlenderDNA.h"
- #include "StreamReader.h"
- #include "fast_atof.h"
-
- using namespace Assimp;
- using namespace Assimp::Blender;
- using namespace Assimp::Formatter;
-
- #define for_each BOOST_FOREACH
- bool match4(StreamReaderAny& stream, const char* string) {
- char tmp[] = {
- (stream).GetI1(),
- (stream).GetI1(),
- (stream).GetI1(),
- (stream).GetI1()
- };
- return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]);
- }
-
- struct Type {
- size_t size;
- std::string name;
- };
-
- // ------------------------------------------------------------------------------------------------
- void DNAParser :: Parse ()
- {
- StreamReaderAny& stream = *db.reader.get();
- DNA& dna = db.dna;
-
- if(!match4(stream,"SDNA")) {
- throw DeadlyImportError("BlenderDNA: Expected SDNA chunk");
- }
-
- // name dictionary
- if(!match4(stream,"NAME")) {
- throw DeadlyImportError("BlenderDNA: Expected NAME field");
- }
-
- std::vector<std::string> names (stream.GetI4());
- for_each(std::string& s, names) {
- while (char c = stream.GetI1()) {
- s += c;
- }
- }
-
- // type dictionary
- for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
- if(!match4(stream,"TYPE")) {
- throw DeadlyImportError("BlenderDNA: Expected TYPE field");
- }
-
- std::vector<Type> types (stream.GetI4());
- for_each(Type& s, types) {
- while (char c = stream.GetI1()) {
- s.name += c;
- }
- }
-
- // type length dictionary
- for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
- if(!match4(stream,"TLEN")) {
- throw DeadlyImportError("BlenderDNA: Expected TLEN field");
- }
-
- for_each(Type& s, types) {
- s.size = stream.GetI2();
- }
-
- // structures dictionary
- for (;stream.GetCurrentPos() & 0x3; stream.GetI1());
- if(!match4(stream,"STRC")) {
- throw DeadlyImportError("BlenderDNA: Expected STRC field");
- }
-
- size_t end = stream.GetI4(), fields = 0;
-
- dna.structures.reserve(end);
- for(size_t i = 0; i != end; ++i) {
-
- uint16_t n = stream.GetI2();
- if (n >= types.size()) {
- throw DeadlyImportError((format(),
- "BlenderDNA: Invalid type index in structure name" ,n,
- " (there are only ", types.size(), " entries)"
- ));
- }
-
- // maintain separate indexes
- dna.indices[types[n].name] = dna.structures.size();
-
- dna.structures.push_back(Structure());
- Structure& s = dna.structures.back();
- s.name = types[n].name;
- //s.index = dna.structures.size()-1;
-
- n = stream.GetI2();
- s.fields.reserve(n);
-
- size_t offset = 0;
- for (size_t m = 0; m < n; ++m, ++fields) {
-
- uint16_t j = stream.GetI2();
- if (j >= types.size()) {
- throw DeadlyImportError((format(),
- "BlenderDNA: Invalid type index in structure field ", j,
- " (there are only ", types.size(), " entries)"
- ));
- }
- s.fields.push_back(Field());
- Field& f = s.fields.back();
- f.offset = offset;
-
- f.type = types[j].name;
- f.size = types[j].size;
-
- j = stream.GetI2();
- if (j >= names.size()) {
- throw DeadlyImportError((format(),
- "BlenderDNA: Invalid name index in structure field ", j,
- " (there are only ", names.size(), " entries)"
- ));
- }
-
- f.name = names[j];
- f.flags = 0u;
-
- // pointers always specify the size of the pointee instead of their own.
- // The pointer asterisk remains a property of the lookup name.
- if (f.name[0] == '*') {
- f.size = db.i64bit ? 8 : 4;
- f.flags |= FieldFlag_Pointer;
- }
-
- // arrays, however, specify the size of a single element so we
- // need to parse the (possibly multi-dimensional) array declaration
- // in order to obtain the actual size of the array in the file.
- // Also we need to alter the lookup name to include no array
- // brackets anymore or size fixup won't work (if our size does
- // not match the size read from the DNA).
- if (*f.name.rbegin() == ']') {
- const std::string::size_type rb = f.name.find('[');
- if (rb == std::string::npos) {
- throw DeadlyImportError((format(),
- "BlenderDNA: Encountered invalid array declaration ",
- f.name
- ));
- }
-
- f.flags |= FieldFlag_Array;
- DNA::ExtractArraySize(f.name,f.array_sizes);
- f.name = f.name.substr(0,rb);
-
- f.size *= f.array_sizes[0] * f.array_sizes[1];
- }
-
- // maintain separate indexes
- s.indices[f.name] = s.fields.size()-1;
- offset += f.size;
- }
- s.size = offset;
- }
-
- DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(),
- " structures with totally ",fields," fields"));
-
- #ifdef ASSIMP_BUILD_BLENDER_DEBUG
- dna.DumpToFile();
- #endif
-
- dna.AddPrimitiveStructures();
- dna.RegisterConverters();
- }
-
-
- #ifdef ASSIMP_BUILD_BLENDER_DEBUG
-
- #include <fstream>
- // ------------------------------------------------------------------------------------------------
- void DNA :: DumpToFile()
- {
- // we dont't bother using the VFS here for this is only for debugging.
- // (and all your bases are belong to us).
-
- std::ofstream f("dna.txt");
- if (f.fail()) {
- DefaultLogger::get()->error("Could not dump dna to dna.txt");
- return;
- }
- f << "Field format: type name offset size" << "\n";
- f << "Structure format: name size" << "\n";
-
- for_each(const Structure& s, structures) {
- f << s.name << " " << s.size << "\n\n";
- for_each(const Field& ff, s.fields) {
- f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << std::endl;
- }
- f << std::endl;
- }
- DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt");
- }
- #endif
-
- // ------------------------------------------------------------------------------------------------
- /*static*/ void DNA :: ExtractArraySize(
- const std::string& out,
- size_t array_sizes[2]
- )
- {
- array_sizes[0] = array_sizes[1] = 1;
- std::string::size_type pos = out.find('[');
- if (pos++ == std::string::npos) {
- return;
- }
- array_sizes[0] = strtoul10(&out[pos]);
-
- pos = out.find('[',pos);
- if (pos++ == std::string::npos) {
- return;
- }
- array_sizes[1] = strtoul10(&out[pos]);
- }
-
- // ------------------------------------------------------------------------------------------------
- boost::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure(
- const Structure& structure,
- const FileDatabase& db
- ) const
- {
- std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name);
- if (it == converters.end()) {
- return boost::shared_ptr< ElemBase >();
- }
-
- boost::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))();
- (structure.*((*it).second.second))(ret,db);
-
- return ret;
- }
-
- // ------------------------------------------------------------------------------------------------
- DNA::FactoryPair DNA :: GetBlobToStructureConverter(
- const Structure& structure,
- const FileDatabase& /*db*/
- ) const
- {
- std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name);
- return it == converters.end() ? FactoryPair() : (*it).second;
- }
-
- // basing on http://www.blender.org/development/architecture/notes-on-sdna/
- // ------------------------------------------------------------------------------------------------
- void DNA :: AddPrimitiveStructures()
- {
- // NOTE: these are just dummies. Their presence enforces
- // Structure::Convert<target_type> to be called on these
- // empty structures. These converters are special
- // overloads which scan the name of the structure and
- // perform the required data type conversion if one
- // of these special names is found in the structure
- // in question.
-
- indices["int"] = structures.size();
- structures.push_back( Structure() );
- structures.back().name = "int";
- structures.back().size = 4;
-
- indices["short"] = structures.size();
- structures.push_back( Structure() );
- structures.back().name = "short";
- structures.back().size = 2;
-
-
- indices["char"] = structures.size();
- structures.push_back( Structure() );
- structures.back().name = "char";
- structures.back().size = 1;
-
-
- indices["float"] = structures.size();
- structures.push_back( Structure() );
- structures.back().name = "float";
- structures.back().size = 4;
-
-
- indices["double"] = structures.size();
- structures.push_back( Structure() );
- structures.back().name = "double";
- structures.back().size = 8;
-
- // no long, seemingly.
- }
-
- // ------------------------------------------------------------------------------------------------
- void SectionParser :: Next()
- {
- stream.SetCurrentPos(current.start + current.size);
-
- const char tmp[] = {
- stream.GetI1(),
- stream.GetI1(),
- stream.GetI1(),
- stream.GetI1()
- };
- current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1);
-
- current.size = stream.GetI4();
- current.address.val = ptr64 ? stream.GetU8() : stream.GetU4();
-
- current.dna_index = stream.GetI4();
- current.num = stream.GetI4();
-
- current.start = stream.GetCurrentPos();
- if (stream.GetRemainingSizeToLimit() < current.size) {
- throw DeadlyImportError("BLEND: invalid size of file block");
- }
-
- #ifdef ASSIMP_BUILD_BLENDER_DEBUG
- DefaultLogger::get()->debug(current.id);
- #endif
- }
-
-
-
- #endif
|