diff --git a/CMakeLists.txt b/CMakeLists.txt index 691d561..ef81902 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -129,6 +129,13 @@ else() set(ZLIB_LIBRARY "") endif() +find_package(bgeo) +if (bgeo_FOUND) + message("Building with modern Bgeo support") +else() + message("Building with NO modern Bgeo support") +endif() + # Make modules able to see partio library set(PARTIO_LIBRARIES partio ${ZLIB_LIBRARY}) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 451abdc..5349425 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -31,8 +31,34 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. -file(GLOB io_cpp "io/*.cpp") -file(GLOB core_cpp "core/*.cpp") +set(core_cpp + core/Particle.cpp + core/ParticleCaching.cpp + core/ParticleHeaders.cpp + core/ParticleSimple.cpp + core/ParticleSimpleInterleave.cpp) + +set(io_cpp + io/BGEO.cpp + io/BHCLASSIC.cpp + io/BIN.cpp + io/GEO.cpp + io/HCLASSIC.cpp + io/MC.cpp + io/ParticleIO.cpp + io/PDA.cpp + io/PDB.cpp + io/PDC.cpp + io/PRT.cpp + io/PTC.cpp + io/PTS.cpp + io/RIB.cpp + io/ZIP.cpp +) + +if (bgeo_FOUND) + list(APPEND io_cpp io/BJSON.cpp ) +endif() if(PARTIO_BUILD_SHARED_LIBS) set(PARTIO_LIBRARY_TYPE SHARED) @@ -55,6 +81,11 @@ if (ZLIB_FOUND) target_link_libraries(partio PUBLIC ZLIB::ZLIB) endif() +if (bgeo_FOUND) + target_link_libraries(partio PUBLIC bgeo::bgeo) + target_compile_definitions(partio PRIVATE MODERN_BGEO) +endif() + install(TARGETS partio DESTINATION ${CMAKE_INSTALL_LIBDIR}) file(GLOB public_includes "*.h") diff --git a/src/lib/core/KdTree.h b/src/lib/core/KdTree.h index 7b73b86..9736533 100644 --- a/src/lib/core/KdTree.h +++ b/src/lib/core/KdTree.h @@ -325,8 +325,16 @@ void KdTree::sortSubtree(int n, int size, int j) // partition range [n, n+size) along axis j into two subranges: // [n, n+leftSize+1) and [n+leftSize+1, n+size) +#ifdef NDEBUG std::nth_element(&_ids[n], &_ids[n+left], &_ids[n+size], ComparePointsById(&_points[0].p[j])); +#else + // In Debug mode element compiler asserting on _ids[n+size] with + // Expression: vector subscript out of range + // whereas it's not accessed by algorithm + std::nth_element(&_ids[n], &_ids[n+left], &_ids[std::min(n+size, this->size()-1)], + ComparePointsById(&_points[0].p[j])); +#endif // move median value (nth element) to front as root node of subtree std::swap(_ids[n], _ids[n+left]); diff --git a/src/lib/io/BGEO.cpp b/src/lib/io/BGEO.cpp index e3406d3..3fe02b4 100644 --- a/src/lib/io/BGEO.cpp +++ b/src/lib/io/BGEO.cpp @@ -1,468 +1,24 @@ -/* -PARTIO SOFTWARE -Copyright 2010 Disney Enterprises, Inc. All rights reserved -Redistribution and use 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. - -* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation -Studios" or the names of its contributors may NOT be used to -endorse or promote products derived from this software without -specific prior written permission from Walt Disney Pictures. - -Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND -CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED. -IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER 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 BASED 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 DAMAGES. -*/ - -#include "PartioEndian.h" #include "../core/ParticleHeaders.h" -#include "io.h" +#include "readers.h" namespace Partio { + ParticlesDataMutable* readBGEO(const char* filename, const bool headersOnly, std::ostream* errorStream) + { -using namespace std; - -void writeHoudiniStr(ostream& ostream,const string& s) -{ - write(ostream,(short)s.size()); - ostream.write(s.c_str(),s.size()); -} - -template -struct Helper -{ - T addAttribute(ParticlesDataMutable* simple, const char* name, ParticleAttributeType type, int size); - int registerIndexedStr(const T& attribute,const char* str); -}; -template<> -struct Helper -{ - ParticleAttribute addAttribute(ParticlesDataMutable* simple, const char* name, ParticleAttributeType type, int size) {return simple->addAttribute(name,type,size);} - int registerIndexedStr(ParticlesDataMutable* simple, const ParticleAttribute& attribute,const char* str) {return simple->registerIndexedStr(attribute,str);} -}; -template<> -struct Helper -{ - FixedAttribute addAttribute(ParticlesDataMutable* simple, const char* name, ParticleAttributeType type, int size) {return simple->addFixedAttribute(name,type,size);} - int registerIndexedStr(ParticlesDataMutable* simple, const FixedAttribute& attribute,const char* str) {return simple->registerFixedIndexedStr(attribute,str);} -}; - -class DummyAttribute {}; -template<> -struct Helper -{ - DummyAttribute addAttribute(ParticlesDataMutable* simple, const char* name, ParticleAttributeType type, int size) { return DummyAttribute(); } - int registerIndexedStr(ParticlesDataMutable* simple, const DummyAttribute& attribute,const char* str) { return 0; } -}; -struct DummyAccessor{ - template - DummyAccessor(const T& /*attr*/){} -}; - -template -bool getAttributes(int& particleSize, vector& attrOffsets, vector& attrHandles, vector& accessors, int nAttrib, istream* input, ParticlesDataMutable* simple, bool headersOnly, std::ostream* errorStream) -{ - Helper helper; - for(int i=0;i(*input,nameLength); - char* name=new char[nameLength+1]; - input->read(name,nameLength);name[nameLength]=0; - unsigned short size; - int houdiniType; - read(*input,size,houdiniType); - if(houdiniType==0 || houdiniType==1 || houdiniType==5){ - // read default values. don't do anything with them - for(int i=0;iread((char*)&defaultValue,sizeof(int)); - } - ParticleAttributeType type=NONE; - if(houdiniType==0) type=FLOAT; - else if(houdiniType==1) type=INT; - else if(houdiniType==5) type=VECTOR; - attrHandles.push_back(helper.addAttribute(simple,name,type,size)); - accessors.push_back(TAccessor(attrHandles.back())); - attrOffsets.push_back(particleSize); - particleSize+=size; - }else if(houdiniType==4){ - TAttribute attribute=helper.addAttribute(simple,name,INDEXEDSTR,size); - attrHandles.push_back(attribute); - accessors.push_back(TAccessor(attrHandles.back())); - attrOffsets.push_back(particleSize); - int numIndices=0; - read(*input,numIndices); - for(int ii=0;ii(*input,indexNameLength); - char* indexName=new char[indexNameLength+1];; - input->read(indexName,indexNameLength); - indexName[indexNameLength]=0; - if (!headersOnly) { - int id=helper.registerIndexedStr(simple,attribute,indexName); - if(id != ii){ - if(errorStream) *errorStream <<"Partio: error on read, expected registerIndexStr to return index "<release(); - return 0; - }else{ - if(errorStream) *errorStream <<"Partio: unknown attribute "<release(); - return 0; - } - delete[] name; - } - - return true; -} - -// read buffer, seekg doesn't work with gzip -void skip(istream *input, size_t numChars) -{ - static const size_t bufferSize = 4096; - static char buffer[bufferSize]; - while (numChars>0) { - int toRead=std::min(numChars,bufferSize); - input->read(buffer,toRead); - numChars-=toRead; - } -} - -// ignore primitive attributes, only know about Particle Systems currently -bool skipPrimitives(int nPoints, int nPrims, int nPrimAttrib, istream* input,std::ostream* errorStream) -{ - int particleSize=0; - vector primAttrOffsets; // offsets in # of 32 bit offsets - vector primAttrHandles; - vector primAccessors; - getAttributes(particleSize, primAttrOffsets, primAttrHandles, primAccessors, nPrimAttrib, input, 0, true, errorStream); - - for(int i=0;i(*input,primType); - if(primType==0x00008000) { - int size; - read(*input,size); - if(nPoints>=(int)1<<16) - skip(input,size*sizeof(int)); - else - skip(input,size*sizeof(unsigned short)); - skip(input,particleSize*sizeof(int)); - } else { - if(errorStream) *errorStream << "Partio: Unrecognized Primitive Type: 0x" << std::hex << primType << " - Cannot process detail attributes" << std::endl; - return false; - } - } - return true; -} - -ParticlesDataMutable* readBGEO(const char* filename,const bool headersOnly,std::ostream* errorStream) -{ - unique_ptr input(io::unzip(filename)); - if(!*input){ - if(errorStream) *errorStream<<"Partio: Unable to open file "<(*input,magic[0],magic[1],magic[2],magic[3]); - read(*input,versionChar,version,nPoints,nPrims,nPointGroups); - read(*input,nPrimGroups,nPointAttrib,nVertexAttrib,nPrimAttrib,nAttrib); - - - // Check header magic and version - const char bgeo_magic[5]={'B','g','e','o',0}; - if(strcmp(magic,bgeo_magic)){ - const char new_bgeo_magic[5]={0x7f,0x4e,0x53,0x4a,0}; - if(!strcmp(magic,new_bgeo_magic)){ - if(errorStream) *errorStream<<"Partio: Attempting to read new BGEO format, we only support old BGEO format. Try writing .bhclassic from Houdini."<addParticles(nPoints); - - - // Read attribute definitions - int particleSize=4; // Size in # of 32 bit primitives - vector attrOffsets; // offsets in # of 32 bit offsets - vector attrHandles; - vector accessors; - attrOffsets.push_back(0); // pull values from byte offset - attrHandles.push_back(simple->addAttribute("position",VECTOR,3)); // we always have one - accessors.push_back(ParticleAccessor(attrHandles[0])); - getAttributes(particleSize, attrOffsets, attrHandles, accessors, nPointAttrib, input.get(), simple, headersOnly, errorStream); - - if(headersOnly) { - skip(input.get(),nPoints*particleSize*sizeof(int)); - } else { - // Read the points - int *buffer=new int[particleSize]; - - // make iterator and register accessors - ParticlesDataMutable::iterator iterator=simple->begin(); - for(size_t i=0;iend();iterator!=end;++iterator){ - input->read((char*)buffer,particleSize*sizeof(int)); - for(unsigned int attrIndex=0;attrIndex(iterator); - for(int k=0;k fixedAttrOffsets; // offsets in # of 32 bit offsets - vector fixedAttrHandles; - vector fixedAccessors; - getAttributes(particleSize, fixedAttrOffsets, fixedAttrHandles, fixedAccessors, nAttrib, input.get(), simple, headersOnly, errorStream); - - if (headersOnly) return simple; - - // Read the points - int *fixedBuffer=new int[particleSize]; - input->read((char*)fixedBuffer,particleSize*sizeof(int)); - for(unsigned int attrIndex=0;attrIndexfixedDataWrite(fixedAttrHandles[attrIndex])[k]=fixedBuffer[fixedAttrOffsets[attrIndex]+k]; - } - } - delete [] fixedBuffer; - - // return the populated simpleParticle - return simple; -} - -bool writeBGEO(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream) -{ - unique_ptr output(io::write(filename, compressed)); - if(!*output){ - if(errorStream) *errorStream <<"Partio Unable to open file "<(*output,magic,versionChar,version,nPoints,nPrims,nPointGroups); - write(*output,nPrimGroups,nPointAttrib,nVertexAttrib,nPrimAttrib,nAttrib); - - vector handles; - vector accessors; - vector attrOffsets; - bool foundPosition=false; - int particleSize=4; - for(int i=0;i(attr.count); - const std::vector& indexTable=p.indexedStrs(attr); - int numIndexes=static_cast(indexTable.size()); - write(*output,size,houdiniType,numIndexes); - for(int i=0;i(attr.count); - write(*output,size,houdiniType); - for(int i=0;i(*output,defaultValue); - } - } - attrOffsets.push_back(particleSize); - particleSize+=attr.count; - } - handles.push_back(attr); - accessors.push_back(ParticleAccessor(handles.back())); - } - if(!foundPosition){ - if(errorStream) *errorStream <<"Partio: didn't find attr 'position' while trying to write GEO"<(iterator); - for(int k=0;kwrite((char*)buffer,particleSize*sizeof(int)); - } - delete [] buffer; - - vector fixedHandles; - vector fixedAttrOffsets; - particleSize=0; - for(int i=0;i& indexTable=p.fixedIndexedStrs(attr); - int numIndexes=indexTable.size(); - write(*output,size,houdiniType,numIndexes); - for(int ii=0;ii(*output,size,houdiniType); - for(int i=0;i(*output,defaultValue); - } - } - fixedAttrOffsets.push_back(particleSize); - particleSize+=attr.count; - - fixedHandles.push_back(attr); + // Fallback to bhclassic + return readBHCLASSIC(filename, headersOnly, errorStream); } - int *fixedBuffer=new int[particleSize]; - - for(unsigned int attrIndex=0;attrIndex(fixedHandles[attrIndex])[k]; - BIGEND::swap(fixedBuffer[fixedAttrOffsets[attrIndex]+k]); - } + bool writeBGEO(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream) + { + return writeBHCLASSIC(filename, p, compressed, errorStream); } - output->write((char*)fixedBuffer,particleSize*sizeof(int)); - - delete [] fixedBuffer; - - // Write extra - write(*output,(char)0x00); -#ifdef _MSC_VER - #pragma warning (push) - #pragma warning (disable : 4310 ) // suppress the warning for 0xff being truncated to 0x7f (max value of a signed char) -#endif - write(*output,(char)0xff); -#ifdef _MSC_VER - #pragma warning (pop) -#endif - - // success - return true; -} - } diff --git a/src/lib/io/BHCLASSIC.cpp b/src/lib/io/BHCLASSIC.cpp new file mode 100644 index 0000000..2fe9662 --- /dev/null +++ b/src/lib/io/BHCLASSIC.cpp @@ -0,0 +1,468 @@ +/* +PARTIO SOFTWARE +Copyright 2010 Disney Enterprises, Inc. All rights reserved + +Redistribution and use 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. + +* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation +Studios" or the names of its contributors may NOT be used to +endorse or promote products derived from this software without +specific prior written permission from Walt Disney Pictures. + +Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED. +IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER 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 BASED 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 DAMAGES. +*/ + +#include "PartioEndian.h" +#include "../core/ParticleHeaders.h" +#include "io.h" + +namespace Partio +{ + +using namespace std; + +void writeHoudiniStr(ostream& ostream,const string& s) +{ + write(ostream,(short)s.size()); + ostream.write(s.c_str(),s.size()); +} + +template +struct Helper +{ + T addAttribute(ParticlesDataMutable* simple, const char* name, ParticleAttributeType type, int size); + int registerIndexedStr(const T& attribute,const char* str); +}; +template<> +struct Helper +{ + ParticleAttribute addAttribute(ParticlesDataMutable* simple, const char* name, ParticleAttributeType type, int size) {return simple->addAttribute(name,type,size);} + int registerIndexedStr(ParticlesDataMutable* simple, const ParticleAttribute& attribute,const char* str) {return simple->registerIndexedStr(attribute,str);} +}; +template<> +struct Helper +{ + FixedAttribute addAttribute(ParticlesDataMutable* simple, const char* name, ParticleAttributeType type, int size) {return simple->addFixedAttribute(name,type,size);} + int registerIndexedStr(ParticlesDataMutable* simple, const FixedAttribute& attribute,const char* str) {return simple->registerFixedIndexedStr(attribute,str);} +}; + +class DummyAttribute {}; +template<> +struct Helper +{ + DummyAttribute addAttribute(ParticlesDataMutable* simple, const char* name, ParticleAttributeType type, int size) { return DummyAttribute(); } + int registerIndexedStr(ParticlesDataMutable* simple, const DummyAttribute& attribute,const char* str) { return 0; } +}; +struct DummyAccessor{ + template + DummyAccessor(const T& /*attr*/){} +}; + +template +bool getAttributes(int& particleSize, vector& attrOffsets, vector& attrHandles, vector& accessors, int nAttrib, istream* input, ParticlesDataMutable* simple, bool headersOnly, std::ostream* errorStream) +{ + Helper helper; + for(int i=0;i(*input,nameLength); + char* name=new char[nameLength+1]; + input->read(name,nameLength);name[nameLength]=0; + unsigned short size; + int houdiniType; + read(*input,size,houdiniType); + if(houdiniType==0 || houdiniType==1 || houdiniType==5){ + // read default values. don't do anything with them + for(int i=0;iread((char*)&defaultValue,sizeof(int)); + } + ParticleAttributeType type=NONE; + if(houdiniType==0) type=FLOAT; + else if(houdiniType==1) type=INT; + else if(houdiniType==5) type=VECTOR; + attrHandles.push_back(helper.addAttribute(simple,name,type,size)); + accessors.push_back(TAccessor(attrHandles.back())); + attrOffsets.push_back(particleSize); + particleSize+=size; + }else if(houdiniType==4){ + TAttribute attribute=helper.addAttribute(simple,name,INDEXEDSTR,size); + attrHandles.push_back(attribute); + accessors.push_back(TAccessor(attrHandles.back())); + attrOffsets.push_back(particleSize); + int numIndices=0; + read(*input,numIndices); + for(int ii=0;ii(*input,indexNameLength); + char* indexName=new char[indexNameLength+1];; + input->read(indexName,indexNameLength); + indexName[indexNameLength]=0; + if (!headersOnly) { + int id=helper.registerIndexedStr(simple,attribute,indexName); + if(id != ii){ + if(errorStream) *errorStream <<"Partio: error on read, expected registerIndexStr to return index "<release(); + return 0; + }else{ + if(errorStream) *errorStream <<"Partio: unknown attribute "<release(); + return 0; + } + delete[] name; + } + + return true; +} + +// read buffer, seekg doesn't work with gzip +void skip(istream *input, size_t numChars) +{ + static const size_t bufferSize = 4096; + static char buffer[bufferSize]; + while (numChars>0) { + int toRead=std::min(numChars,bufferSize); + input->read(buffer,toRead); + numChars-=toRead; + } +} + +// ignore primitive attributes, only know about Particle Systems currently +bool skipPrimitives(int nPoints, int nPrims, int nPrimAttrib, istream* input,std::ostream* errorStream) +{ + int particleSize=0; + vector primAttrOffsets; // offsets in # of 32 bit offsets + vector primAttrHandles; + vector primAccessors; + getAttributes(particleSize, primAttrOffsets, primAttrHandles, primAccessors, nPrimAttrib, input, 0, true, errorStream); + + for(int i=0;i(*input,primType); + if(primType==0x00008000) { + int size; + read(*input,size); + if(nPoints>=(int)1<<16) + skip(input,size*sizeof(int)); + else + skip(input,size*sizeof(unsigned short)); + skip(input,particleSize*sizeof(int)); + } else { + if(errorStream) *errorStream << "Partio: Unrecognized Primitive Type: 0x" << std::hex << primType << " - Cannot process detail attributes" << std::endl; + return false; + } + } + return true; +} + +ParticlesDataMutable* readBHCLASSIC(const char* filename,const bool headersOnly,std::ostream* errorStream) +{ + unique_ptr input(io::unzip(filename)); + if(!*input){ + if(errorStream) *errorStream<<"Partio: Unable to open file "<(*input,magic[0],magic[1],magic[2],magic[3]); + read(*input,versionChar,version,nPoints,nPrims,nPointGroups); + read(*input,nPrimGroups,nPointAttrib,nVertexAttrib,nPrimAttrib,nAttrib); + + + // Check header magic and version + const char bgeo_magic[5]={'B','g','e','o',0}; + if(strcmp(magic,bgeo_magic)){ + const char new_bgeo_magic[5]={0x7f,0x4e,0x53,0x4a,0}; + if(!strcmp(magic,new_bgeo_magic)){ + if(errorStream) *errorStream<<"Partio: Attempting to read new BGEO format, we only support old BGEO format. Try writing .bhclassic from Houdini."<addParticles(nPoints); + + + // Read attribute definitions + int particleSize=4; // Size in # of 32 bit primitives + vector attrOffsets; // offsets in # of 32 bit offsets + vector attrHandles; + vector accessors; + attrOffsets.push_back(0); // pull values from byte offset + attrHandles.push_back(simple->addAttribute("position",VECTOR,3)); // we always have one + accessors.push_back(ParticleAccessor(attrHandles[0])); + getAttributes(particleSize, attrOffsets, attrHandles, accessors, nPointAttrib, input.get(), simple, headersOnly, errorStream); + + if(headersOnly) { + skip(input.get(),nPoints*particleSize*sizeof(int)); + } else { + // Read the points + int *buffer=new int[particleSize]; + + // make iterator and register accessors + ParticlesDataMutable::iterator iterator=simple->begin(); + for(size_t i=0;iend();iterator!=end;++iterator){ + input->read((char*)buffer,particleSize*sizeof(int)); + for(unsigned int attrIndex=0;attrIndex(iterator); + for(int k=0;k fixedAttrOffsets; // offsets in # of 32 bit offsets + vector fixedAttrHandles; + vector fixedAccessors; + getAttributes(particleSize, fixedAttrOffsets, fixedAttrHandles, fixedAccessors, nAttrib, input.get(), simple, headersOnly, errorStream); + + if (headersOnly) return simple; + + // Read the points + int *fixedBuffer=new int[particleSize]; + input->read((char*)fixedBuffer,particleSize*sizeof(int)); + for(unsigned int attrIndex=0;attrIndexfixedDataWrite(fixedAttrHandles[attrIndex])[k]=fixedBuffer[fixedAttrOffsets[attrIndex]+k]; + } + } + delete [] fixedBuffer; + + // return the populated simpleParticle + return simple; +} + +bool writeBHCLASSIC(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream) +{ + unique_ptr output(io::write(filename, compressed)); + if(!*output){ + if(errorStream) *errorStream <<"Partio Unable to open file "<(*output,magic,versionChar,version,nPoints,nPrims,nPointGroups); + write(*output,nPrimGroups,nPointAttrib,nVertexAttrib,nPrimAttrib,nAttrib); + + vector handles; + vector accessors; + vector attrOffsets; + bool foundPosition=false; + int particleSize=4; + for(int i=0;i(attr.count); + const std::vector& indexTable=p.indexedStrs(attr); + int numIndexes=static_cast(indexTable.size()); + write(*output,size,houdiniType,numIndexes); + for(int i=0;i(attr.count); + write(*output,size,houdiniType); + for(int i=0;i(*output,defaultValue); + } + } + attrOffsets.push_back(particleSize); + particleSize+=attr.count; + } + handles.push_back(attr); + accessors.push_back(ParticleAccessor(handles.back())); + } + if(!foundPosition){ + if(errorStream) *errorStream <<"Partio: didn't find attr 'position' while trying to write GEO"<(iterator); + for(int k=0;kwrite((char*)buffer,particleSize*sizeof(int)); + } + delete [] buffer; + + vector fixedHandles; + vector fixedAttrOffsets; + particleSize=0; + for(int i=0;i& indexTable=p.fixedIndexedStrs(attr); + int numIndexes=indexTable.size(); + write(*output,size,houdiniType,numIndexes); + for(int ii=0;ii(*output,size,houdiniType); + for(int i=0;i(*output,defaultValue); + } + } + fixedAttrOffsets.push_back(particleSize); + particleSize+=attr.count; + + fixedHandles.push_back(attr); + } + + int *fixedBuffer=new int[particleSize]; + + for(unsigned int attrIndex=0;attrIndex(fixedHandles[attrIndex])[k]; + BIGEND::swap(fixedBuffer[fixedAttrOffsets[attrIndex]+k]); + } + } + output->write((char*)fixedBuffer,particleSize*sizeof(int)); + + delete [] fixedBuffer; + + // Write extra + write(*output,(char)0x00); +#ifdef _MSC_VER + #pragma warning (push) + #pragma warning (disable : 4310 ) // suppress the warning for 0xff being truncated to 0x7f (max value of a signed char) +#endif + write(*output,(char)0xff); +#ifdef _MSC_VER + #pragma warning (pop) +#endif + + // success + return true; +} + +} diff --git a/src/lib/io/BJSON.cpp b/src/lib/io/BJSON.cpp new file mode 100644 index 0000000..920c1a0 --- /dev/null +++ b/src/lib/io/BJSON.cpp @@ -0,0 +1,136 @@ +// Utilize this library +// https://github.com/LaikaStudios/bgeo_reader + + +#include "../core/ParticleHeaders.h" + +#ifdef MODERN_BGEO + #include + #include + #include +#endif + +#include + +using namespace ika::bgeo; + +namespace Partio +{ + std::string getMapping(const char* name) + { + const std::unordered_map mapping = + { + {"P", "position"}, + }; + auto it = mapping.find(name); + if (it != mapping.end()) + return it->second; + else + return name; + } + + ParticlesDataMutable* readBJSON(const char* filename, const bool headersOnly, std::ostream* errorStream) + { + try + { + BgeoHeader bgeoHeader(filename); + } + catch(const ika::bgeo::parser::ReadError& e) + { + return nullptr; + } + + Bgeo bgeo(filename, false); + + // Allocate a simple particle with the appropriate number of points + ParticlesDataMutable* particles = headersOnly ? new ParticleHeaders : create(); + particles->addParticles(bgeo.getPointCount()); + + int attribCount = bgeo.getPointAttributeCount(); + for (int k = 0; k < attribCount; k++) + { + Bgeo::AttributePtr currentAttrib = bgeo.getPointAttribute(k); + + if (strcmp(currentAttrib->getType(), "string") == 0) + { + std::vector values; + std::vector strings; + currentAttrib->getData(values); + currentAttrib->getStrings(strings); + + ParticleAttribute attrib = particles->addAttribute( getMapping(currentAttrib->getName()).c_str(), INDEXEDSTR, 1); + for(size_t i = 0; i < strings.size(); i++) + { + particles->registerIndexedStr(attrib, strings[i].c_str()); + } + + for (size_t i = 0; i < bgeo.getPointCount(); i++) + { + int* data = particles->dataWrite(attrib, i); + *data = values[i]; + } + continue; + } + + int tupleSize = currentAttrib->getTupleSize(); + parser::storage::Storage fundamentalType = currentAttrib->getFundamentalType();// 1: Int32, 2: Fpreal32 + ParticleAttributeType myType = NONE; + + if (fundamentalType == parser::storage::Int32) + myType = INT; + else if(fundamentalType == parser::storage::Fpreal32) + { + myType = FLOAT; + const char *subType = currentAttrib->getSubType(); + + if ((tupleSize == 3) && + ((strcmp(subType, "point") == 0) || + (strcmp(subType, "vector") == 0) || + (strcmp(subType, "normal") == 0))) + myType = VECTOR; + } + else + continue; + + ParticleAttribute attrib = particles->addAttribute( getMapping(currentAttrib->getName()).c_str(), myType, tupleSize); + + if (fundamentalType == parser::storage::Int32) + { + std::vector values; + currentAttrib->getData(values); + size_t idx = 0; + + for (size_t i = 0; i < bgeo.getPointCount(); i++) + { + int* data = particles->dataWrite(attrib, i); + + for (int c = 0; c < tupleSize; c++) + { + data[c] = values[idx+c]; + } + idx += tupleSize; + } + } + else if(fundamentalType == parser::storage::Fpreal32) + { + std::vector values; + currentAttrib->getData(values); + size_t idx = 0; + + for (size_t i = 0; i < bgeo.getPointCount(); i++) + { + float* data = particles->dataWrite(attrib, i); + for (int c = 0; c < tupleSize; c++) + { + data[c] = values[idx+c]; + } + idx += tupleSize; + } + } + else + continue; + } + + return particles; + } +} diff --git a/src/lib/io/GEO.cpp b/src/lib/io/GEO.cpp index f08a8b6..1943587 100644 --- a/src/lib/io/GEO.cpp +++ b/src/lib/io/GEO.cpp @@ -1,318 +1,24 @@ -/* -PARTIO SOFTWARE -Copyright 2010 Disney Enterprises, Inc. All rights reserved - -Redistribution and use 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. - -* The names "Disney", "Walt Disney Pictures", "Walt Disney Animation -Studios" or the names of its contributors may NOT be used to -endorse or promote products derived from this software without -specific prior written permission from Walt Disney Pictures. - -Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND -CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, -BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED. -IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER 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 BASED 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 DAMAGES. -*/ #include "../core/ParticleHeaders.h" -#include "io.h" +#include "readers.h" namespace Partio { + ParticlesDataMutable* readGEO(const char* filename, const bool headersOnly, std::ostream* errorStream) + { -using namespace std; - -template -void readGeoAttr(istream& f,const ParticleAttribute& attr,ParticleAccessor& accessor,ParticlesDataMutable::iterator& iterator) -{ - //cout<<"reading "<::TYPE TYPE; - TYPE* data=accessor.raw(iterator); - for(int k=0;k>data[k]; - } -} - -void writeString(std::ostream& output,const char* s){ - const char* p=s; - output<<"\""; - while(*p != 0){ - if(*p=='\\' || *p=='"') output<<'\\'; - output<<*p; - p++; - } - output<<"\""; -} +#ifdef MODERN_BGEO + ParticlesDataMutable *result = readBJSON(filename, headersOnly, errorStream); + if (result != nullptr) + return result; +#endif -string scanString(istream& input) -{ - // TODO: this code does not check for buf overrun - // TODO: this code doesn't properly check for FEOF condition - char buf[4096]; - char *ptr=buf; - char c; - while(input.good()){ - input.get(c); - if(!isspace(c)) break; - } - if(!input.good()) return ""; - - if(c!='"'){ - while(input.good()){ - *ptr++=c; - input.get(c); - if(isspace(c)) break; - } - }else{ - while(input.good()){ - input.get(c); - if(c=='\\'){ - input.get(c); - *ptr++=c; - }else if(c=='"'){ - break; - }else{ - *ptr++=c; - } - } - } - *ptr++=0; - return string(buf); -} - -ParticlesDataMutable* readGEO(const char* filename,const bool headersOnly,std::ostream* errorStream) -{ - unique_ptr input(io::unzip(filename)); - if(!*input){ - if(errorStream) *errorStream<<"Partio: Can't open particle data file: "<good()){ - *input>>word; - if(word=="NPoints") *input>>NPoints; - else if(word=="NPointAttrib"){*input>>NPointAttrib;break;} - } - // skip until PointAttrib - while(input->good()){ - *input>>word; - if(word=="PointAttrib") break; + // Fallback to hclassic + return readHCLASSIC(filename, headersOnly, errorStream); } - // read attribute descriptions - int attrInfoRead = 0; - - ParticleAttribute positionAttr=simple->addAttribute("position",VECTOR,3); - ParticleAccessor positionAccessor(positionAttr); - vector attrs; - vector accessors; - while (input->good() && attrInfoRead < NPointAttrib) { - string attrName, attrType; - int nvals = 0; - *input >> attrName >> nvals >> attrType; - if(attrType=="index"){ - if(errorStream) *errorStream<<"Partio: attr '"<>nIndices; - ParticleAttribute attribute=simple->addAttribute(attrName.c_str(),INDEXEDSTR,1); - attrs.push_back(attribute); - for(int j=0;j>indexName; - indexName=scanString(*input); - if (!headersOnly) { - int id=simple->registerIndexedStr(attribute,indexName.c_str()); - if(id != j){ - if(errorStream) *errorStream<<"Partio: error on read, expected registerIndexStr to return index "<>defval; - } - ParticleAttributeType type; - // TODO: fix for other attribute types - if(attrType=="float") type=FLOAT; - else if(attrType=="vector") type=VECTOR; - else if(attrType=="int") type=INT; - else{ - if(errorStream) *errorStream<<"Partio: unknown attribute "<addAttribute(attrName.c_str(),type,nvals)); - accessors.push_back(ParticleAccessor(attrs.back())); - attrInfoRead++; - } + bool writeGEO(const char* filename,const ParticlesData& p,const bool compressed,std::ostream* errorStream) + { + return writeHCLASSIC(filename, p, compressed, errorStream); } - - simple->addParticles(NPoints); - - ParticlesDataMutable::iterator iterator=simple->begin(); - iterator.addAccessor(positionAccessor); - for(size_t i=0;iend();iterator!=end && input->good();++iterator){ - float* posInternal=positionAccessor.raw(iterator); - for(int i=0;i<3;i++) *input>>posInternal[i]; - *input>>fval; - //cout<<"saw "<> paren; - if (paren != '(') break; - - // read additional attribute values - for (unsigned int i=0;i(*input,attrs[i],accessors[i],iterator);break; - case VECTOR: readGeoAttr(*input,attrs[i],accessors[i],iterator);break; - case INT: readGeoAttr(*input,attrs[i],accessors[i],iterator);break; - case INDEXEDSTR: readGeoAttr(*input,attrs[i],accessors[i],iterator);break; - } - } - // skip closing parenthes - *input >> paren; - if (paren != ')') break; - } - return simple; -} - - -template -void writeType(ostream& output,const ParticlesData&,const ParticleAttribute& attrib, - const ParticleAccessor& accessor,const ParticlesData::const_iterator& iterator) -{ - const T* data=accessor.raw(iterator); - for(int i=0;i0) output<<" "; - output< output(io::write(filename, compressed)); - *output<<"PGEOMETRY V5"<0) *output<<"PointAttrib"< handles; - vector accessors; - for(int i=0;i& indexes=p.indexedStrs(attrib); - *output<& point=positionAccessor.data >(iterator); - *output<0) *output<<"\t"; - ParticleAttribute& handle=handles[aindex]; - ParticleAccessor& accessor=accessors[aindex]; - switch(handle.type){ - case NONE: assert(false);break; - case FLOAT: writeType::TYPE>(*output,p,handle,accessor,iterator);break; - case INT: writeType::TYPE>(*output,p,handle,accessor,iterator);break; - case VECTOR: writeType::TYPE>(*output,p,handle,accessor,iterator);break; - case INDEXEDSTR: writeType::TYPE>(*output,p,handle,accessor,iterator);break; - } - } - if(handles.size()) *output<<")"; - *output< +void readGeoAttr(istream& f,const ParticleAttribute& attr,ParticleAccessor& accessor,ParticlesDataMutable::iterator& iterator) +{ + //cout<<"reading "<::TYPE TYPE; + TYPE* data=accessor.raw(iterator); + for(int k=0;k>data[k]; + } +} + +void writeString(std::ostream& output,const char* s){ + const char* p=s; + output<<"\""; + while(*p != 0){ + if(*p=='\\' || *p=='"') output<<'\\'; + output<<*p; + p++; + } + output<<"\""; +} + +string scanString(istream& input) +{ + // TODO: this code does not check for buf overrun + // TODO: this code doesn't properly check for FEOF condition + char buf[4096]; + char *ptr=buf; + char c; + while(input.good()){ + input.get(c); + if(!isspace(c)) break; + } + if(!input.good()) return ""; + + if(c!='"'){ + while(input.good()){ + *ptr++=c; + input.get(c); + if(isspace(c)) break; + } + }else{ + while(input.good()){ + input.get(c); + if(c=='\\'){ + input.get(c); + *ptr++=c; + }else if(c=='"'){ + break; + }else{ + *ptr++=c; + } + } + } + *ptr++=0; + return string(buf); +} + +ParticlesDataMutable* readHCLASSIC(const char* filename,const bool headersOnly,std::ostream* errorStream) +{ + unique_ptr input(io::unzip(filename)); + if(!*input){ + if(errorStream) *errorStream<<"Partio: Can't open particle data file: "<good()){ + *input>>word; + if(word=="NPoints") *input>>NPoints; + else if(word=="NPointAttrib"){*input>>NPointAttrib;break;} + } + // skip until PointAttrib + while(input->good()){ + *input>>word; + if(word=="PointAttrib") break; + } + // read attribute descriptions + int attrInfoRead = 0; + + ParticleAttribute positionAttr=simple->addAttribute("position",VECTOR,3); + ParticleAccessor positionAccessor(positionAttr); + + vector attrs; + vector accessors; + while (input->good() && attrInfoRead < NPointAttrib) { + string attrName, attrType; + int nvals = 0; + *input >> attrName >> nvals >> attrType; + if(attrType=="index"){ + if(errorStream) *errorStream<<"Partio: attr '"<>nIndices; + ParticleAttribute attribute=simple->addAttribute(attrName.c_str(),INDEXEDSTR,1); + attrs.push_back(attribute); + for(int j=0;j>indexName; + indexName=scanString(*input); + if (!headersOnly) { + int id=simple->registerIndexedStr(attribute,indexName.c_str()); + if(id != j){ + if(errorStream) *errorStream<<"Partio: error on read, expected registerIndexStr to return index "<>defval; + } + ParticleAttributeType type; + // TODO: fix for other attribute types + if(attrType=="float") type=FLOAT; + else if(attrType=="vector") type=VECTOR; + else if(attrType=="int") type=INT; + else{ + if(errorStream) *errorStream<<"Partio: unknown attribute "<addAttribute(attrName.c_str(),type,nvals)); + accessors.push_back(ParticleAccessor(attrs.back())); + attrInfoRead++; + } + } + + simple->addParticles(NPoints); + + ParticlesDataMutable::iterator iterator=simple->begin(); + iterator.addAccessor(positionAccessor); + for(size_t i=0;iend();iterator!=end && input->good();++iterator){ + float* posInternal=positionAccessor.raw(iterator); + for(int i=0;i<3;i++) *input>>posInternal[i]; + *input>>fval; + //cout<<"saw "<> paren; + if (paren != '(') break; + + // read additional attribute values + for (unsigned int i=0;i(*input,attrs[i],accessors[i],iterator);break; + case VECTOR: readGeoAttr(*input,attrs[i],accessors[i],iterator);break; + case INT: readGeoAttr(*input,attrs[i],accessors[i],iterator);break; + case INDEXEDSTR: readGeoAttr(*input,attrs[i],accessors[i],iterator);break; + } + } + // skip closing parenthes + *input >> paren; + if (paren != ')') break; + } + return simple; +} + + +template +void writeType(ostream& output,const ParticlesData&,const ParticleAttribute& attrib, + const ParticleAccessor& accessor,const ParticlesData::const_iterator& iterator) +{ + const T* data=accessor.raw(iterator); + for(int i=0;i0) output<<" "; + output< output(io::write(filename, compressed)); + *output<<"PGEOMETRY V5"<0) *output<<"PointAttrib"< handles; + vector accessors; + for(int i=0;i& indexes=p.indexedStrs(attrib); + *output<& point=positionAccessor.data >(iterator); + *output<0) *output<<"\t"; + ParticleAttribute& handle=handles[aindex]; + ParticleAccessor& accessor=accessors[aindex]; + switch(handle.type){ + case NONE: assert(false);break; + case FLOAT: writeType::TYPE>(*output,p,handle,accessor,iterator);break; + case INT: writeType::TYPE>(*output,p,handle,accessor,iterator);break; + case VECTOR: writeType::TYPE>(*output,p,handle,accessor,iterator);break; + case INDEXEDSTR: writeType::TYPE>(*output,p,handle,accessor,iterator);break; + } + } + if(handles.size()) *output<<")"; + *output<