bool writeBGEO(const char* filename,const ParticlesData& p,const bool compressed) { auto_ptr<ostream> output( compressed ? Gzip_Out(filename,ios::out|ios::binary) :new ofstream(filename,ios::out|ios::binary)); if(!*output){ cerr<<"Partio Unable to open file "<<filename<<endl; return false; } int magic=((((('B'<<8)|'g')<<8)|'e')<<8)|'o'; char versionChar='V'; int version=5; int nPoints=p.numParticles(); int nPrims=1; int nPointGroups=0; int nPrimGroups=0; int nPointAttrib=p.numAttributes()-1; int nVertexAttrib=0; int nPrimAttrib=1; int nAttrib=0; write<BIGEND>(*output,magic,versionChar,version,nPoints,nPrims,nPointGroups); write<BIGEND>(*output,nPrimGroups,nPointAttrib,nVertexAttrib,nPrimAttrib,nAttrib); vector<ParticleAttribute> handles; vector<ParticleAccessor> accessors; vector<int> attrOffsets; bool foundPosition=false; int particleSize=4; for(int i=0;i<p.numAttributes();i++){ ParticleAttribute attr; p.attributeInfo(i,attr); if(attr.name=="position"){ attrOffsets.push_back(0); foundPosition=true; }else{ writeHoudiniStr(*output,attr.name); if(attr.type==INDEXEDSTR){ int houdiniType=4; unsigned short size=attr.count; const std::vector<std::string>& indexTable=p.indexedStrs(attr); int numIndexes=indexTable.size(); write<BIGEND>(*output,size,houdiniType,numIndexes); for(int i=0;i<numIndexes;i++) writeHoudiniStr(*output,indexTable[i]); }else{ int houdiniType=0; switch(attr.type){ case FLOAT: houdiniType=0;break; case INT: houdiniType=1;break; case VECTOR: houdiniType=5;break; case INDEXEDSTR: case NONE: assert(false);houdiniType=0;break; } unsigned short size=attr.count; write<BIGEND>(*output,size,houdiniType); for(int i=0;i<attr.count;i++){ int defaultValue=0; write<BIGEND>(*output,defaultValue); } } attrOffsets.push_back(particleSize); particleSize+=attr.count; } handles.push_back(attr); accessors.push_back(ParticleAccessor(handles.back())); } if(!foundPosition){ cerr<<"Partio: didn't find attr 'position' while trying to write GEO"<<endl; return false; } ParticlesData::const_iterator iterator=p.begin(); for(size_t i=0;i<accessors.size();i++) iterator.addAccessor(accessors[i]); int *buffer=new int[particleSize]; for(ParticlesData::const_iterator end=p.end();iterator!=end;++iterator){ for(unsigned int attrIndex=0;attrIndex<handles.size();attrIndex++){ ParticleAttribute& handle=handles[attrIndex]; ParticleAccessor& accessor=accessors[attrIndex]; // TODO: this violates strict aliasing, we could just go to char* and make // a different endian swapper const int* data=accessor.raw<int>(iterator); for(int k=0;k<handle.count;k++){ buffer[attrOffsets[attrIndex]+k]=data[k]; BIGEND::swap(buffer[attrOffsets[attrIndex]+k]); } } // set homogeneous coordinate float *w=(float*)&buffer[3]; *w=1.; BIGEND::swap(*w); output->write((char*)buffer,particleSize*sizeof(int)); } delete [] buffer; // Write primitive attribs writeHoudiniStr(*output,"generator"); write<BIGEND>(*output,(short)0x1); // count 1 write<BIGEND>(*output,(int)0x4); // type 4 index write<BIGEND>(*output,(int)0x1); // type 4 index writeHoudiniStr(*output,"papi"); // Write the primitive write<BIGEND>(*output,(int)0x8000); write<BIGEND>(*output,(int)nPoints); if(nPoints>(int)1<<16) for(int i=0;i<nPoints;i++) write<BIGEND>(*output,(int)i); else for(int i=0;i<nPoints;i++) write<BIGEND>(*output,(unsigned short)i); write<BIGEND>(*output,(int)0); // Write extra write<BIGEND>(*output,(char)0x00); write<BIGEND>(*output,(char)0xff); // success return true; }
bool writeRIB(const char* filename, const ParticlesData& p, const bool compressed,std::ostream* errorStream) { auto_ptr<ostream> output( compressed ? Gzip_Out(filename, ios::out | ios::binary) : new ofstream(filename, ios::out | ios::binary)); ParticleAttribute dummy; bool foundP = p.attributeInfo("position", dummy) || p.attributeInfo("P", dummy); bool foundP2 = p.attributeInfo("position2", dummy) || p.attributeInfo("P2", dummy); bool foundWidth = p.attributeInfo("radius", dummy) || p.attributeInfo("width", dummy) || p.attributeInfo("radiusPP", dummy); if (!foundP) { if(errorStream) *errorStream << "Partio: failed to find attr 'position' or 'P' for RIB output" << endl; return false; } if (!foundWidth) if(errorStream) *errorStream << "Partio: failed to find attr 'width','radius', or 'radiusPP' for RIB output, using constantwidth = 1" << endl; *output << "version 3.04" << endl; if (foundP2) *output << "GeometricApproximation \"motionfactor\" 1.0" << endl; *output << "AttributeBegin" << endl; *output << " ResourceBegin" << endl; *output << " Attribute \"identifier\" \"name\" [\"|partioParticle1|partioParticleShape1\"]" << endl; int numPasses = foundP2 ? 2 : 1; if (foundP2) *output << " MotionBegin [0.0 1.0]" << endl; for (int passIndex = 0; passIndex < numPasses; ++passIndex) { *output << (foundP2 ? " " : "") << " Points "; for (int attrIndex = 0; attrIndex < p.numAttributes(); ++attrIndex) { ParticleAttribute attr; p.attributeInfo(attrIndex, attr); if ((passIndex == 0 && (attr.name == "P2" || attr.name == "position2")) || (passIndex == 1 && (attr.name == "P" || attr.name == "position"))) continue; string attrname = (attr.name == "position" || attr.name == "position2" || attr.name == "P" || attr.name == "P2") ? "P" : (attr.name == "radius" ? "width" : attr.name); *output << "\"" << attrname << "\" [ "; int spaceCount = 0; switch (attr.type) { case Partio::FLOAT: case Partio::VECTOR: { for (int particleIndex = 0; particleIndex < p.numParticles(); ++particleIndex) { const float *data = p.data<float>(attr, particleIndex); for (int count = 0; count < attr.count; ++count) { *output << data[count] << " "; spaceCount ++; } if (spaceCount > 12) { *output << "\n "; spaceCount = 0; } } break; } case Partio::INT: { for (int particleIndex = 0; particleIndex < p.numParticles(); ++particleIndex) { const int *data = p.data<int>(attr, particleIndex); for (int count = 0; count < attr.count; ++count) { *output << data[count] << " "; spaceCount ++; } if (spaceCount > 12) { *output << "\n "; spaceCount = 0; } } break; } case Partio::NONE: default: break; } *output << "]\n "; } if (!foundWidth) *output << "\"constantwidth\" [1.0]"; *output << endl; } if (foundP2) *output << " MotionEnd" << endl; *output << " ResourceEnd" << endl; *output << "AttributeEnd" << endl; return true; }
bool writePRT(const char* filename,const ParticlesData& p,const bool /*compressed*/) { /// Krakatoa pukes on 0 particle files for some reason so don't export at all.... int numParts = p.numParticles(); if (numParts) { std::auto_ptr<std::ostream> output( new std::ofstream(filename,std::ios::out|std::ios::binary)); if (!*output) { std::cerr<<"Partio Unable to open file "<<filename<<std::endl; return false; } FileHeadder header; memcpy(header.magic, magic, sizeof(magic)); memcpy(header.signature, signature, sizeof(signature)); header.headersize = 0x38; header.version = 1; header.numParticles = p.numParticles(); int reserve = 4; output->write((char*)&header,sizeof(FileHeadder)); write<LITEND>(*output, reserve); write<LITEND>(*output, (int)p.numAttributes()); reserve = 0x2c; write<LITEND>(*output, reserve); std::vector<ParticleAttribute> attrs; int offset = 0; for (int i=0;i<p.numAttributes();i++) { ParticleAttribute attr; p.attributeInfo(i,attr); Channel ch; memset(&ch, 0, sizeof(Channel)); memcpy((char*)ch.name, attr.name.c_str(), attr.name.size()); ch.offset = offset; switch (attr.type) { case FLOAT: ch.type=4; ch.arity=attr.count; offset += sizeof(float)*attr.count; break; case INT: ch.type=1; ch.arity=attr.count; offset += sizeof(int)*attr.count; break; case VECTOR: ch.type=4; ch.arity=attr.count; offset += sizeof(float)*attr.count; break; case INDEXEDSTR:; break; case NONE:;break; } if (ch.arity) { #ifdef AUTO_CASES if (ch.name[0] >= 'a' && ch.name[0] <= 'z') { ch.name[0] -= 0x20; } #endif output->write((char*)&ch,sizeof(Channel)); attrs.push_back(attr); } } z_stream z; z.zalloc = Z_NULL;z.zfree = Z_NULL;z.opaque = Z_NULL; if (deflateInit( &z, Z_DEFAULT_COMPRESSION ) != Z_OK) { std::cerr<<"Zlib deflateInit error"<<std::endl; return false; } char out_buf[OUT_BUFSIZE+10]; for (int particleIndex=0;particleIndex<p.numParticles();particleIndex++) { for (unsigned int attrIndex=0;attrIndex<attrs.size();attrIndex++) { if (attrs[attrIndex].type==Partio::INT) { const int* data=p.data<int>(attrs[attrIndex],particleIndex); if (!write_buffer(*output, z, (char*)out_buf, (void*)data, sizeof(int)*attrs[attrIndex].count, false)) return false; } else if (attrs[attrIndex].type==Partio::FLOAT || attrs[attrIndex].type==Partio::VECTOR) { const float* data=p.data<float>(attrs[attrIndex],particleIndex); if (!write_buffer(*output, z, (char*)out_buf, (void*)data, sizeof(int)*attrs[attrIndex].count, false)) return false; } } } write_buffer(*output, z, (char*)out_buf, 0, 0, true); if (deflateEnd( &z ) != Z_OK) { std::cerr<<"Zlib deflateEnd error"<<std::endl; return false; } // success }// end if numParticles > 0 return true; }
bool writePTC(const char* filename,const ParticlesData& p,const bool compressed) { //ofstream output(filename,ios::out|ios::binary); auto_ptr<ostream> output( compressed ? Gzip_Out(filename,ios::out|ios::binary) :new ofstream(filename,ios::out|ios::binary)); if(!*output){ cerr<<"Partio Unable to open file "<<filename<<endl; return false; } // magic & version write<LITEND>(*output,ptc_magic); write<LITEND>(*output,(int)0); // particle count double numParticlesAsDouble=p.numParticles(); write<LITEND>(*output,numParticlesAsDouble); ParticleAttribute positionHandle,normalHandle,radiusHandle; bool foundPosition=p.attributeInfo("position",positionHandle); bool foundNormal=p.attributeInfo("normal",normalHandle); bool foundRadius=p.attributeInfo("radius",radiusHandle); if(!foundPosition){ cerr<<"Partio: failed to find attr 'position' for PTC output"<<endl; return false; } if(!foundNormal) cerr<<"Partio: failed to find attr 'normal' for PTC output, using 0,0,0"<<endl; if(!foundRadius) cerr<<"Partio: failed to find attr 'radius' for PTC output, using 1"<<endl; // compute bounding box float boxmin[3]={FLT_MAX,FLT_MAX,FLT_MAX},boxmax[3]={-FLT_MAX,-FLT_MAX,-FLT_MAX}; for(int i=0;i<p.numParticles();i++){ const float* pos=p.data<float>(positionHandle,i); for(int k=0;k<3;k++){ boxmin[k]=min(pos[k],boxmin[k]); boxmax[k]=max(pos[k],boxmax[k]); } } write<LITEND>(*output,boxmin[0],boxmin[1],boxmin[2]); write<LITEND>(*output,boxmax[0],boxmax[1],boxmax[2]); // world-to-eye & for(int i=0;i<4;i++) for(int j=0;j<4;j++){ if(i==j) write<LITEND>(*output,(float)1); else write<LITEND>(*output,(float)0); } // eye-to-screen const float foo[4][4]={{1.8f,0,0,0}, {0,2.41f,0,0}, {0,0,1,1}, {0,0,-.1f,0}}; for(int i=0;i<4;i++) for(int j=0;j<4;j++){ write<LITEND>(*output,foo[i][j]); } // imgwidth imgheight, imgdepth write<LITEND>(*output,(float)640,(float)480,(float)300); int nVars=0,dataSize=0; vector<string> specs; vector<ParticleAttribute> attrs; for(int i=0;i<p.numAttributes();i++){ ParticleAttribute attr; p.attributeInfo(i,attr); if(attr.name!="position" && attr.name!="radius" && attr.name!="normal"){ if(attr.count==3 && attr.type!=INT){ attrs.push_back(attr); specs.push_back("color "+attr.name+"\n"); dataSize+=attr.count; nVars++; }else if(attr.count==1 && attr.type!=INT){ attrs.push_back(attr); dataSize+=attr.count; nVars++; specs.push_back("float "+attr.name+"\n"); }else if(attr.count==16 && attr.type!=INT){ nVars++; attrs.push_back(attr); dataSize+=attr.count; specs.push_back("matrix "+attr.name+"\n"); }else{ cerr<<"Partio: Unable to write data type "<<TypeName(attr.type)<<"["<<attr.count<<"] to a ptc file"<<endl; } } } //cerr<<"writing dataSize"<<dataSize<<endl; write<LITEND>(*output,nVars,dataSize); for(unsigned int i=0;i<specs.size();i++){ output->write(specs[i].c_str(),specs[i].length()); } for(int pointIndex=0;pointIndex<p.numParticles();pointIndex++){ // write position const float* pos=p.data<float>(positionHandle,pointIndex); write<LITEND>(*output,pos[0],pos[1],pos[2]); // write normal static const float static_n[3]={0,0,0}; const float* n=static_n; if(foundNormal) n=p.data<float>(normalHandle,pointIndex); // normalize and encode normals as two unsigned short integers z and // phi, representing the z coordinate and angle in the xy plane. The // special value z == phi == 65535 encodes a zero normal. int phi, z; if (n[0] == 0 && n[1] == 0 && n[2] == 0) phi = z = 65535; else { float mag_squared=n[0]*n[0]+n[1]*n[1]+n[2]*n[2]; phi = int((atan2(n[0], n[1]) * (1/(2*M_PI)) + 0.5) * 65535 + 0.5); z = std::min(int((n[2]/sqrt(mag_squared)+1)/2 * 65535 + 0.5), 65535); // phi is redundent when z == 65535; avoid the special value. if (phi == 65535 && z == 65535) phi = 0; } write<LITEND>(*output,(unsigned short)phi,(unsigned short)z); // write radius static const float static_r[1]={1.f}; const float* radius=static_r; if(foundRadius) radius=p.data<float>(radiusHandle,pointIndex); write<LITEND>(*output,radius[0]); // write other attributes for(unsigned int i=0;i<specs.size();i++){ const float* data=p.data<float>(attrs[i],pointIndex); for(int k=0;k<attrs[i].count;k++){ write<LITEND>(*output,data[k]); } } } return true; }