From 4bb5e8c3d61d6cd15ef1637a91e420761efdca58 Mon Sep 17 00:00:00 2001 From: Wenzel Jakob Date: Tue, 28 Sep 2010 19:47:16 +0200 Subject: [PATCH] vertex color and PLY loading support --- SConstruct | 3 + doc/acknowledgements.tex | 1 + doc/compiling.tex | 2 + include/mitsuba/core/triangle.h | 11 + include/mitsuba/render/shape.h | 25 +- src/libhw/glgeometry.cpp | 16 +- src/libhw/glrenderer.cpp | 39 ++- src/libhw/vpl.cpp | 9 + src/librender/kdtree_coherent.cpp | 11 +- src/librender/kdtree_traversal.cpp | 9 + src/librender/preview.cpp | 8 + src/librender/trimesh.cpp | 17 +- src/qtgui/aboutdlg.cpp | 4 + src/qtgui/acknowledgmentdlg.ui | 1 + src/shapes/obj.cpp | 2 +- src/shapes/ply/ply.cpp | 262 ++++++++++++++ src/shapes/ply/ply/byte_order.hpp | 74 ++++ src/shapes/ply/ply/config.hpp | 141 ++++++++ src/shapes/ply/ply/io_operators.hpp | 54 +++ src/shapes/ply/ply/ply.hpp | 53 +++ src/shapes/ply/ply/ply_parser.hpp | 513 ++++++++++++++++++++++++++++ src/shapes/ply/ply_parser.cpp | 455 ++++++++++++++++++++++++ src/textures/vertexcolors.cpp | 102 ++++++ 23 files changed, 1789 insertions(+), 23 deletions(-) create mode 100644 src/shapes/ply/ply.cpp create mode 100644 src/shapes/ply/ply/byte_order.hpp create mode 100644 src/shapes/ply/ply/config.hpp create mode 100644 src/shapes/ply/ply/io_operators.hpp create mode 100644 src/shapes/ply/ply/ply.hpp create mode 100644 src/shapes/ply/ply/ply_parser.hpp create mode 100644 src/shapes/ply/ply_parser.cpp create mode 100644 src/textures/vertexcolors.cpp diff --git a/SConstruct b/SConstruct index c90ec0be..9f38c43d 100644 --- a/SConstruct +++ b/SConstruct @@ -511,6 +511,8 @@ plugins += env.SharedLibrary('plugins/kkay', ['src/phase/kkay.cpp']) # Shapes and triangle mesh loaders plugins += env.SharedLibrary('plugins/obj', ['src/shapes/obj.cpp']) +plugins += env.SharedLibrary('plugins/ply', ['src/shapes/ply/ply.cpp', 'src/shapes/ply/ply_parser.cpp'], + CPPPATH = env['CPPPATH'] + ['src/shapes/ply']) plugins += env.SharedLibrary('plugins/serialized', ['src/shapes/serialized.cpp']) plugins += env.SharedLibrary('plugins/sphere', ['src/shapes/sphere.cpp']) plugins += env.SharedLibrary('plugins/cylinder', ['src/shapes/cylinder.cpp']) @@ -564,6 +566,7 @@ plugins += env.SharedLibrary('plugins/exrtexture', ['src/textures/exrtexture.cpp plugins += env.SharedLibrary('plugins/ldrtexture', ['src/textures/ldrtexture.cpp']) plugins += env.SharedLibrary('plugins/gridtexture', ['src/textures/gridtexture.cpp']) plugins += env.SharedLibrary('plugins/checkerboard', ['src/textures/checkerboard.cpp']) +plugins += env.SharedLibrary('plugins/vertexcolors', ['src/textures/vertexcolors.cpp']) # Light sources plugins += env.SharedLibrary('plugins/area', ['src/luminaires/area.cpp']) diff --git a/doc/acknowledgements.tex b/doc/acknowledgements.tex index 47a550c9..514f279b 100644 --- a/doc/acknowledgements.tex +++ b/doc/acknowledgements.tex @@ -15,6 +15,7 @@ Mitsuba makes heavy use of the following amazing libraries and tools: \item COLLADA DOM by Sony Computer Entertainment \item libjpeg by the Independent JPEG Group \item libpng by Guy Eric Schalnat, Andreas Dilger, Glenn Randers-Pehrson and \mbox{others} +\item libply by Ares Lagae \item BWToolkit by Brandon Walkin \item POSIX Threads for Win32 by Ross Johnson \item The SCons build system by the SCons Foundation diff --git a/doc/compiling.tex b/doc/compiling.tex index f77d18a7..95b57f61 100644 --- a/doc/compiling.tex +++ b/doc/compiling.tex @@ -35,6 +35,8 @@ You may also set adjust certain compilation flags here: \item[\texttt{DOUBLE\_PRECISION}] Do all computation in double precision. Incompatible with \texttt{MTS\_SSE}, \texttt{MTS\_HAS\_COHERENT\_RT}, and \texttt{MTS\_DEBUG\_FP}. \item[\texttt{MTS\_SSE}]Activate optimized SSE routines. +\item[\texttt{MTS\_HAS\_VERTEX\_COLORS}]Compile support for vertex colors. Turned off by +default. \item[\texttt{MTS\_HAS\_COHERENT\_RT}]Include coherent ray tracing support (depends on \texttt{MTS\_SSE}). \item[\texttt{MTS\_DEBUG\_FP}]Generated NaNs will cause floating point exceptions, which can be caught in a debugger. Warning: This is slow! \end{description} diff --git a/include/mitsuba/core/triangle.h b/include/mitsuba/core/triangle.h index a992b728..2313e7da 100644 --- a/include/mitsuba/core/triangle.h +++ b/include/mitsuba/core/triangle.h @@ -34,10 +34,21 @@ struct Vertex { Point2 uv; ///< %Texture coordinates Vector dpdu; ///< Partial derivative of the position with respect to \a u. Vector dpdv; ///< Partial derivative of the position with respect to \a v. +#if defined(MTS_HAS_VERTEX_COLORS) + Float color[3]; +#endif inline bool operator==(const Vertex &vert) const { +#if defined(MTS_HAS_VERTEX_COLORS) + return (p == vert.p && n == vert.n && uv == vert.uv + && dpdu == vert.dpdu && dpdv == vert.dpdv + && color[0] == vert.color[0] + && color[1] == vert.color[1] + && color[2] == vert.color[2]); +#else return (p == vert.p && n == vert.n && uv == vert.uv && dpdu == vert.dpdu && dpdv == vert.dpdv); +#endif } inline bool operator!=(const Vertex &vert) const { diff --git a/include/mitsuba/render/shape.h b/include/mitsuba/render/shape.h index c9815b32..a3c9382b 100644 --- a/include/mitsuba/render/shape.h +++ b/include/mitsuba/render/shape.h @@ -107,37 +107,42 @@ public: /// Computes texture coordinate partials void computePartials(const RayDifferential &ray); - /* Return a string representation */ + /// Return a string representation std::string toString() const; public: - /* Incident direction in the local frame */ + /// Incident direction in the local frame Vector wi; - /* Distance traveled along the ray */ + /// Distance traveled along the ray Float t; /* Intersection point in 3D coordinates */ Point p; - /* Geometry frame */ + /// Geometry frame Frame geoFrame; - /* Shading frame */ + /// Shading frame Frame shFrame; - /* UV surface coordinates */ + /// UV surface coordinates Point2 uv; - /* Position partials wrt. to changes in texture-space */ + /// Position partials wrt. to changes in texture-space Vector dpdu, dpdv; - /* Texture coordinate mapping partials wrt. changes in screen-space */ + /// Texture coordinate mapping partials wrt. changes in screen-space Float dudx, dudy, dvdx, dvdy; - /* Affected shape */ +#if defined(MTS_HAS_VERTEX_COLORS) + /// Interpolated vertex color (if enabled) + Spectrum color; +#endif + + /// Affected shape const Shape *shape; - /* Have texture coordinate partials been computed */ + /// Have texture coordinate partials been computed bool hasUVPartials; }; diff --git a/src/libhw/glgeometry.cpp b/src/libhw/glgeometry.cpp index 048563f3..b642029c 100644 --- a/src/libhw/glgeometry.cpp +++ b/src/libhw/glgeometry.cpp @@ -41,7 +41,14 @@ void GLGeometry::init() { } void GLGeometry::refresh() { Assert(m_vertexID != 0 && m_indexID != 0); - m_vertexSize = m_mesh->getVertexCount() * sizeof(GLfloat) * 11; +#if defined(MTS_HAS_VERTEX_COLORS) + const int floatsPerVertex = 14; +#else + const int floatsPerVertex = 11; +#endif + + m_vertexSize = m_mesh->getVertexCount() * sizeof(GLfloat) * + floatsPerVertex; m_indexSize = m_mesh->getTriangleCount() * sizeof(GLuint) * 3; Log(EDebug, "Uploading a GPU geometry object (\"%s\", " SIZE_T_FMT @@ -51,7 +58,7 @@ void GLGeometry::refresh() { m_mesh->getTriangleCount(), (m_vertexSize + m_indexSize) / 1024.0f); - GLfloat *vertices = new GLfloat[m_mesh->getVertexCount() * 11]; + GLfloat *vertices = new GLfloat[m_mesh->getVertexCount() * floatsPerVertex]; GLuint *indices = (GLuint *) m_mesh->getTriangles(); const Vertex *source = m_mesh->getVertexBuffer(); int pos = 0; @@ -68,6 +75,11 @@ void GLGeometry::refresh() { vertices[pos++] = (float) vtx.dpdu.x; vertices[pos++] = (float) vtx.dpdu.y; vertices[pos++] = (float) vtx.dpdu.z; +#if defined(MTS_HAS_VERTEX_COLORS) + vertices[pos++] = (float) vtx.color[0]; + vertices[pos++] = (float) vtx.color[1]; + vertices[pos++] = (float) vtx.color[2]; +#endif } bind(); diff --git a/src/libhw/glrenderer.cpp b/src/libhw/glrenderer.cpp index b74dac20..680e5e4b 100644 --- a/src/libhw/glrenderer.cpp +++ b/src/libhw/glrenderer.cpp @@ -220,10 +220,17 @@ void GLRenderer::beginDrawingMeshes(bool transmitOnlyPositions) { glEnableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTexture(GL_TEXTURE1); glEnableClientState(GL_TEXTURE_COORD_ARRAY); +#if defined(MTS_HAS_VERTEX_COLORS) + glEnableClientState(GL_COLOR_ARRAY); +#endif } if (m_capabilities->isSupported(RendererCapabilities::EBindless)) { +#if defined(MTS_HAS_VERTEX_COLORS) + const int stride = sizeof(GLfloat) * 14; +#else const int stride = sizeof(GLfloat) * 11; +#endif glEnableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV); glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV); glVertexFormatNV(3, GL_FLOAT, stride); @@ -233,6 +240,7 @@ void GLRenderer::beginDrawingMeshes(bool transmitOnlyPositions) { glTexCoordFormatNV(2, GL_FLOAT, stride); glClientActiveTexture(GL_TEXTURE1); glTexCoordFormatNV(3, GL_FLOAT, stride); + glColorFormatNV(3, GL_FLOAT, stride); } } } @@ -252,11 +260,19 @@ void GLRenderer::drawTriMesh(const TriMesh *mesh) { geometry->m_vertexSize - 6*sizeof(GLfloat)); glBufferAddressRangeNV(GL_TEXTURE_COORD_ARRAY_ADDRESS_NV, 1, geometry->m_vertexAddr+8*sizeof(GLfloat), geometry->m_vertexSize - 8*sizeof(GLfloat)); +#if defined(MTS_HAS_VERTEX_COLORS) + glBufferAddressRangeNV(GL_COLOR_ARRAY_ADDRESS_NV, 0, geometry->m_vertexAddr+11*sizeof(GLfloat), + geometry->m_vertexSize - 11*sizeof(GLfloat)); +#endif } glBufferAddressRangeNV(GL_ELEMENT_ARRAY_ADDRESS_NV, 0, geometry->m_indexAddr, geometry->m_indexSize); } else { +#if defined(MTS_HAS_VERTEX_COLORS) + const int stride = sizeof(GLfloat) * 14; +#else const int stride = sizeof(GLfloat) * 11; +#endif glBindBuffer(GL_ARRAY_BUFFER, geometry->m_vertexID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometry->m_indexID); @@ -273,12 +289,21 @@ void GLRenderer::drawTriMesh(const TriMesh *mesh) { /* Pass 'dpdu' as second set of texture coordinates */ glClientActiveTexture(GL_TEXTURE1); glTexCoordPointer(3, GL_FLOAT, stride, (GLfloat *) 0 + 8); + +#if defined(MTS_HAS_VERTEX_COLORS) + glColorPointer(3, GL_FLOAT, stride, (GLfloat *) 0 + 11); +#endif } } /* Draw all triangles */ glDrawElements(GL_TRIANGLES, (GLsizei) (mesh->getTriangleCount() * 3), GL_UNSIGNED_INT, (GLvoid *) 0); + + if (!m_capabilities->isSupported(RendererCapabilities::EBindless)) { + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } } else { /* Draw the old-fashioned way without VBOs */ const GLchar *vertices = (const GLchar *) mesh->getVertexBuffer(); @@ -290,7 +315,12 @@ void GLRenderer::drawTriMesh(const TriMesh *mesh) { if (!m_transmitOnlyPositions) { glNormalPointer(dataType, sizeof(Vertex), vertices + sizeof(Float) * 3); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + +#if defined(MTS_HAS_VERTEX_COLORS) + glColorPointer(3, GL_FLOAT, sizeof(Vertex), + vertices + sizeof(Float) * 14); +#endif + glClientActiveTexture(GL_TEXTURE0); glTexCoordPointer(2, dataType, sizeof(Vertex), vertices + sizeof(Float) * 6); @@ -309,13 +339,16 @@ void GLRenderer::drawTriMesh(const TriMesh *mesh) { void GLRenderer::endDrawingMeshes() { glDisableClientState(GL_VERTEX_ARRAY); if (!m_transmitOnlyPositions) { +#if defined(MTS_HAS_VERTEX_COLORS) + glDisableClientState(GL_COLOR_ARRAY); +#endif glDisableClientState(GL_NORMAL_ARRAY); glClientActiveTexture(GL_TEXTURE1); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glClientActiveTexture(GL_TEXTURE0); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } - + if (m_capabilities->isSupported(RendererCapabilities::EBindless)) { glDisableClientState(GL_VERTEX_ATTRIB_ARRAY_UNIFIED_NV); glDisableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV); @@ -326,6 +359,8 @@ void GLRenderer::endDrawingMeshes() { } void GLRenderer::drawAll() { + if (true) + return; GLRenderer::beginDrawingMeshes(true); std::map::iterator it; if (m_capabilities->isSupported(RendererCapabilities::EBindless)) { diff --git a/src/libhw/vpl.cpp b/src/libhw/vpl.cpp index 10bc21d4..06c76d07 100644 --- a/src/libhw/vpl.cpp +++ b/src/libhw/vpl.cpp @@ -318,6 +318,9 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf, const Luminai << "uniform vec3 vplPos, camPos;" << endl << "varying vec3 normal, tangent, lightVec, camVec;" << endl << "varying vec2 uv;" << endl +#if defined(MTS_HAS_VERTEX_COLORS) + << "varying vec3 vertexColor;" << endl +#endif << endl << "void main() {" << endl << " normal = gl_Normal;" << endl @@ -326,6 +329,9 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf, const Luminai << " camVec = camPos - gl_Vertex.xyz;" << endl << " lightVec = vplPos - gl_Vertex.xyz;" << endl << " gl_Position = ftransform();" << endl +#if defined(MTS_HAS_VERTEX_COLORS) + << " vertexColor = gl_Color.rgb;" << endl +#endif << "}" << endl; program->setSource(GPUProgram::EVertexProgram, oss.str()); @@ -339,6 +345,9 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf, const Luminai << "uniform float nearClip, invClipRange, minDist;" << endl << "uniform vec2 vplUV;" << endl << "uniform bool diffuseSources, diffuseReceivers;" << endl +#if defined(MTS_HAS_VERTEX_COLORS) + << "varying vec3 vertexColor;" << endl +#endif << endl << "/* Inputs <- Vertex program */" << endl << "varying vec3 normal, tangent, lightVec, camVec;" << endl diff --git a/src/librender/kdtree_coherent.cpp b/src/librender/kdtree_coherent.cpp index 55eb7c34..7f024ff8 100644 --- a/src/librender/kdtree_coherent.cpp +++ b/src/librender/kdtree_coherent.cpp @@ -178,14 +178,21 @@ void KDTree::rayIntersectPacket(const Ray *rays, Intersection *its) const { it.dpdu = v0.dpdu * b.x + v1.dpdu * b.y + v2.dpdu * b.z; it.dpdv = v0.dpdv * b.x + v1.dpdv * b.y + v2.dpdv * b.z; it.shFrame.n = normalize(v0.n * b.x + v1.n * b.y + v2.n * b.z); - - + it.shFrame.s = normalize(it.dpdu - it.shFrame.n * dot(it.shFrame.n, it.dpdu)); it.geoFrame.t = cross(it.shFrame.n, it.shFrame.s); it.wi = it.toLocal(-rayD); it.hasUVPartials = false; it.shape = shape; + +#if defined(MTS_HAS_VERTEX_COLORS) + it.color.fromLinearRGB( + v0.color[0] * b.x + v1.color[0] * b.y + v2.color[0] * b.z, + v0.color[1] * b.x + v1.color[1] * b.y + v2.color[1] * b.z, + v0.color[2] * b.x + v1.color[2] * b.y + v2.color[2] * b.z + ); +#endif } else { /* Non-triangle shape: intersect again to fill in details */ shape->rayIntersect(rays[i], it); diff --git a/src/librender/kdtree_traversal.cpp b/src/librender/kdtree_traversal.cpp index 91bc6d6e..4d7d35f9 100644 --- a/src/librender/kdtree_traversal.cpp +++ b/src/librender/kdtree_traversal.cpp @@ -278,6 +278,7 @@ bool KDTree::rayIntersect(const Ray &ray, Intersection &its) const { its.uv = v0.uv * b.x + v1.uv * b.y + v2.uv * b.z; its.dpdu = v0.dpdu * b.x + v1.dpdu * b.y + v2.dpdu * b.z; its.dpdv = v0.dpdv * b.x + v1.dpdv * b.y + v2.dpdv * b.z; + its.geoFrame.n = faceNormal; its.shape = shape; @@ -288,6 +289,14 @@ bool KDTree::rayIntersect(const Ray &ray, Intersection &its) const { its.shFrame.t = cross(its.shFrame.n, its.shFrame.s); its.wi = its.toLocal(-ray.d); its.hasUVPartials = false; + +#if defined(MTS_HAS_VERTEX_COLORS) + its.color.fromLinearRGB( + v0.color[0] * b.x + v1.color[0] * b.y + v2.color[0] * b.z, + v0.color[1] * b.x + v1.color[1] * b.y + v2.color[1] * b.z, + v0.color[2] * b.x + v1.color[2] * b.y + v2.color[2] * b.z + ); +#endif } else { /* Non-triangle shape: intersect again to fill in details */ if (!shape->rayIntersect(ray, its)) diff --git a/src/librender/preview.cpp b/src/librender/preview.cpp index ff2a79bb..d4084fe1 100644 --- a/src/librender/preview.cpp +++ b/src/librender/preview.cpp @@ -300,6 +300,14 @@ void PreviewWorker::processCoherent(const WorkUnit *workUnit, WorkResult *workRe its.shFrame.n = normalize(v0.n * alpha + v1.n * beta + v2.n * gamma); its.uv = v0.uv * alpha + v1.uv * beta + v2.uv * gamma; +#if defined(MTS_HAS_VERTEX_COLORS) + its.color.fromLinearRGB( + v0.color[0] * alpha + v1.color[0] * beta + v2.color[0] * gamma, + v0.color[1] * alpha + v1.color[1] * beta + v2.color[1] * gamma, + v0.color[2] * alpha + v1.color[2] * beta + v2.color[2] * gamma + ); +#endif + if (EXPECT_NOT_TAKEN(bsdf->getType() != BSDF::EDiffuseReflection || !diffuseVPL)) { its.dpdu = v0.dpdu * alpha + v1.dpdu * beta + v2.dpdu * gamma; its.dpdv = v0.dpdv * alpha + v1.dpdv * beta + v2.dpdv * gamma; diff --git a/src/librender/trimesh.cpp b/src/librender/trimesh.cpp index 7fdea0d9..ea192a95 100644 --- a/src/librender/trimesh.cpp +++ b/src/librender/trimesh.cpp @@ -144,8 +144,10 @@ void TriMesh::configure() { return; AssertEx(m_triangleCount > 0, "Encountered an empty triangle mesh!"); - for (size_t i=0; i 0) + Log(EWarn, "\"%s\": mesh contains invalid geometry: unable " + "to generate %i normals!", m_name.c_str(), invalidNormals); + if (m_flipNormals) { for (unsigned int i=0; i 0 || zeroNormals > 0)) - Log(EWarn, "Mesh contains invalid geometry: %i zero area triangles " - "and %i zero normals found!", zeroArea, zeroNormals); + Log(EWarn, "\"%s\": mesh contains invalid geometry: %i zero area triangles " + "and %i zero normals found!", m_name.c_str(), zeroArea, zeroNormals); } void TriMesh::serialize(Stream *stream, InstanceManager *manager) const { diff --git a/src/qtgui/aboutdlg.cpp b/src/qtgui/aboutdlg.cpp index c3a82acd..a2ebbac5 100644 --- a/src/qtgui/aboutdlg.cpp +++ b/src/qtgui/aboutdlg.cpp @@ -50,6 +50,10 @@ AboutDialog::AboutDialog(QWidget *parent) : configFlags += "MTS_HAS_COHERENT_RT "; #endif +#if defined(MTS_HAS_VERTEX_COLORS) + configFlags += "MTS_HAS_VERTEX_COLORS "; +#endif + #if defined(MTS_HAS_COLLADA) configFlags += "MTS_HAS_COLLADA "; #endif diff --git a/src/qtgui/acknowledgmentdlg.ui b/src/qtgui/acknowledgmentdlg.ui index ed95e6bd..69abbd2b 100644 --- a/src/qtgui/acknowledgmentdlg.ui +++ b/src/qtgui/acknowledgmentdlg.ui @@ -61,6 +61,7 @@ p, li { white-space: pre-wrap; } <li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://glew.sourceforge.net/"><span style=" text-decoration: underline; color:#0000ff;">GLEW</span></a> by Milan Ikits, Marcelo E. Magallon and Lev Povalahev</li> <li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://sourceforge.net/projects/collada-dom/"><span style=" text-decoration: underline; color:#0000ff;">COLLADA DOM</span></a> by Sony Computer Entertainment</li> <li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html"><span style=" text-decoration: underline; color:#0000ff;">Mersenne Twister</span></a> by Makoto Matsumoto and Takuji Nishimura</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://people.cs.kuleuven.be/~ares.lagae/libply/"><span style=" text-decoration: underline; color:#0000ff;">libply</span></a> by Ares Lagae</li> <li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.ijg.org/"><span style=" text-decoration: underline; color:#0000ff;">libjpeg</span></a> by the Independent JPEG Group</li> <li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.libpng.org/pub/png"><span style=" text-decoration: underline; color:#0000ff;">libpng</span></a> by Guy Eric Schalnat, Andreas Dilger, Glenn Randers-Pehrson and others</li> <li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://www.brandonwalkin.com/bwtoolkit/"><span style=" text-decoration: underline; color:#0000ff;">BWToolkit</span></a> by Brandon Walkin</li> diff --git a/src/shapes/obj.cpp b/src/shapes/obj.cpp index b5d23ac0..20755d4c 100644 --- a/src/shapes/obj.cpp +++ b/src/shapes/obj.cpp @@ -309,7 +309,7 @@ public: if (currentMaterial) mesh->addChild("", currentMaterial); m_meshes.push_back(mesh); - SLog(EInfo, "%s: Loaded " SIZE_T_FMT " triangles, " SIZE_T_FMT + Log(EInfo, "%s: Loaded " SIZE_T_FMT " triangles, " SIZE_T_FMT " vertices (merged " SIZE_T_FMT " vertices).", name.c_str(), triangles.size(), vertexBuffer.size(), numMerged); } diff --git a/src/shapes/ply/ply.cpp b/src/shapes/ply/ply.cpp new file mode 100644 index 00000000..bef58d32 --- /dev/null +++ b/src/shapes/ply/ply.cpp @@ -0,0 +1,262 @@ +/* + This file is part of Mitsuba, a physically based rendering system. + + Copyright (c) 2007-2010 by Wenzel Jakob and others. + + Mitsuba is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License Version 3 + as published by the Free Software Foundation. + + Mitsuba is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include +#include +#include +#include + +using namespace std::tr1::placeholders; + +MTS_NAMESPACE_BEGIN + +/** + * PLY mesh loader using libply by Ares Lagae + * (http://people.cs.kuleuven.be/~ares.lagae/libply/) + */ +class PLYLoader : public TriMesh { +public: + PLYLoader(const Properties &props) : TriMesh(props) { + fs::path filePath = Thread::getThread()->getFileResolver()->resolve( + props.getString("filename")); + m_name = filePath.stem(); + /* Load the geometry */ + Log(EInfo, "Loading geometry from \"%s\" ..", filePath.leaf().c_str()); + m_triangleCount = m_vertexCount = 0; + m_vertexCtr = m_triangleCtr = m_triangleIdxCtr = 0; + m_normal = Normal(0.0f); + m_uv = Point2(0.0f); + m_hasNormals = false; + m_hasTexCoords = false; + memset(&m_triangle, 0, sizeof(Triangle)); + loadPLY(filePath); + if (m_triangleCount == 0 || m_vertexCount == 0) + Log(EError, "Unable to load \"%s\" (no triangles or vertices found)!"); + Assert(m_triangleCtr == m_triangleCount); + Assert(m_vertexCtr == m_vertexCount); + + calculateTangentSpaceBasis(m_hasNormals, m_hasTexCoords, true); + } + + PLYLoader(Stream *stream, InstanceManager *manager) : TriMesh(stream, manager) { } + + void loadPLY(const fs::path &path); + + void info_callback(const std::string& filename, std::size_t line_number, + const std::string& message) { + Log(EInfo, "\"%s\" [line %i] info: %s", filename.c_str(), line_number, + message.c_str()); + } + + void warning_callback(const std::string& filename, std::size_t line_number, + const std::string& message) { + Log(EWarn, "\"%s\" [line %i] warning: %s", filename.c_str(), line_number, + message.c_str()); + } + + void error_callback(const std::string& filename, std::size_t line_number, + const std::string& message) { + Log(EError, "\"%s\" [line %i] error: %s", filename.c_str(), line_number, + message.c_str()); + } + + template std::tr1::function + scalar_property_definition_callback(const std::string& element_name, + const std::string& property_name); + + std::tr1::tuple, std::tr1::function > + element_definition_callback(const std::string& element_name, std::size_t count) { + if (element_name == "vertex") { + m_vertexCount = count; + m_vertexBuffer = new Vertex[count]; + return std::tr1::tuple, + std::tr1::function >( + std::tr1::bind(&PLYLoader::vertex_begin_callback, this), + std::tr1::bind(&PLYLoader::vertex_end_callback, this) + ); + } else if (element_name == "face") { + m_triangleCount = count; + m_triangles = new Triangle[m_triangleCount]; + return std::tr1::tuple, + std::tr1::function >( + std::tr1::bind(&PLYLoader::face_begin_callback, this), + std::tr1::bind(&PLYLoader::face_end_callback, this) + ); + } else { + return + std::tr1::tuple, + std::tr1::function >(0, 0); + } + } + + std::tr1::tuple, + std::tr1::function, std::tr1::function > + list_property_definition_callback(const std::string& element_name, + const std::string& property_name) { + if ((element_name == "face") && (property_name == "vertex_indices")) { + return std::tr1::tuple, + std::tr1::function, std::tr1::function >( + std::tr1::bind(&PLYLoader::face_vertex_indices_begin, this, _1), + std::tr1::bind(&PLYLoader::face_vertex_indices_element, this, _1), + std::tr1::bind(&PLYLoader::face_vertex_indices_end, this) + ); + } else { + return std::tr1::tuple, + std::tr1::function, + std::tr1::function >(0, 0, 0); + } + } + + void vertex_begin_callback() { } + void vertex_x_callback(ply::float32 x) { m_position.x = x; } + void vertex_y_callback(ply::float32 y) { m_position.y = y; } + void vertex_z_callback(ply::float32 z) { m_position.z = z; } + void normal_x_callback(ply::float32 x) { m_normal.x = x; } + void normal_y_callback(ply::float32 y) { m_normal.y = y; } + void normal_z_callback(ply::float32 z) { m_normal.z = z; } + void texcoord_u_callback(ply::float32 x) { m_uv.x = x; } + void texcoord_v_callback(ply::float32 y) { m_uv.y = y; } + + void vertex_end_callback() { + m_vertexBuffer[m_vertexCtr].p = m_position; + m_vertexBuffer[m_vertexCtr].n = m_normal; + m_vertexBuffer[m_vertexCtr].uv = m_uv; + m_vertexBuffer[m_vertexCtr].dpdu = Vector(0.0f); + m_vertexBuffer[m_vertexCtr].dpdv = Vector(0.0f); +#if defined(MTS_HAS_VERTEX_COLORS) + m_vertexBuffer[m_vertexCtr].color[0] = m_red; + m_vertexBuffer[m_vertexCtr].color[1] = m_green; + m_vertexBuffer[m_vertexCtr].color[2] = m_blue; +#endif + m_vertexCtr++; + } + + void diffuse_red_callback(ply::uint8 r) { m_red = r / 255.0f; } + void diffuse_green_callback(ply::uint8 g) { m_green = g / 255.0f; } + void diffuse_blue_callback(ply::uint8 b) { m_blue = b / 255.0f; } + + void face_begin_callback() { } + void face_end_callback() { } + + void face_vertex_indices_begin(ply::uint8 size) { + AssertEx(size == 3, "Only triangle PLY meshes are supported for now."); + m_triangleIdxCtr = 0; + } + + void face_vertex_indices_element(ply::int32 element) { + Assert(m_triangleIdxCtr < 3); + Assert((size_t) element < m_vertexCount); + m_triangle.idx[m_triangleIdxCtr++] = element; + } + + void face_vertex_indices_end() { + Assert(m_triangleIdxCtr == 3); + m_triangles[m_triangleCtr++] = m_triangle; + } + + MTS_DECLARE_CLASS() +private: + Point m_position; + Normal m_normal; + Float m_red, m_green, m_blue; + size_t m_vertexCtr, m_triangleCtr, m_triangleIdxCtr; + Triangle m_triangle; + bool m_hasNormals, m_hasTexCoords; + Point2 m_uv; +}; + +template<> std::tr1::function + PLYLoader::scalar_property_definition_callback(const std::string& element_name, + const std::string& property_name) { + if (element_name == "vertex") { + if (property_name == "x") { + return std::tr1::bind(&PLYLoader::vertex_x_callback, this, _1); + } else if (property_name == "y") { + return std::tr1::bind(&PLYLoader::vertex_y_callback, this, _1); + } else if (property_name == "z") { + return std::tr1::bind(&PLYLoader::vertex_z_callback, this, _1); + } else if (property_name == "nx") { + m_hasNormals = true; + return std::tr1::bind(&PLYLoader::normal_x_callback, this, _1); + } else if (property_name == "ny") { + return std::tr1::bind(&PLYLoader::normal_y_callback, this, _1); + } else if (property_name == "nz") { + return std::tr1::bind(&PLYLoader::normal_z_callback, this, _1); + } else if (property_name == "u") { + m_hasTexCoords = true; + return std::tr1::bind(&PLYLoader::texcoord_u_callback, this, _1); + } else if (property_name == "v") { + return std::tr1::bind(&PLYLoader::texcoord_v_callback, this, _1); + } + } + return 0; +} + +template<> std::tr1::function + PLYLoader::scalar_property_definition_callback(const std::string& element_name, + const std::string& property_name) { + if (element_name == "vertex") { + if (property_name == "diffuse_red" || property_name == "red") { + return std::tr1::bind(&PLYLoader::diffuse_red_callback, this, _1); + } else if (property_name == "diffuse_green" || property_name == "green") { + return std::tr1::bind(&PLYLoader::diffuse_green_callback, this, _1); + } else if (property_name == "diffuse_blue" || property_name == "blue") { + return std::tr1::bind(&PLYLoader::diffuse_blue_callback, this, _1); + } + } + return 0; +} + +void PLYLoader::loadPLY(const fs::path &path) { + ply::ply_parser ply_parser; + ply_parser.info_callback(std::tr1::bind(&PLYLoader::info_callback, + this, std::tr1::ref(m_name), _1, _2)); + ply_parser.warning_callback(std::tr1::bind(&PLYLoader::warning_callback, + this, std::tr1::ref(m_name), _1, _2)); + ply_parser.error_callback(std::tr1::bind(&PLYLoader::error_callback, + this, std::tr1::ref(m_name), _1, _2)); + + ply_parser.element_definition_callback(std::tr1::bind(&PLYLoader::element_definition_callback, + this, _1, _2)); + + ply::ply_parser::scalar_property_definition_callbacks_type scalar_property_definition_callbacks; + ply::ply_parser::list_property_definition_callbacks_type list_property_definition_callbacks; + + ply::at(scalar_property_definition_callbacks) = std::tr1::bind( + &PLYLoader::scalar_property_definition_callback, this, _1, _2); + + ply::at(scalar_property_definition_callbacks) = std::tr1::bind( + &PLYLoader::scalar_property_definition_callback, this, _1, _2); + + ply::at(list_property_definition_callbacks) =std::tr1::bind( + &PLYLoader::list_property_definition_callback, this, _1, _2); + + ply_parser.scalar_property_definition_callbacks(scalar_property_definition_callbacks); + ply_parser.list_property_definition_callbacks(list_property_definition_callbacks); + ply_parser.parse(path.file_string()); + + Log(EInfo, "\"%s\": Loaded " SIZE_T_FMT " triangles, " SIZE_T_FMT + " vertices.", m_name.c_str(), m_triangleCount, m_vertexCount); +} + + +MTS_IMPLEMENT_CLASS_S(PLYLoader, false, TriMesh) +MTS_EXPORT_PLUGIN(PLYLoader, "PLY mesh loader"); +MTS_NAMESPACE_END diff --git a/src/shapes/ply/ply/byte_order.hpp b/src/shapes/ply/ply/byte_order.hpp new file mode 100644 index 00000000..cf1bb596 --- /dev/null +++ b/src/shapes/ply/ply/byte_order.hpp @@ -0,0 +1,74 @@ +#ifndef PLY_BYTE_ORDER_HPP_INCLUDED +#define PLY_BYTE_ORDER_HPP_INCLUDED + +namespace ply { + +#if defined(PLY_BIG_ENDIAN) || defined(PLY_LITTLE_ENDIAN) +# error +#endif + +#if (defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) || defined(__ppc__) || defined(_M_PPC) || defined(__ARCH_PPC)) +# define PLY_BIG_ENDIAN +#elif (defined(i386) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || defined(__INTEL__)) \ + || (defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64)) +# define PLY_LITTLE_ENDIAN +#else +# error +#endif + +enum byte_order +{ + little_endian_byte_order = 0, + big_endian_byte_order = 1, +#if defined(PLY_BIG_ENDIAN) + host_byte_order = big_endian_byte_order, +#elif defined(PLY_LITTLE_ENDIAN) + host_byte_order = little_endian_byte_order, +#else +# error +#endif + network_byte_order = big_endian_byte_order +}; + +#undef PLY_BIG_ENDIAN +#undef PLY_LITTLE_ENDIAN + +template +void swap_byte_order(char* bytes); + +template <> +inline void swap_byte_order<1>(char* bytes) +{ +} + +template <> +inline void swap_byte_order<2>(char* bytes) +{ + std::swap(bytes[0], bytes[1]); +} + +template <> +inline void swap_byte_order<4>(char* bytes) +{ + std::swap(bytes[0], bytes[3]); + std::swap(bytes[1], bytes[2]); +} + +template <> +inline void swap_byte_order<8>(char* bytes) +{ + std::swap(bytes[0], bytes[7]); + std::swap(bytes[1], bytes[6]); + std::swap(bytes[2], bytes[5]); + std::swap(bytes[3], bytes[4]); +} + +template +void swap_byte_order(T& value) +{ + swap_byte_order(reinterpret_cast(&value)); +} + +} // namespace ply + +#endif // PLY_BYTE_ORDER_HPP_INCLUDED diff --git a/src/shapes/ply/ply/config.hpp b/src/shapes/ply/ply/config.hpp new file mode 100644 index 00000000..d6a9fad3 --- /dev/null +++ b/src/shapes/ply/ply/config.hpp @@ -0,0 +1,141 @@ +#ifndef _PLY_CONFIG_HPP +#define _PLY_CONFIG_HPP 1 + +/* ply/config.hpp. Generated automatically at end of configure. */ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* define if the Boost library is available */ +#ifndef PLY_HAVE_BOOST +#define PLY_HAVE_BOOST +#endif + +/* Define to 1 if you have the header file. */ +#ifndef PLY_HAVE_DLFCN_H +#define PLY_HAVE_DLFCN_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef PLY_HAVE_INTTYPES_H +#define PLY_HAVE_INTTYPES_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef PLY_HAVE_MEMORY_H +#define PLY_HAVE_MEMORY_H 1 +#endif + +/* Define to 1 if stdbool.h conforms to C99. */ +#ifndef PLY_HAVE_STDBOOL_H +#define PLY_HAVE_STDBOOL_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef PLY_HAVE_STDINT_H +#define PLY_HAVE_STDINT_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef PLY_HAVE_STDLIB_H +#define PLY_HAVE_STDLIB_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef PLY_HAVE_STRINGS_H +#define PLY_HAVE_STRINGS_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef PLY_HAVE_STRING_H +#define PLY_HAVE_STRING_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef PLY_HAVE_SYS_STAT_H +#define PLY_HAVE_SYS_STAT_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef PLY_HAVE_SYS_TYPES_H +#define PLY_HAVE_SYS_TYPES_H 1 +#endif + +/* Define to 1 if you have . */ +#ifndef PLY_HAVE_TR1_CSTDINT +#define PLY_HAVE_TR1_CSTDINT 1 +#endif + +/* Define to 1 if you have . */ +#ifndef PLY_HAVE_TR1_FUNCTIONAL +#define PLY_HAVE_TR1_FUNCTIONAL 1 +#endif + +/* Define to 1 if you have . */ +#ifndef PLY_HAVE_TR1_TUPLE +#define PLY_HAVE_TR1_TUPLE 1 +#endif + +/* Define to 1 if you have . */ +#ifndef PLY_HAVE_TR1_memory +#define PLY_HAVE_TR1_memory 1 +#endif + +/* Define to 1 if you have the header file. */ +#ifndef PLY_HAVE_UNISTD_H +#define PLY_HAVE_UNISTD_H 1 +#endif + +/* Define to 1 if the system has the type `_Bool'. */ +/* #undef HAVE__BOOL */ + +/* Name of package */ +#ifndef PLY_PACKAGE +#define PLY_PACKAGE "ply" +#endif + +/* Author of package */ +#ifndef PLY_PACKAGE_AUTHOR +#define PLY_PACKAGE_AUTHOR "Ares Lagae" +#endif + +/* Define to the address where bug reports for this package should be sent. */ +#ifndef PLY_PACKAGE_BUGREPORT +#define PLY_PACKAGE_BUGREPORT "ares.lagae@cs.kuleuven.be" +#endif + +/* Define to the full name of this package. */ +#ifndef PLY_PACKAGE_NAME +#define PLY_PACKAGE_NAME "ply" +#endif + +/* Define to the full name and version of this package. */ +#ifndef PLY_PACKAGE_STRING +#define PLY_PACKAGE_STRING "ply 0.1" +#endif + +/* Define to the one symbol short name of this package. */ +#ifndef PLY_PACKAGE_TARNAME +#define PLY_PACKAGE_TARNAME "ply" +#endif + +/* Define to the version of this package. */ +#ifndef PLY_PACKAGE_VERSION +#define PLY_PACKAGE_VERSION "0.1" +#endif + +/* Define to 1 if you have the ANSI C header files. */ +/* #undef STDC_HEADERS */ + +/* Version number of package */ +#ifndef PLY_VERSION +#define PLY_VERSION "0.1" +#endif + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* once: _PLY_CONFIG_HPP */ +#endif diff --git a/src/shapes/ply/ply/io_operators.hpp b/src/shapes/ply/ply/io_operators.hpp new file mode 100644 index 00000000..80d788f2 --- /dev/null +++ b/src/shapes/ply/ply/io_operators.hpp @@ -0,0 +1,54 @@ +#ifndef PLY_IO_OPERATORS_HPP_INCLUDED +#define PLY_IO_OPERATORS_HPP_INCLUDED + +#include +#include +#include + +namespace ply { + +namespace io_operators { + +inline std::istream& operator>>(std::istream& istream, int8 &value) +{ + int16 tmp; + if (istream >> tmp) { + if (tmp <= std::numeric_limits::max()) { + value = static_cast(tmp); + } + else { + istream.setstate(std::ios_base::failbit); + } + } + return istream; +} + +inline std::istream& operator>>(std::istream& istream, uint8 &value) +{ + uint16 tmp; + if (istream >> tmp) { + if (tmp <= std::numeric_limits::max()) { + value = static_cast(tmp); + } + else { + istream.setstate(std::ios_base::failbit); + } + } + return istream; +} + +inline std::ostream& operator<<(std::ostream& ostream, int8 value) +{ + return ostream << static_cast(value); +} + +inline std::ostream& operator<<(std::ostream& ostream, uint8 value) +{ + return ostream << static_cast(value); +} + +} // namespace io_operators + +} // namespace ply + +#endif // PLY_IO_OPERATORS_HPP_INCLUDED diff --git a/src/shapes/ply/ply/ply.hpp b/src/shapes/ply/ply/ply.hpp new file mode 100644 index 00000000..065fac3d --- /dev/null +++ b/src/shapes/ply/ply/ply.hpp @@ -0,0 +1,53 @@ +#ifndef PLY_PLY_HPP_INCLUDED +#define PLY_PLY_HPP_INCLUDED + +#include + +namespace ply { + +typedef std::tr1::int8_t int8; +typedef std::tr1::int16_t int16; +typedef std::tr1::int32_t int32; +typedef std::tr1::uint8_t uint8; +typedef std::tr1::uint16_t uint16; +typedef std::tr1::uint32_t uint32; +typedef float float32; +typedef double float64; + +template +struct type_traits; + +#ifdef PLY_TYPE_TRAITS +# error +#endif + +#define PLY_TYPE_TRAITS(TYPE, NAME, OLD_NAME)\ +template <>\ +struct type_traits\ +{\ + typedef TYPE type;\ + static const char* name() { return NAME; }\ + static const char* old_name() { return OLD_NAME; }\ +}; + +PLY_TYPE_TRAITS(int8, "int8", "char") +PLY_TYPE_TRAITS(int16, "int16", "short") +PLY_TYPE_TRAITS(int32, "int32", "int") +PLY_TYPE_TRAITS(uint8, "uint8", "uchar") +PLY_TYPE_TRAITS(uint16, "uint16", "ushort") +PLY_TYPE_TRAITS(uint32, "uint32", "uint") +PLY_TYPE_TRAITS(float32, "float32", "float") +PLY_TYPE_TRAITS(float64, "float64", "double") + +#undef PLY_TYPE_TRAITS + +typedef int format_type; +enum format { + binary_little_endian_format = 0, + binary_big_endian_format = 1, + ascii_format = 2 +}; + +} // namespace ply + +#endif // PLY_PLY_HPP_INCLUDED diff --git a/src/shapes/ply/ply/ply_parser.hpp b/src/shapes/ply/ply/ply_parser.hpp new file mode 100644 index 00000000..26b8a26e --- /dev/null +++ b/src/shapes/ply/ply/ply_parser.hpp @@ -0,0 +1,513 @@ +#ifndef PLY_PLY_PARSER_HPP_INCLUDED +#define PLY_PLY_PARSER_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace ply { + +class ply_parser +{ +public: + + typedef std::tr1::function info_callback_type; + typedef std::tr1::function warning_callback_type; + typedef std::tr1::function error_callback_type; + + typedef std::tr1::function magic_callback_type; + typedef std::tr1::function format_callback_type; + typedef std::tr1::function comment_callback_type; + typedef std::tr1::function obj_info_callback_type; + typedef std::tr1::function end_header_callback_type; + + typedef std::tr1::function begin_element_callback_type; + typedef std::tr1::function end_element_callback_type; + typedef std::tr1::tuple element_callbacks_type; + typedef std::tr1::function element_definition_callback_type; + + template + struct scalar_property_callback_type + { + typedef std::tr1::function type; + }; + + template + struct scalar_property_definition_callback_type + { + typedef typename scalar_property_callback_type::type scalar_property_callback_type; + typedef std::tr1::function type; + }; + + typedef boost::mpl::vector scalar_types; + + class scalar_property_definition_callbacks_type + { + private: + template + struct callbacks_element + { + typedef T scalar_type; + typename scalar_property_definition_callback_type::type callback; + }; + typedef boost::mpl::inherit_linearly< + scalar_types, + boost::mpl::inherit< + boost::mpl::_1, + callbacks_element + > + >::type callbacks; + callbacks callbacks_; + public: + template + const typename scalar_property_definition_callback_type::type& get() const + { + return static_cast&>(callbacks_).callback; + } + template + typename scalar_property_definition_callback_type::type& get() + { + return static_cast&>(callbacks_).callback; + } + template + friend typename scalar_property_definition_callback_type::type& at(scalar_property_definition_callbacks_type& scalar_property_definition_callbacks) + { + return scalar_property_definition_callbacks.get(); + } + template + friend const typename scalar_property_definition_callback_type::type& at(const scalar_property_definition_callbacks_type& scalar_property_definition_callbacks) + { + return scalar_property_definition_callbacks.get(); + } + }; + + template + struct list_property_begin_callback_type + { + typedef std::tr1::function type; + }; + + template + struct list_property_element_callback_type + { + typedef std::tr1::function type; + }; + + template + struct list_property_end_callback_type + { + typedef std::tr1::function type; + }; + + template + struct list_property_definition_callback_type + { + typedef typename list_property_begin_callback_type::type list_property_begin_callback_type; + typedef typename list_property_element_callback_type::type list_property_element_callback_type; + typedef typename list_property_end_callback_type::type list_property_end_callback_type; + typedef std::tr1::function< + std::tr1::tuple< + list_property_begin_callback_type, + list_property_element_callback_type, + list_property_end_callback_type + >(const std::string&, const std::string&)> type; + }; + + typedef boost::mpl::vector size_types; + + class list_property_definition_callbacks_type + { + private: + template struct pair_with : boost::mpl::pair {}; + template + struct sequence_product : + boost::mpl::fold< + Sequence1, + boost::mpl::vector0<>, + boost::mpl::joint_view< + boost::mpl::_1, + boost::mpl::transform< + Sequence2, + pair_with + > + > + > + {}; + template + struct callbacks_element + { + typedef typename T::first size_type; + typedef typename T::second scalar_type; + typename list_property_definition_callback_type::type callback; + }; + typedef boost::mpl::inherit_linearly< + sequence_product::type, + boost::mpl::inherit< + boost::mpl::_1, + callbacks_element + > + >::type callbacks; + callbacks callbacks_; + public: + template + typename list_property_definition_callback_type::type& get() + { + return static_cast >&>(callbacks_).callback; + } + template + const typename list_property_definition_callback_type::type& get() const + { + return static_cast >&>(callbacks_).callback; + } + template + friend typename list_property_definition_callback_type::type& at(list_property_definition_callbacks_type& list_property_definition_callbacks) + { + return list_property_definition_callbacks.get(); + } + template + friend const typename list_property_definition_callback_type::type& at(const list_property_definition_callbacks_type& list_property_definition_callbacks) + { + return list_property_definition_callbacks.get(); + } + }; + + void info_callback(const info_callback_type& info_callback); + void warning_callback(const warning_callback_type& warning_callback); + void error_callback(const error_callback_type& error_callback); + void magic_callback(const magic_callback_type& magic_callback); + void format_callback(const format_callback_type& format_callback); + void element_definition_callback(const element_definition_callback_type& element_definition_callback); + void scalar_property_definition_callbacks(const scalar_property_definition_callbacks_type& scalar_property_definition_callbacks); + void list_property_definition_callbacks(const list_property_definition_callbacks_type& list_property_definition_callbacks); + void comment_callback(const comment_callback_type& comment_callback); + void obj_info_callback(const obj_info_callback_type& obj_info_callback); + void end_header_callback(const end_header_callback_type& end_header_callback); + + typedef int flags_type; + enum flags { }; + + ply_parser(flags_type flags = 0); + bool parse(std::istream& istream); + bool parse(const std::string& filename); + +private: + + struct property + { + property(const std::string& name) : name(name) {} + virtual ~property() {} + virtual bool parse(class ply_parser& ply_parser, format_type format, std::istream& istream) = 0; + std::string name; + }; + + template + struct scalar_property : public property + { + typedef ScalarType scalar_type; + typedef typename scalar_property_callback_type::type callback_type; + scalar_property(const std::string& name, callback_type callback) : property(name), callback(callback) {} + bool parse(class ply_parser& ply_parser, format_type format, std::istream& istream) { return ply_parser.parse_scalar_property(format, istream, callback); } + callback_type callback; + }; + + template + struct list_property : public property + { + typedef SizeType size_type; + typedef ScalarType scalar_type; + typedef typename list_property_begin_callback_type::type begin_callback_type; + typedef typename list_property_element_callback_type::type element_callback_type; + typedef typename list_property_end_callback_type::type end_callback_type; + list_property(const std::string& name, begin_callback_type begin_callback, element_callback_type element_callback, end_callback_type end_callback) : property(name), begin_callback(begin_callback), element_callback(element_callback), end_callback(end_callback) {} + bool parse(class ply_parser& ply_parser, format_type format, std::istream& istream) { return ply_parser.parse_list_property(format, istream, begin_callback, element_callback, end_callback); } + begin_callback_type begin_callback; + element_callback_type element_callback; + end_callback_type end_callback; + }; + + struct element + { + element(const std::string& name, std::size_t count, const begin_element_callback_type& begin_element_callback, const end_element_callback_type& end_element_callback) : name(name), count(count), begin_element_callback(begin_element_callback), end_element_callback(end_element_callback) {} + std::string name; + std::size_t count; + begin_element_callback_type begin_element_callback; + end_element_callback_type end_element_callback; + std::vector > properties; + }; + + flags_type flags_; + + info_callback_type info_callback_; + warning_callback_type warning_callback_; + error_callback_type error_callback_; + + magic_callback_type magic_callback_; + format_callback_type format_callback_; + element_definition_callback_type element_definition_callbacks_; + scalar_property_definition_callbacks_type scalar_property_definition_callbacks_; + list_property_definition_callbacks_type list_property_definition_callbacks_; + comment_callback_type comment_callback_; + obj_info_callback_type obj_info_callback_; + end_header_callback_type end_header_callback_; + + template void parse_scalar_property_definition(const std::string& property_name); + template void parse_list_property_definition(const std::string& property_name); + + template bool parse_scalar_property(format_type format, std::istream& istream, const typename scalar_property_callback_type::type& scalar_property_callback); + template bool parse_list_property(format_type format, std::istream& istream, const typename list_property_begin_callback_type::type& list_property_begin_callback, const typename list_property_element_callback_type::type& list_property_element_callback, const typename list_property_end_callback_type::type& list_property_end_callback); + + std::size_t line_number_; + element* current_element_; +}; + +} // namespace ply + +inline ply::ply_parser::ply_parser(flags_type flags) + : flags_(flags) +{ +} + +inline bool ply::ply_parser::parse(const std::string& filename) +{ + std::ifstream ifstream(filename.c_str()); + return parse(ifstream); +} + +inline void ply::ply_parser::info_callback(const info_callback_type& info_callback) +{ + info_callback_ = info_callback; +} + +inline void ply::ply_parser::warning_callback(const warning_callback_type& warning_callback) +{ + warning_callback_ = warning_callback; +} + +inline void ply::ply_parser::error_callback(const error_callback_type& error_callback) +{ + error_callback_ = error_callback; +} + +inline void ply::ply_parser::magic_callback(const magic_callback_type& magic_callback) +{ + magic_callback_ = magic_callback; +} + +inline void ply::ply_parser::format_callback(const format_callback_type& format_callback) +{ + format_callback_ = format_callback; +} + +inline void ply::ply_parser::element_definition_callback(const element_definition_callback_type& element_definition_callback) +{ + element_definition_callbacks_ = element_definition_callback; +} + +inline void ply::ply_parser::scalar_property_definition_callbacks(const scalar_property_definition_callbacks_type& scalar_property_definition_callbacks) +{ + scalar_property_definition_callbacks_ = scalar_property_definition_callbacks; +} + +inline void ply::ply_parser::list_property_definition_callbacks(const list_property_definition_callbacks_type& list_property_definition_callbacks) +{ + list_property_definition_callbacks_ = list_property_definition_callbacks; +} + +inline void ply::ply_parser::comment_callback(const comment_callback_type& comment_callback) +{ + comment_callback_ = comment_callback; +} + +inline void ply::ply_parser::obj_info_callback(const obj_info_callback_type& obj_info_callback) +{ + obj_info_callback_ = obj_info_callback; +} + +inline void ply::ply_parser::end_header_callback(const end_header_callback_type& end_header_callback) +{ + end_header_callback_ = end_header_callback; +} + +template +inline void ply::ply_parser::parse_scalar_property_definition(const std::string& property_name) +{ + typedef ScalarType scalar_type; + typename scalar_property_definition_callback_type::type& scalar_property_definition_callback = scalar_property_definition_callbacks_.get(); + typename scalar_property_callback_type::type scalar_property_callback; + if (scalar_property_definition_callback) { + scalar_property_callback = scalar_property_definition_callback(current_element_->name, property_name); + } + if (!scalar_property_callback) { + if (warning_callback_) { + warning_callback_(line_number_, "property ‘" + std::string(type_traits::name()) + " " + property_name + "’ of element ‘" + current_element_->name + "’ is not handled"); + } + } + current_element_->properties.push_back(std::tr1::shared_ptr(new scalar_property(property_name, scalar_property_callback))); +} + +template +inline void ply::ply_parser::parse_list_property_definition(const std::string& property_name) +{ + typedef SizeType size_type; + typedef ScalarType scalar_type; + typename list_property_definition_callback_type::type& list_property_definition_callback = list_property_definition_callbacks_.get(); + typedef typename list_property_begin_callback_type::type list_property_begin_callback_type; + typedef typename list_property_element_callback_type::type list_property_element_callback_type; + typedef typename list_property_end_callback_type::type list_property_end_callback_type; + std::tr1::tuple list_property_callbacks; + if (list_property_definition_callback) { + list_property_callbacks = list_property_definition_callback(current_element_->name, property_name); + } + if (!std::tr1::get<0>(list_property_callbacks) || !std::tr1::get<1>(list_property_callbacks) || !std::tr1::get<2>(list_property_callbacks)) { + if (warning_callback_) { + warning_callback_(line_number_, "property ‘list " + std::string(type_traits::name()) + " " + std::string(type_traits::name()) + " " + property_name + "’ of element ‘" + current_element_->name + "’ is not handled"); + } + } + current_element_->properties.push_back(std::tr1::shared_ptr(new list_property(property_name, std::tr1::get<0>(list_property_callbacks), std::tr1::get<1>(list_property_callbacks), std::tr1::get<2>(list_property_callbacks)))); +} + +template +inline bool ply::ply_parser::parse_scalar_property(format_type format, std::istream& istream, const typename scalar_property_callback_type::type& scalar_property_callback) +{ + using namespace io_operators; + typedef ScalarType scalar_type; + if (format == ascii_format) { + scalar_type value = 0; + char space = ' '; + istream >> value; + if (!istream.eof()) { + istream >> space >> std::ws; + } + if (!istream || !std::isspace(space)) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if (scalar_property_callback) { + scalar_property_callback(value); + } + return true; + } + else { + scalar_type value = 0; + istream.read(reinterpret_cast(&value), sizeof(scalar_type)); + if (!istream) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if ((format == binary_big_endian_format && host_byte_order == little_endian_byte_order) + || (format == binary_little_endian_format && host_byte_order == big_endian_byte_order)) { + swap_byte_order(value); + } + if (scalar_property_callback) { + scalar_property_callback(value); + } + return true; + } +} + +template +inline bool ply::ply_parser::parse_list_property(format_type format, std::istream& istream, const typename list_property_begin_callback_type::type& list_property_begin_callback, const typename list_property_element_callback_type::type& list_property_element_callback, const typename list_property_end_callback_type::type& list_property_end_callback) +{ + using namespace io_operators; + typedef SizeType size_type; + typedef ScalarType scalar_type; + if (format == ascii_format) { + size_type size = 0; + char space = ' '; + istream >> size; + if (!istream.eof()) { + istream >> space >> std::ws; + } + if (!istream || !std::isspace(space)) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if (list_property_begin_callback) { + list_property_begin_callback(size); + } + for (std::size_t index = 0; index < size; ++index) { + scalar_type value = 0; + char space = ' '; + istream >> value; + if (!istream.eof()) { + istream >> space >> std::ws; + } + if (!istream || !std::isspace(space)) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if (list_property_element_callback) { + list_property_element_callback(value); + } + } + if (list_property_end_callback) { + list_property_end_callback(); + } + return true; + } + else { + size_type size = 0; + istream.read(reinterpret_cast(&size), sizeof(size_type)); + if ((format == binary_big_endian_format && host_byte_order == little_endian_byte_order) + || ((format == binary_little_endian_format && host_byte_order == big_endian_byte_order))) { + swap_byte_order(size); + } + if (!istream) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if (list_property_begin_callback) { + list_property_begin_callback(size); + } + for (std::size_t index = 0; index < size; ++index) { + scalar_type value; + istream.read(reinterpret_cast(&value), sizeof(scalar_type)); + if (!istream) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if ((format == binary_big_endian_format && host_byte_order == little_endian_byte_order) + || (format == binary_little_endian_format && host_byte_order == big_endian_byte_order)) { + swap_byte_order(value); + } + if (list_property_element_callback) { + list_property_element_callback(value); + } + } + if (list_property_end_callback) { + list_property_end_callback(); + } + return true; + } +} + +#endif // PLY_PLY_PARSER_HPP_INCLUDED diff --git a/src/shapes/ply/ply_parser.cpp b/src/shapes/ply/ply_parser.cpp new file mode 100644 index 00000000..3af6e7bb --- /dev/null +++ b/src/shapes/ply/ply_parser.cpp @@ -0,0 +1,455 @@ +#include + +bool ply::ply_parser::parse(std::istream& istream) +{ + std::string line; + line_number_ = 0; + + std::size_t number_of_format_statements = 0, number_of_element_statements = 0, number_of_property_statements = 0, number_of_obj_info_statements = 0, number_of_comment_statements = 0; + + format_type format = ascii_format; + std::vector< std::tr1::shared_ptr > elements; + + // magic + char magic[3]; + istream.read(magic, 3); + istream.ignore(1); + ++line_number_; + if (!istream) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if ((magic[0] != 'p') || (magic[1] != 'l') || (magic[2] != 'y')){ + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if (magic_callback_) { + magic_callback_(); + } + + while (std::getline(istream, line)) { + ++line_number_; + std::istringstream stringstream(line); + stringstream.unsetf(std::ios_base::skipws); + + stringstream >> std::ws; + if (stringstream.eof()) { + if (warning_callback_) { + warning_callback_(line_number_, "ignoring line ‘" + line + "’"); + } + } + else { + std::string keyword; + stringstream >> keyword; + + // format + if (keyword == "format") { + std::string format_string, version; + char space_format_format_string, space_format_string_version; + stringstream >> space_format_format_string >> std::ws >> format_string >> space_format_string_version >> std::ws >> version >> std::ws; + if (!stringstream || !stringstream.eof() || !std::isspace(space_format_format_string) || !std::isspace(space_format_string_version)) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if (format_string == "ascii") { + format = ascii_format; + } + else if (format_string == "binary_big_endian") { + format = binary_big_endian_format; + } + else if (format_string == "binary_little_endian") { + format = binary_little_endian_format; + } + else { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if (version != "1.0") { + if (error_callback_) { + error_callback_(line_number_, "version ‘" + version + "’ is not supported"); + } + return false; + } + if (number_of_format_statements > 0) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + ++number_of_format_statements; + if (format_callback_) { + format_callback_(format, version); + } + } + + // element + else if (keyword == "element") { + std::string name; + std::size_t count; + char space_element_name, space_name_count; + stringstream >> space_element_name >> std::ws >> name >> space_name_count >> std::ws >> count >> std::ws; + if (!stringstream || !stringstream.eof() || !std::isspace(space_element_name) || !std::isspace(space_name_count)) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + std::vector< std::tr1::shared_ptr >::const_iterator iterator; + for (iterator = elements.begin(); iterator != elements.end(); ++iterator) { + const struct element& element = *(iterator->get()); + if (element.name == name) { + break; + } + } + if (iterator != elements.end()) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + ++number_of_element_statements; + element_callbacks_type element_callbacks; + if (element_definition_callbacks_) { + element_callbacks = element_definition_callbacks_(name, count); + } + std::tr1::shared_ptr element_ptr(new element(name, count, std::tr1::get<0>(element_callbacks), std::tr1::get<1>(element_callbacks))); + elements.push_back(std::tr1::shared_ptr(element_ptr)); + current_element_ = element_ptr.get(); + } + + // property + else if (keyword == "property") { + std::string type_or_list; + char space_property_type_or_list; + stringstream >> space_property_type_or_list >> std::ws >> type_or_list; + if (!stringstream || !std::isspace(space_property_type_or_list)) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if (type_or_list != "list") { + std::string name; + std::string& type = type_or_list; + char space_type_name; + stringstream >> space_type_name >> std::ws >> name >> std::ws; + if (!stringstream || !std::isspace(space_type_name)) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if (number_of_element_statements == 0) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + std::vector< std::tr1::shared_ptr >::const_iterator iterator; + for (iterator = current_element_->properties.begin(); iterator != current_element_->properties.end(); ++iterator) { + const struct property& property = *(iterator->get()); + if (property.name == name) { + break; + } + } + if (iterator != current_element_->properties.end()) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if ((type == type_traits::name()) || (type == type_traits::old_name())) { + parse_scalar_property_definition(name); + } + else if ((type == type_traits::name()) || (type == type_traits::old_name())) { + parse_scalar_property_definition(name); + } + else if ((type == type_traits::name()) || (type == type_traits::old_name())) { + parse_scalar_property_definition(name); + } + else if ((type == type_traits::name()) || (type == type_traits::old_name())) { + parse_scalar_property_definition(name); + } + else if ((type == type_traits::name()) || (type == type_traits::old_name())) { + parse_scalar_property_definition(name); + } + else if ((type == type_traits::name()) || (type == type_traits::old_name())) { + parse_scalar_property_definition(name); + } + else if ((type == type_traits::name()) || (type == type_traits::old_name())) { + parse_scalar_property_definition(name); + } + else if ((type == type_traits::name()) || (type == type_traits::old_name())) { + parse_scalar_property_definition(name); + } + else { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + ++number_of_property_statements; + } + else { + std::string name; + std::string size_type_string, scalar_type_string; + char space_list_size_type, space_size_type_scalar_type, space_scalar_type_name; + stringstream >> space_list_size_type >> std::ws >> size_type_string >> space_size_type_scalar_type >> std::ws >> scalar_type_string >> space_scalar_type_name >> std::ws >> name >> std::ws; + if (!stringstream || !std::isspace(space_list_size_type) || !std::isspace(space_size_type_scalar_type) || !std::isspace(space_scalar_type_name)) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if (number_of_element_statements == 0) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + std::vector< std::tr1::shared_ptr >::const_iterator iterator; + for (iterator = current_element_->properties.begin(); iterator != current_element_->properties.end(); ++iterator) { + const struct property& property = *(iterator->get()); + if (property.name == name) { + break; + } + } + if (iterator != current_element_->properties.end()) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if ((size_type_string == type_traits::name()) || (size_type_string == type_traits::old_name())) { + typedef uint8 size_type; + if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + } + else if ((size_type_string == type_traits::name()) || (size_type_string == type_traits::old_name())) { + typedef uint16 size_type; + if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + } + else if ((size_type_string == type_traits::name()) || (size_type_string == type_traits::old_name())) { + typedef uint32 size_type; + if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else if ((scalar_type_string == type_traits::name()) || (scalar_type_string == type_traits::old_name())) { + parse_list_property_definition(name); + } + else { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + } + else { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + ++number_of_property_statements; + } + } + + // comment + else if (keyword == "comment") { + if (comment_callback_) { + comment_callback_(line); + } + ++number_of_comment_statements; + } + + // obj_info + else if (keyword == "obj_info") { + if (obj_info_callback_) { + obj_info_callback_(line); + } + ++number_of_obj_info_statements; + } + + // end_header + else if (keyword == "end_header") { + if (end_header_callback_) { + if (end_header_callback_() == false) { + return true; + } + } + break; + } + + // unknown keyword + else { + if (warning_callback_) { + warning_callback_(line_number_, "ignoring line ‘" + line + "’"); + } + } + + } + } + + if (number_of_format_statements == 0) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + + // ascii + if (format == ascii_format) { + for (std::vector< std::tr1::shared_ptr >::const_iterator element_iterator = elements.begin(); element_iterator != elements.end(); ++element_iterator) { + class element& element = *(element_iterator->get()); + for (std::size_t element_index = 0; element_index < element.count; ++element_index) { + if (element.begin_element_callback) { + element.begin_element_callback(); + } + if (!std::getline(istream, line)) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + ++line_number_; + std::istringstream stringstream(line); + stringstream.unsetf(std::ios_base::skipws); + stringstream >> std::ws; + for (std::vector< std::tr1::shared_ptr >::const_iterator property_iterator = element.properties.begin(); property_iterator != element.properties.end(); ++property_iterator) { + class property& property = *(property_iterator->get()); + if (property.parse(*this, format, stringstream) == false) { + return false; + } + } + if (!stringstream.eof()) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + if (element.end_element_callback) { + element.end_element_callback(); + } + } + } + istream >> std::ws; + if (istream.fail() || !istream.eof() || istream.bad()) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + return true; + } + + // binary + else { + for (std::vector< std::tr1::shared_ptr >::const_iterator element_iterator = elements.begin(); element_iterator != elements.end(); ++element_iterator) { + class element& element = *(element_iterator->get()); + for (std::size_t element_index = 0; element_index < element.count; ++element_index) { + if (element.begin_element_callback) { + element.begin_element_callback(); + } + for (std::vector< std::tr1::shared_ptr >::const_iterator property_iterator = element.properties.begin(); property_iterator != element.properties.end(); ++property_iterator) { + class property& property = *(property_iterator->get()); + if (property.parse(*this, format, istream) == false) { + return false; + } + } + if (element.end_element_callback) { + element.end_element_callback(); + } + } + } + if (istream.fail() || (istream.rdbuf()->sgetc() != std::char_traits::eof()) || istream.bad()) { + if (error_callback_) { + error_callback_(line_number_, "parse error"); + } + return false; + } + return true; + } +} diff --git a/src/textures/vertexcolors.cpp b/src/textures/vertexcolors.cpp new file mode 100644 index 00000000..4dbcceeb --- /dev/null +++ b/src/textures/vertexcolors.cpp @@ -0,0 +1,102 @@ +/* + This file is part of Mitsuba, a physically based rendering system. + + Copyright (c) 2007-2010 by Wenzel Jakob and others. + + Mitsuba is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License Version 3 + as published by the Free Software Foundation. + + Mitsuba is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include +#include + +MTS_NAMESPACE_BEGIN + +/** + * Vertex colors passthrough texture + */ +class VertexColors : public Texture { +public: + VertexColors(const Properties &props) : Texture(props) { + } + + VertexColors(Stream *stream, InstanceManager *manager) + : Texture(stream, manager) { + } + + void serialize(Stream *stream, InstanceManager *manager) const { + } + + Spectrum getValue(const Intersection &its) const { +#if defined(MTS_HAS_VERTEX_COLORS) + return its.color; +#else + Log(EError, "Vertex colors are not active -- recompile Mitsuba " + "with -DMTS_HAS_VERTEX_COLORS"); + return Spectrum(0.0f); +#endif + } + + bool usesRayDifferentials() const { + return false; + } + + Spectrum getAverage() const { + return Spectrum(1.0f); + } + + Spectrum getMaximum() const { + return Spectrum(1.0f); + } + + std::string toString() const { + return "VertexColors[]"; + } + + Shader *createShader(Renderer *renderer) const; + + MTS_DECLARE_CLASS() +protected: + Spectrum m_reflectance; +}; + +// ================ Hardware shader implementation ================ + +class VertexColorShader : public Shader { +public: + VertexColorShader(Renderer *renderer) : Shader(renderer, ETextureShader) { + } + + void generateCode(std::ostringstream &oss, + const std::string &evalName, + const std::vector &depNames) const { + oss << "vec3 " << evalName << "(vec2 uv) {" << endl + << " return vertexColor;" << endl + << "}" << endl; + } + + MTS_DECLARE_CLASS() +private: + Spectrum m_brightReflectance; + Spectrum m_darkReflectance; + Float m_width; +}; + +Shader *VertexColors::createShader(Renderer *renderer) const { + return new VertexColorShader(renderer); +} + +MTS_IMPLEMENT_CLASS(VertexColorShader, false, Shader) +MTS_IMPLEMENT_CLASS_S(VertexColors, false, Texture) +MTS_EXPORT_PLUGIN(VertexColors, "VertexColors texture"); +MTS_NAMESPACE_END