vertex color and PLY loading support
parent
7539f12bee
commit
4bb5e8c3d6
|
@ -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'])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<const TriMesh *, GPUGeometry *>::iterator it;
|
||||
if (m_capabilities->isSupported(RendererCapabilities::EBindless)) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -144,8 +144,10 @@ void TriMesh::configure() {
|
|||
return;
|
||||
|
||||
AssertEx(m_triangleCount > 0, "Encountered an empty triangle mesh!");
|
||||
for (size_t i=0; i<m_triangleCount; i++)
|
||||
|
||||
for (size_t i=0; i<m_triangleCount; i++)
|
||||
m_areaPDF.put(m_triangles[i].surfaceArea(m_vertexBuffer));
|
||||
|
||||
m_surfaceArea = m_areaPDF.build();
|
||||
m_invSurfaceArea = 1.0f / m_surfaceArea;
|
||||
/* Generate a bounding sphere */
|
||||
|
@ -166,7 +168,7 @@ Float TriMesh::sampleArea(ShapeSamplingRecord &sRec, const Point2 &sample) const
|
|||
|
||||
void TriMesh::calculateTangentSpaceBasis(bool hasNormals, bool hasTexCoords, bool complain) {
|
||||
/* Calculate smooth normals if there aren't any */
|
||||
int zeroArea = 0, zeroNormals = 0;
|
||||
int zeroArea = 0, zeroNormals = 0, invalidNormals = 0;
|
||||
|
||||
if (!hasNormals) {
|
||||
for (unsigned int i=0; i<m_vertexCount; i++)
|
||||
|
@ -192,13 +194,16 @@ void TriMesh::calculateTangentSpaceBasis(bool hasNormals, bool hasTexCoords, boo
|
|||
m_vertexBuffer[i].n /= length;
|
||||
} else {
|
||||
/* Choose some bogus value */
|
||||
if (complain)
|
||||
Log(EWarn, "Could not generate correct mesh normals!");
|
||||
invalidNormals++;
|
||||
m_vertexBuffer[i].n = Normal(1, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (complain && invalidNormals > 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<m_vertexCount; i++)
|
||||
m_vertexBuffer[i].n *= -1;
|
||||
|
@ -314,8 +319,8 @@ void TriMesh::calculateTangentSpaceBasis(bool hasNormals, bool hasTexCoords, boo
|
|||
}
|
||||
|
||||
if (complain && (zeroArea > 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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <mitsuba/render/trimesh.h>
|
||||
#include <mitsuba/core/fresolver.h>
|
||||
#include <mitsuba/core/properties.h>
|
||||
#include <mitsuba/core/fstream.h>
|
||||
#include <ply/ply_parser.hpp>
|
||||
#include <tr1/functional>
|
||||
|
||||
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<typename ValueType> std::tr1::function <void (ValueType)>
|
||||
scalar_property_definition_callback(const std::string& element_name,
|
||||
const std::string& property_name);
|
||||
|
||||
std::tr1::tuple<std::tr1::function<void()>, std::tr1::function<void()> >
|
||||
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<void()>,
|
||||
std::tr1::function<void()> >(
|
||||
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<void()>,
|
||||
std::tr1::function<void()> >(
|
||||
std::tr1::bind(&PLYLoader::face_begin_callback, this),
|
||||
std::tr1::bind(&PLYLoader::face_end_callback, this)
|
||||
);
|
||||
} else {
|
||||
return
|
||||
std::tr1::tuple<std::tr1::function<void()>,
|
||||
std::tr1::function<void()> >(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
std::tr1::tuple<std::tr1::function<void (ply::uint8)>,
|
||||
std::tr1::function<void (ply::int32)>, std::tr1::function<void ()> >
|
||||
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<void (ply::uint8)>,
|
||||
std::tr1::function<void (ply::int32)>, std::tr1::function<void ()> >(
|
||||
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<void (ply::uint8)>,
|
||||
std::tr1::function<void (ply::int32)>,
|
||||
std::tr1::function<void ()> >(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 <void (ply::float32)>
|
||||
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 <void (ply::uint8)>
|
||||
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<ply::float32>(scalar_property_definition_callbacks) = std::tr1::bind(
|
||||
&PLYLoader::scalar_property_definition_callback<ply::float32>, this, _1, _2);
|
||||
|
||||
ply::at<ply::uint8>(scalar_property_definition_callbacks) = std::tr1::bind(
|
||||
&PLYLoader::scalar_property_definition_callback<ply::uint8>, this, _1, _2);
|
||||
|
||||
ply::at<ply::uint8, ply::int32>(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
|
|
@ -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 <std::size_t N>
|
||||
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 <typename T>
|
||||
void swap_byte_order(T& value)
|
||||
{
|
||||
swap_byte_order<sizeof(T)>(reinterpret_cast<char*>(&value));
|
||||
}
|
||||
|
||||
} // namespace ply
|
||||
|
||||
#endif // PLY_BYTE_ORDER_HPP_INCLUDED
|
|
@ -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 <dlfcn.h> header file. */
|
||||
#ifndef PLY_HAVE_DLFCN_H
|
||||
#define PLY_HAVE_DLFCN_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#ifndef PLY_HAVE_INTTYPES_H
|
||||
#define PLY_HAVE_INTTYPES_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <memory.h> 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 <stdint.h> header file. */
|
||||
#ifndef PLY_HAVE_STDINT_H
|
||||
#define PLY_HAVE_STDINT_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#ifndef PLY_HAVE_STDLIB_H
|
||||
#define PLY_HAVE_STDLIB_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#ifndef PLY_HAVE_STRINGS_H
|
||||
#define PLY_HAVE_STRINGS_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#ifndef PLY_HAVE_STRING_H
|
||||
#define PLY_HAVE_STRING_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#ifndef PLY_HAVE_SYS_STAT_H
|
||||
#define PLY_HAVE_SYS_STAT_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#ifndef PLY_HAVE_SYS_TYPES_H
|
||||
#define PLY_HAVE_SYS_TYPES_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have <tr1/cstdint>. */
|
||||
#ifndef PLY_HAVE_TR1_CSTDINT
|
||||
#define PLY_HAVE_TR1_CSTDINT 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have <tr1/functional>. */
|
||||
#ifndef PLY_HAVE_TR1_FUNCTIONAL
|
||||
#define PLY_HAVE_TR1_FUNCTIONAL 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have <tr1/tuple>. */
|
||||
#ifndef PLY_HAVE_TR1_TUPLE
|
||||
#define PLY_HAVE_TR1_TUPLE 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have <tr1/memory>. */
|
||||
#ifndef PLY_HAVE_TR1_memory
|
||||
#define PLY_HAVE_TR1_memory 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> 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 <sys/types.h> does not define. */
|
||||
/* #undef size_t */
|
||||
|
||||
/* once: _PLY_CONFIG_HPP */
|
||||
#endif
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef PLY_IO_OPERATORS_HPP_INCLUDED
|
||||
#define PLY_IO_OPERATORS_HPP_INCLUDED
|
||||
|
||||
#include <istream>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
|
||||
namespace ply {
|
||||
|
||||
namespace io_operators {
|
||||
|
||||
inline std::istream& operator>>(std::istream& istream, int8 &value)
|
||||
{
|
||||
int16 tmp;
|
||||
if (istream >> tmp) {
|
||||
if (tmp <= std::numeric_limits<int8>::max()) {
|
||||
value = static_cast<int8>(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<uint8>::max()) {
|
||||
value = static_cast<uint8>(tmp);
|
||||
}
|
||||
else {
|
||||
istream.setstate(std::ios_base::failbit);
|
||||
}
|
||||
}
|
||||
return istream;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& ostream, int8 value)
|
||||
{
|
||||
return ostream << static_cast<int16>(value);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& ostream, uint8 value)
|
||||
{
|
||||
return ostream << static_cast<uint16>(value);
|
||||
}
|
||||
|
||||
} // namespace io_operators
|
||||
|
||||
} // namespace ply
|
||||
|
||||
#endif // PLY_IO_OPERATORS_HPP_INCLUDED
|
|
@ -0,0 +1,53 @@
|
|||
#ifndef PLY_PLY_HPP_INCLUDED
|
||||
#define PLY_PLY_HPP_INCLUDED
|
||||
|
||||
#include <tr1/cstdint>
|
||||
|
||||
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 <typename ScalarType>
|
||||
struct type_traits;
|
||||
|
||||
#ifdef PLY_TYPE_TRAITS
|
||||
# error
|
||||
#endif
|
||||
|
||||
#define PLY_TYPE_TRAITS(TYPE, NAME, OLD_NAME)\
|
||||
template <>\
|
||||
struct type_traits<TYPE>\
|
||||
{\
|
||||
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
|
|
@ -0,0 +1,513 @@
|
|||
#ifndef PLY_PLY_PARSER_HPP_INCLUDED
|
||||
#define PLY_PLY_PARSER_HPP_INCLUDED
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <tr1/functional>
|
||||
#include <tr1/memory>
|
||||
|
||||
#include <boost/mpl/fold.hpp>
|
||||
#include <boost/mpl/inherit.hpp>
|
||||
#include <boost/mpl/inherit_linearly.hpp>
|
||||
#include <boost/mpl/joint_view.hpp>
|
||||
#include <boost/mpl/transform.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
|
||||
#include <ply/ply.hpp>
|
||||
#include <ply/byte_order.hpp>
|
||||
#include <ply/io_operators.hpp>
|
||||
|
||||
namespace ply {
|
||||
|
||||
class ply_parser
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::tr1::function<void (std::size_t, const std::string&)> info_callback_type;
|
||||
typedef std::tr1::function<void (std::size_t, const std::string&)> warning_callback_type;
|
||||
typedef std::tr1::function<void (std::size_t, const std::string&)> error_callback_type;
|
||||
|
||||
typedef std::tr1::function<void ()> magic_callback_type;
|
||||
typedef std::tr1::function<void (format_type, const std::string&)> format_callback_type;
|
||||
typedef std::tr1::function<void (const std::string&)> comment_callback_type;
|
||||
typedef std::tr1::function<void (const std::string&)> obj_info_callback_type;
|
||||
typedef std::tr1::function<bool ()> end_header_callback_type;
|
||||
|
||||
typedef std::tr1::function<void()> begin_element_callback_type;
|
||||
typedef std::tr1::function<void()> end_element_callback_type;
|
||||
typedef std::tr1::tuple<begin_element_callback_type, end_element_callback_type> element_callbacks_type;
|
||||
typedef std::tr1::function<element_callbacks_type (const std::string&, std::size_t)> element_definition_callback_type;
|
||||
|
||||
template <typename ScalarType>
|
||||
struct scalar_property_callback_type
|
||||
{
|
||||
typedef std::tr1::function<void (ScalarType)> type;
|
||||
};
|
||||
|
||||
template <typename ScalarType>
|
||||
struct scalar_property_definition_callback_type
|
||||
{
|
||||
typedef typename scalar_property_callback_type<ScalarType>::type scalar_property_callback_type;
|
||||
typedef std::tr1::function<scalar_property_callback_type (const std::string&, const std::string&)> type;
|
||||
};
|
||||
|
||||
typedef boost::mpl::vector<int8, int16, int32, uint8, uint16, uint32, float32, float64> scalar_types;
|
||||
|
||||
class scalar_property_definition_callbacks_type
|
||||
{
|
||||
private:
|
||||
template <typename T>
|
||||
struct callbacks_element
|
||||
{
|
||||
typedef T scalar_type;
|
||||
typename scalar_property_definition_callback_type<scalar_type>::type callback;
|
||||
};
|
||||
typedef boost::mpl::inherit_linearly<
|
||||
scalar_types,
|
||||
boost::mpl::inherit<
|
||||
boost::mpl::_1,
|
||||
callbacks_element<boost::mpl::_2>
|
||||
>
|
||||
>::type callbacks;
|
||||
callbacks callbacks_;
|
||||
public:
|
||||
template <typename ScalarType>
|
||||
const typename scalar_property_definition_callback_type<ScalarType>::type& get() const
|
||||
{
|
||||
return static_cast<const callbacks_element<ScalarType>&>(callbacks_).callback;
|
||||
}
|
||||
template <typename ScalarType>
|
||||
typename scalar_property_definition_callback_type<ScalarType>::type& get()
|
||||
{
|
||||
return static_cast<callbacks_element<ScalarType>&>(callbacks_).callback;
|
||||
}
|
||||
template <typename ScalarType>
|
||||
friend typename scalar_property_definition_callback_type<ScalarType>::type& at(scalar_property_definition_callbacks_type& scalar_property_definition_callbacks)
|
||||
{
|
||||
return scalar_property_definition_callbacks.get<ScalarType>();
|
||||
}
|
||||
template <typename ScalarType>
|
||||
friend const typename scalar_property_definition_callback_type<ScalarType>::type& at(const scalar_property_definition_callbacks_type& scalar_property_definition_callbacks)
|
||||
{
|
||||
return scalar_property_definition_callbacks.get<ScalarType>();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename SizeType, typename ScalarType>
|
||||
struct list_property_begin_callback_type
|
||||
{
|
||||
typedef std::tr1::function<void (SizeType)> type;
|
||||
};
|
||||
|
||||
template <typename SizeType, typename ScalarType>
|
||||
struct list_property_element_callback_type
|
||||
{
|
||||
typedef std::tr1::function<void (ScalarType)> type;
|
||||
};
|
||||
|
||||
template <typename SizeType, typename ScalarType>
|
||||
struct list_property_end_callback_type
|
||||
{
|
||||
typedef std::tr1::function<void ()> type;
|
||||
};
|
||||
|
||||
template <typename SizeType, typename ScalarType>
|
||||
struct list_property_definition_callback_type
|
||||
{
|
||||
typedef typename list_property_begin_callback_type<SizeType, ScalarType>::type list_property_begin_callback_type;
|
||||
typedef typename list_property_element_callback_type<SizeType, ScalarType>::type list_property_element_callback_type;
|
||||
typedef typename list_property_end_callback_type<SizeType, ScalarType>::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<uint8, uint16, uint32> size_types;
|
||||
|
||||
class list_property_definition_callbacks_type
|
||||
{
|
||||
private:
|
||||
template <typename T> struct pair_with : boost::mpl::pair<T,boost::mpl::_> {};
|
||||
template<typename Sequence1, typename Sequence2>
|
||||
struct sequence_product :
|
||||
boost::mpl::fold<
|
||||
Sequence1,
|
||||
boost::mpl::vector0<>,
|
||||
boost::mpl::joint_view<
|
||||
boost::mpl::_1,
|
||||
boost::mpl::transform<
|
||||
Sequence2,
|
||||
pair_with<boost::mpl::_2>
|
||||
>
|
||||
>
|
||||
>
|
||||
{};
|
||||
template <typename T>
|
||||
struct callbacks_element
|
||||
{
|
||||
typedef typename T::first size_type;
|
||||
typedef typename T::second scalar_type;
|
||||
typename list_property_definition_callback_type<size_type, scalar_type>::type callback;
|
||||
};
|
||||
typedef boost::mpl::inherit_linearly<
|
||||
sequence_product<size_types, scalar_types>::type,
|
||||
boost::mpl::inherit<
|
||||
boost::mpl::_1,
|
||||
callbacks_element<boost::mpl::_2>
|
||||
>
|
||||
>::type callbacks;
|
||||
callbacks callbacks_;
|
||||
public:
|
||||
template <typename SizeType, typename ScalarType>
|
||||
typename list_property_definition_callback_type<SizeType, ScalarType>::type& get()
|
||||
{
|
||||
return static_cast<callbacks_element<boost::mpl::pair<SizeType, ScalarType> >&>(callbacks_).callback;
|
||||
}
|
||||
template <typename SizeType, typename ScalarType>
|
||||
const typename list_property_definition_callback_type<SizeType, ScalarType>::type& get() const
|
||||
{
|
||||
return static_cast<const callbacks_element<boost::mpl::pair<SizeType, ScalarType> >&>(callbacks_).callback;
|
||||
}
|
||||
template <typename SizeType, typename ScalarType>
|
||||
friend typename list_property_definition_callback_type<SizeType, ScalarType>::type& at(list_property_definition_callbacks_type& list_property_definition_callbacks)
|
||||
{
|
||||
return list_property_definition_callbacks.get<SizeType, ScalarType>();
|
||||
}
|
||||
template <typename SizeType, typename ScalarType>
|
||||
friend const typename list_property_definition_callback_type<SizeType, ScalarType>::type& at(const list_property_definition_callbacks_type& list_property_definition_callbacks)
|
||||
{
|
||||
return list_property_definition_callbacks.get<SizeType, ScalarType>();
|
||||
}
|
||||
};
|
||||
|
||||
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 <typename ScalarType>
|
||||
struct scalar_property : public property
|
||||
{
|
||||
typedef ScalarType scalar_type;
|
||||
typedef typename scalar_property_callback_type<scalar_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<scalar_type>(format, istream, callback); }
|
||||
callback_type callback;
|
||||
};
|
||||
|
||||
template <typename SizeType, typename ScalarType>
|
||||
struct list_property : public property
|
||||
{
|
||||
typedef SizeType size_type;
|
||||
typedef ScalarType scalar_type;
|
||||
typedef typename list_property_begin_callback_type<size_type, scalar_type>::type begin_callback_type;
|
||||
typedef typename list_property_element_callback_type<size_type, scalar_type>::type element_callback_type;
|
||||
typedef typename list_property_end_callback_type<size_type, scalar_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<size_type, scalar_type>(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<std::tr1::shared_ptr<property> > 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 <typename ScalarType> void parse_scalar_property_definition(const std::string& property_name);
|
||||
template <typename SizeType, typename ScalarType> void parse_list_property_definition(const std::string& property_name);
|
||||
|
||||
template <typename ScalarType> bool parse_scalar_property(format_type format, std::istream& istream, const typename scalar_property_callback_type<ScalarType>::type& scalar_property_callback);
|
||||
template <typename SizeType, typename ScalarType> bool parse_list_property(format_type format, std::istream& istream, const typename list_property_begin_callback_type<SizeType, ScalarType>::type& list_property_begin_callback, const typename list_property_element_callback_type<SizeType, ScalarType>::type& list_property_element_callback, const typename list_property_end_callback_type<SizeType, ScalarType>::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 <typename ScalarType>
|
||||
inline void ply::ply_parser::parse_scalar_property_definition(const std::string& property_name)
|
||||
{
|
||||
typedef ScalarType scalar_type;
|
||||
typename scalar_property_definition_callback_type<scalar_type>::type& scalar_property_definition_callback = scalar_property_definition_callbacks_.get<scalar_type>();
|
||||
typename scalar_property_callback_type<scalar_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<scalar_type>::name()) + " " + property_name + "’ of element ‘" + current_element_->name + "’ is not handled");
|
||||
}
|
||||
}
|
||||
current_element_->properties.push_back(std::tr1::shared_ptr<property>(new scalar_property<scalar_type>(property_name, scalar_property_callback)));
|
||||
}
|
||||
|
||||
template <typename SizeType, typename ScalarType>
|
||||
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<size_type, scalar_type>::type& list_property_definition_callback = list_property_definition_callbacks_.get<size_type, scalar_type>();
|
||||
typedef typename list_property_begin_callback_type<size_type, scalar_type>::type list_property_begin_callback_type;
|
||||
typedef typename list_property_element_callback_type<size_type, scalar_type>::type list_property_element_callback_type;
|
||||
typedef typename list_property_end_callback_type<size_type, scalar_type>::type list_property_end_callback_type;
|
||||
std::tr1::tuple<list_property_begin_callback_type, list_property_element_callback_type, list_property_end_callback_type> 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<size_type>::name()) + " " + std::string(type_traits<scalar_type>::name()) + " " + property_name + "’ of element ‘" + current_element_->name + "’ is not handled");
|
||||
}
|
||||
}
|
||||
current_element_->properties.push_back(std::tr1::shared_ptr<property>(new list_property<size_type, scalar_type>(property_name, std::tr1::get<0>(list_property_callbacks), std::tr1::get<1>(list_property_callbacks), std::tr1::get<2>(list_property_callbacks))));
|
||||
}
|
||||
|
||||
template <typename ScalarType>
|
||||
inline bool ply::ply_parser::parse_scalar_property(format_type format, std::istream& istream, const typename scalar_property_callback_type<ScalarType>::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<char*>(&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 <typename SizeType, typename ScalarType>
|
||||
inline bool ply::ply_parser::parse_list_property(format_type format, std::istream& istream, const typename list_property_begin_callback_type<SizeType, ScalarType>::type& list_property_begin_callback, const typename list_property_element_callback_type<SizeType, ScalarType>::type& list_property_element_callback, const typename list_property_end_callback_type<SizeType, ScalarType>::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<char*>(&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<char*>(&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
|
|
@ -0,0 +1,455 @@
|
|||
#include <ply/ply_parser.hpp>
|
||||
|
||||
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<element> > 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<element> >::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> 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>(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<property> >::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<int8>::name()) || (type == type_traits<int8>::old_name())) {
|
||||
parse_scalar_property_definition<int8>(name);
|
||||
}
|
||||
else if ((type == type_traits<int16>::name()) || (type == type_traits<int16>::old_name())) {
|
||||
parse_scalar_property_definition<int16>(name);
|
||||
}
|
||||
else if ((type == type_traits<int32>::name()) || (type == type_traits<int32>::old_name())) {
|
||||
parse_scalar_property_definition<int32>(name);
|
||||
}
|
||||
else if ((type == type_traits<uint8>::name()) || (type == type_traits<uint8>::old_name())) {
|
||||
parse_scalar_property_definition<uint8>(name);
|
||||
}
|
||||
else if ((type == type_traits<uint16>::name()) || (type == type_traits<uint16>::old_name())) {
|
||||
parse_scalar_property_definition<uint16>(name);
|
||||
}
|
||||
else if ((type == type_traits<uint32>::name()) || (type == type_traits<uint32>::old_name())) {
|
||||
parse_scalar_property_definition<uint32>(name);
|
||||
}
|
||||
else if ((type == type_traits<float32>::name()) || (type == type_traits<float32>::old_name())) {
|
||||
parse_scalar_property_definition<float32>(name);
|
||||
}
|
||||
else if ((type == type_traits<float64>::name()) || (type == type_traits<float64>::old_name())) {
|
||||
parse_scalar_property_definition<float64>(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<property> >::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<uint8>::name()) || (size_type_string == type_traits<uint8>::old_name())) {
|
||||
typedef uint8 size_type;
|
||||
if ((scalar_type_string == type_traits<int8>::name()) || (scalar_type_string == type_traits<int8>::old_name())) {
|
||||
parse_list_property_definition<size_type, int8>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<int16>::name()) || (scalar_type_string == type_traits<int16>::old_name())) {
|
||||
parse_list_property_definition<size_type, int16>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<int32>::name()) || (scalar_type_string == type_traits<int32>::old_name())) {
|
||||
parse_list_property_definition<size_type, int32>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<uint8>::name()) || (scalar_type_string == type_traits<uint8>::old_name())) {
|
||||
parse_list_property_definition<size_type, uint8>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<uint16>::name()) || (scalar_type_string == type_traits<uint16>::old_name())) {
|
||||
parse_list_property_definition<size_type, uint16>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<uint32>::name()) || (scalar_type_string == type_traits<uint32>::old_name())) {
|
||||
parse_list_property_definition<size_type, uint32>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<float32>::name()) || (scalar_type_string == type_traits<float32>::old_name())) {
|
||||
parse_list_property_definition<size_type, float32>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<float64>::name()) || (scalar_type_string == type_traits<float64>::old_name())) {
|
||||
parse_list_property_definition<size_type, float64>(name);
|
||||
}
|
||||
else {
|
||||
if (error_callback_) {
|
||||
error_callback_(line_number_, "parse error");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ((size_type_string == type_traits<uint16>::name()) || (size_type_string == type_traits<uint16>::old_name())) {
|
||||
typedef uint16 size_type;
|
||||
if ((scalar_type_string == type_traits<int8>::name()) || (scalar_type_string == type_traits<int8>::old_name())) {
|
||||
parse_list_property_definition<size_type, int8>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<int16>::name()) || (scalar_type_string == type_traits<int16>::old_name())) {
|
||||
parse_list_property_definition<size_type, int16>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<int32>::name()) || (scalar_type_string == type_traits<int32>::old_name())) {
|
||||
parse_list_property_definition<size_type, int32>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<uint8>::name()) || (scalar_type_string == type_traits<uint8>::old_name())) {
|
||||
parse_list_property_definition<size_type, uint8>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<uint16>::name()) || (scalar_type_string == type_traits<uint16>::old_name())) {
|
||||
parse_list_property_definition<size_type, uint16>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<uint32>::name()) || (scalar_type_string == type_traits<uint32>::old_name())) {
|
||||
parse_list_property_definition<size_type, uint32>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<float32>::name()) || (scalar_type_string == type_traits<float32>::old_name())) {
|
||||
parse_list_property_definition<size_type, float32>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<float64>::name()) || (scalar_type_string == type_traits<float64>::old_name())) {
|
||||
parse_list_property_definition<size_type, float64>(name);
|
||||
}
|
||||
else {
|
||||
if (error_callback_) {
|
||||
error_callback_(line_number_, "parse error");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ((size_type_string == type_traits<uint32>::name()) || (size_type_string == type_traits<uint32>::old_name())) {
|
||||
typedef uint32 size_type;
|
||||
if ((scalar_type_string == type_traits<int8>::name()) || (scalar_type_string == type_traits<int8>::old_name())) {
|
||||
parse_list_property_definition<size_type, int8>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<int16>::name()) || (scalar_type_string == type_traits<int16>::old_name())) {
|
||||
parse_list_property_definition<size_type, int16>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<int32>::name()) || (scalar_type_string == type_traits<int32>::old_name())) {
|
||||
parse_list_property_definition<size_type, int32>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<uint8>::name()) || (scalar_type_string == type_traits<uint8>::old_name())) {
|
||||
parse_list_property_definition<size_type, uint8>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<uint16>::name()) || (scalar_type_string == type_traits<uint16>::old_name())) {
|
||||
parse_list_property_definition<size_type, uint16>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<uint32>::name()) || (scalar_type_string == type_traits<uint32>::old_name())) {
|
||||
parse_list_property_definition<size_type, uint32>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<float32>::name()) || (scalar_type_string == type_traits<float32>::old_name())) {
|
||||
parse_list_property_definition<size_type, float32>(name);
|
||||
}
|
||||
else if ((scalar_type_string == type_traits<float64>::name()) || (scalar_type_string == type_traits<float64>::old_name())) {
|
||||
parse_list_property_definition<size_type, float64>(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<element> >::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<property> >::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<element> >::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<property> >::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<char>::eof()) || istream.bad()) {
|
||||
if (error_callback_) {
|
||||
error_callback_(line_number_, "parse error");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <mitsuba/render/texture.h>
|
||||
#include <mitsuba/render/shape.h>
|
||||
#include <mitsuba/core/properties.h>
|
||||
|
||||
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<std::string> &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
|
Loading…
Reference in New Issue