#include #include #include #include #define MTS_FILEFORMAT_HEADER 0x041C #define MTS_FILEFORMAT_VERSION_V1 0x01 #define MTS_FILEFORMAT_VERSION_V2 0x02 MTS_NAMESPACE_BEGIN TriMesh::TriMesh(size_t triangleCount, size_t vertexCount) : Shape(Properties()), m_triangleCount(triangleCount), m_vertexCount(vertexCount), m_flipNormals(false) { m_triangles = new Triangle[m_triangleCount]; m_vertexBuffer = new Vertex[m_vertexCount]; } TriMesh::TriMesh(const std::string &name, Transform worldToObject, Triangle *triangles, size_t triangleCount, Vertex *vertexBuffer, size_t vertexCount) : Shape(Properties()), m_triangles(triangles), m_triangleCount(triangleCount), m_vertexBuffer(vertexBuffer), m_vertexCount(vertexCount), m_flipNormals(false) { m_name = name; m_worldToObject = worldToObject; m_objectToWorld.inverse(); } TriMesh::TriMesh(const Properties &props) : Shape(props) { m_flipNormals = props.getBoolean("flipNormals", false); m_triangles = NULL; m_vertexBuffer = NULL; } TriMesh::TriMesh(Stream *stream, InstanceManager *manager) : Shape(stream, manager) { Assert(sizeof(Vertex) == 14*sizeof(Float)); Assert(sizeof(Triangle) == 3*sizeof(int)); m_vertexCount = (size_t) stream->readULong(); m_vertexBuffer = new Vertex[m_vertexCount]; stream->readFloatArray(reinterpret_cast(m_vertexBuffer), m_vertexCount * sizeof(Vertex)/sizeof(Float)); m_triangleCount = (size_t) stream->readULong(); m_triangles = new Triangle[m_triangleCount]; stream->readIntArray(reinterpret_cast(m_triangles), m_triangleCount * sizeof(Triangle)/sizeof(int)); m_flipNormals = false; configure(); } TriMesh::TriMesh(Stream *_stream) : Shape(Properties()) { ref stream = _stream; Assert(sizeof(Vertex) == 14*sizeof(Float)); Assert(sizeof(Triangle) == 3*sizeof(int)); if (stream->getByteOrder() != Stream::ENetworkByteOrder) Log(EError, "Tried to unserialize a shape from a stream, " "which was not previously set to network byte order!"); #if defined(SINGLE_PRECISION) bool doublePrecision = false; #else bool doublePrecision = true; #endif if (stream->readShort() != MTS_FILEFORMAT_HEADER) Log(EError, "Encountered an invalid file format!"); short version = stream->readShort(); if (version != MTS_FILEFORMAT_VERSION_V1 && version != MTS_FILEFORMAT_VERSION_V2) Log(EError, "Encountered an incompatible file version!"); if (version == MTS_FILEFORMAT_VERSION_V2) stream = new ZStream(stream); bool fileDoublePrecision = stream->readBool(); m_vertexCount = (size_t) stream->readULong(); m_vertexBuffer = new Vertex[m_vertexCount]; size_t numEntries = m_vertexCount * sizeof(Vertex)/sizeof(Float); Float *target = reinterpret_cast(m_vertexBuffer); if ((doublePrecision && fileDoublePrecision) || (!doublePrecision && !fileDoublePrecision)) { /* Precision matches - load directly into memory */ stream->readFloatArray(target, numEntries); } else if (fileDoublePrecision) { /* Double -> Single conversion */ double *temp = new double[numEntries]; stream->readDoubleArray(temp, numEntries); for (size_t i=0; i Double conversion */ float *temp = new float[numEntries]; stream->readSingleArray(temp, numEntries); for (size_t i=0; ireadULong(); m_triangles = new Triangle[m_triangleCount]; stream->readIntArray(reinterpret_cast(m_triangles), m_triangleCount * sizeof(Triangle)/sizeof(int)); m_flipNormals = false; configure(); } TriMesh::~TriMesh() { if (m_triangles) delete[] m_triangles; if (m_vertexBuffer) delete[] m_vertexBuffer; } void TriMesh::configure() { Shape::configure(); if (m_areaPDF.isReady()) return; AssertEx(m_triangleCount > 0, "Encountered an empty triangle mesh!"); for (size_t i=0; i 0) { dpdu /= (Float) sharers[i]; dpdv /= (Float) sharers[i]; } } m_vertexBuffer[i].dpdu = dpdu; m_vertexBuffer[i].dpdv = dpdv; } delete[] sharers; } if (complain && (zeroArea > 0 || zeroNormals > 0)) Log(EWarn, "Mesh contains invalid geometry: %i zero area triangles " "and %i zero normals found!", zeroArea, zeroNormals); } void TriMesh::serialize(Stream *stream, InstanceManager *manager) const { Shape::serialize(stream, manager); Assert(sizeof(Vertex) == 14*sizeof(Float)); Assert(sizeof(Triangle) == 3*sizeof(int)); stream->writeULong(m_vertexCount); stream->writeFloatArray(reinterpret_cast(m_vertexBuffer), m_vertexCount * sizeof(Vertex)/sizeof(Float)); stream->writeULong(m_triangleCount); stream->writeIntArray(reinterpret_cast(m_triangles), m_triangleCount * sizeof(Triangle)/sizeof(int)); } void TriMesh::serialize(Stream *_stream) const { ref stream = _stream; Assert(sizeof(Vertex) == 14*sizeof(Float)); Assert(sizeof(Triangle) == 3*sizeof(int)); if (stream->getByteOrder() != Stream::ENetworkByteOrder) Log(EError, "Tried to unserialize a shape from a stream, " "which was not previously set to network byte order!"); #if defined(SINGLE_PRECISION) bool doublePrecision = false; #else bool doublePrecision = true; #endif stream->writeShort(MTS_FILEFORMAT_HEADER); stream->writeShort(MTS_FILEFORMAT_VERSION_V2); stream = new ZStream(stream, Z_BEST_COMPRESSION); stream->writeBool(doublePrecision); stream->writeULong(m_vertexCount); stream->writeFloatArray(reinterpret_cast(m_vertexBuffer), m_vertexCount * sizeof(Vertex)/sizeof(Float)); stream->writeULong(m_triangleCount); stream->writeIntArray(reinterpret_cast(m_triangles), m_triangleCount * sizeof(Triangle)/sizeof(int)); } std::string TriMesh::toString() const { std::ostringstream oss; oss << getClass()->getName() << "[" << endl << " name = \"" << m_name<< "\"," << endl << " triangleCount = " << m_triangleCount << "," << endl << " vertexCount = " << m_vertexCount << "," << endl << " flipNormals = " << m_flipNormals << "," << endl << " surfaceArea = " << m_surfaceArea << "," << endl << " aabb = " << m_aabb.toString() << "," << endl << " bsphere = " << m_bsphere.toString() << "," << endl << " bsdf = " << indent(m_bsdf.toString()) << "," << endl << " subsurface = " << indent(m_subsurface.toString()) << "," << endl << " luminaire = " << indent(m_luminaire.toString()) << endl << "]"; return oss.str(); } MTS_IMPLEMENT_CLASS_S(TriMesh, false, Shape) MTS_NAMESPACE_END