diff --git a/CMakeLists.txt b/CMakeLists.txt index 6691be4a..ae1cdeb0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,7 @@ IF(ENABLE_EXAMPLES AND QT_QTOPENGL_FOUND) ADD_SUBDIRECTORY(examples/Paging) ADD_SUBDIRECTORY(examples/OpenGL) ADD_SUBDIRECTORY(examples/SmoothLOD) + ADD_SUBDIRECTORY(examples/DecodeOnGPU) ADD_SUBDIRECTORY(examples/Python) SET(BUILD_EXAMPLES ON) ELSE() diff --git a/examples/Basic/CMakeLists.txt b/examples/Basic/CMakeLists.txt index 02e203d2..c34dc96c 100644 --- a/examples/Basic/CMakeLists.txt +++ b/examples/Basic/CMakeLists.txt @@ -26,7 +26,7 @@ PROJECT(BasicExample) #Projects source files SET(SRC_FILES main.cpp - OpenGLWidget.cpp + ../common/OpenGLWidget.cpp ) #Projects headers files @@ -36,19 +36,20 @@ SET(INC_FILES add_definitions(-DGLEW_STATIC) -#"Sources" and "Headers" are the group names in Visual Studio. -#They may have other uses too... -SOURCE_GROUP("Sources" FILES ${SRC_FILES}) -SOURCE_GROUP("Headers" FILES ${INC_FILES}) - FIND_PACKAGE(OpenGL REQUIRED) #Tell CMake the paths for OpenGL and for PolyVox (which is just relative to our current location) INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_BINARY_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include ${GLEW_SOURCE_DIR}) LINK_DIRECTORIES(${PolyVoxCore_BINARY_DIR}) +#This will include the shader files inside the compiled binary +QT4_ADD_RESOURCES(COMMON_RESOURCES_RCC ../common/example.qrc) + +# Put the resources in a seperate folder in Visual Studio +SOURCE_GROUP("Resource Files" FILES ../common/example.qrc ${COMMON_RESOURCES_RCC}) + #Build -ADD_EXECUTABLE(BasicExample ${SRC_FILES}) +ADD_EXECUTABLE(BasicExample ${SRC_FILES} ${COMMON_RESOURCES_RCC}) IF(MSVC) SET_TARGET_PROPERTIES(BasicExample PROPERTIES COMPILE_FLAGS "/W4 /wd4127") ENDIF(MSVC) diff --git a/examples/Basic/OpenGLWidget.cpp b/examples/Basic/OpenGLWidget.cpp deleted file mode 100644 index a3f6ad96..00000000 --- a/examples/Basic/OpenGLWidget.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include "OpenGLWidget.h" - -#include -#include -//#include - -using namespace PolyVox; -using namespace std; - -OpenGLWidget::OpenGLWidget(QWidget *parent) - :QGLWidget(parent) - ,m_xRotation(0) - ,m_yRotation(0) -{ -} - -void OpenGLWidget::setSurfaceMeshToRender(const PolyVox::SurfaceMesh >& surfaceMesh) -{ - //Convienient access to the vertices and indices - const auto& vecIndices = surfaceMesh.getIndices(); - const auto& vecVertices = surfaceMesh.getVertices(); - - //Create the VAO for the mesh - glGenVertexArrays(1, &vertexArrayObject); - glBindVertexArray(vertexArrayObject); - - //The GL_ARRAY_BUFFER will contain the list of vertex positions - glGenBuffers(1, &vertexBuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); - glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(CubicVertex), vecVertices.data(), GL_STATIC_DRAW); - - //and GL_ELEMENT_ARRAY_BUFFER will contain the indices - glGenBuffers(1, &indexBuffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), vecIndices.data(), GL_STATIC_DRAW); - - //We need to tell OpenGL how to understand the format of the vertex data - glEnableVertexAttribArray(0); //We're talking about shader attribute '0' - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(CubicVertex), 0); //take the first 3 floats from every sizeof(decltype(vecVertices)::value_type) - - glBindVertexArray(0); - - noOfIndices = vecIndices.size(); //Save this for the call to glDrawElements later -} - -void OpenGLWidget::initializeGL() -{ - GLenum err = glewInit(); - if (GLEW_OK != err) - { - /* Problem: glewInit failed, something is seriously wrong. */ - std::cout << "GLEW Error: " << glewGetErrorString(err) << std::endl; - } - - //Print out some information about the OpenGL implementation. - std::cout << "OpenGL Implementation Details:" << std::endl; - if(glGetString(GL_VENDOR)) - std::cout << "\tGL_VENDOR: " << glGetString(GL_VENDOR) << std::endl; - if(glGetString(GL_RENDERER)) - std::cout << "\tGL_RENDERER: " << glGetString(GL_RENDERER) << std::endl; - if(glGetString(GL_VERSION)) - std::cout << "\tGL_VERSION: " << glGetString(GL_VERSION) << std::endl; - if(glGetString(GL_SHADING_LANGUAGE_VERSION)) - std::cout << "\tGL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; - - //Set up the clear colour - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClearDepth(1.0f); - - glEnable(GL_CULL_FACE); - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); - glDepthFunc(GL_LEQUAL); - glDepthRange(0.0, 1.0); - - if (!shader.addShaderFromSourceCode(QGLShader::Vertex, R"( - #version 140 - - in vec4 position; //This will be the position of the vertex in model-space - - uniform mat4 cameraToClipMatrix; - uniform mat4 worldToCameraMatrix; - uniform mat4 modelToWorldMatrix; - - out vec4 worldPosition; //This is being passed to the fragment shader to calculate the normals - - void main() - { - worldPosition = modelToWorldMatrix * position; - vec4 cameraPosition = worldToCameraMatrix * worldPosition; - gl_Position = cameraToClipMatrix * cameraPosition; - } - )")) - { - std::cerr << shader.log().toStdString() << std::endl; - exit(EXIT_FAILURE); - } - - if (!shader.addShaderFromSourceCode(QGLShader::Fragment, R"( - #version 130 - - in vec4 worldPosition; //Passed in from the vertex shader - - out vec4 outputColor; - - void main() - { - vec3 normal = normalize(cross(dFdy(worldPosition.xyz), dFdx(worldPosition.xyz))); - - float color = clamp(abs(dot(normalize(normal.xyz), vec3(0.9,0.1,0.5))), 0, 1); - outputColor = vec4(1.0, 0.5, color, 1.0); - } - )")) - { - std::cerr << shader.log().toStdString() << std::endl; - exit(EXIT_FAILURE); - } - - shader.bindAttributeLocation("position", 0); - - if(!shader.link()) - { - std::cerr << shader.log().toStdString() << std::endl; - exit(EXIT_FAILURE); - } - - shader.bind(); - - QMatrix4x4 worldToCameraMatrix{}; - worldToCameraMatrix.translate(0, 0, -50); //Move the camera back by 50 units - - shader.setUniformValue("worldToCameraMatrix", worldToCameraMatrix); - - shader.release(); -} - -void OpenGLWidget::resizeGL(int w, int h) -{ - //Setup the viewport - glViewport(0, 0, w, h); - - auto aspectRatio = w / (float)h; - float zNear = 1.0; - float zFar = 1000.0; - - QMatrix4x4 cameraToClipMatrix{}; - cameraToClipMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar); - - shader.bind(); - shader.setUniformValue("cameraToClipMatrix", cameraToClipMatrix); - shader.release(); -} - -void OpenGLWidget::paintGL() -{ - //Clear the screen - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - QMatrix4x4 modelToWorldMatrix{}; - modelToWorldMatrix.rotate(m_xRotation, 0, 1, 0); //rotate around y-axis - modelToWorldMatrix.rotate(m_yRotation, 1, 0, 0); //rotate around x-axis - modelToWorldMatrix.translate(-32, -32, -32); //centre the model on the origin - - shader.bind(); - - shader.setUniformValue("modelToWorldMatrix", modelToWorldMatrix); //Update to the latest camera matrix - - glBindVertexArray(vertexArrayObject); - - glDrawElements(GL_TRIANGLES, noOfIndices, GL_UNSIGNED_INT, 0); - - glBindVertexArray(0); - - shader.release(); - - GLenum errCode = glGetError(); - if(errCode != GL_NO_ERROR) - { - std::cerr << "OpenGL Error: " << errCode << std::endl; - } -} - -void OpenGLWidget::mousePressEvent(QMouseEvent* event) -{ - m_CurrentMousePos = event->pos(); - m_LastFrameMousePos = m_CurrentMousePos; - - update(); -} - -void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) -{ - m_CurrentMousePos = event->pos(); - QPoint diff = m_CurrentMousePos - m_LastFrameMousePos; - m_xRotation += diff.x(); - m_yRotation += diff.y(); - m_LastFrameMousePos = m_CurrentMousePos; - - update(); -} diff --git a/examples/Basic/OpenGLWidget.h b/examples/Basic/OpenGLWidget.h deleted file mode 100644 index a7cac3ca..00000000 --- a/examples/Basic/OpenGLWidget.h +++ /dev/null @@ -1,69 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not -claim that you wrote the original software. If you use this software -in a product, an acknowledgment in the product documentation would be -appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and must not be -misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*******************************************************************************/ - -#ifndef __BasicExample_OpenGLWidget_H__ -#define __BasicExample_OpenGLWidget_H__ - -#include "PolyVoxCore/SurfaceMesh.h" - -#include "glew/glew.h" - -#include -#include - -class OpenGLWidget : public QGLWidget -{ -public: - //Constructor - OpenGLWidget(QWidget *parent); - - //Mouse handling - void mouseMoveEvent(QMouseEvent* event); - void mousePressEvent(QMouseEvent* event); - - //Convert a SurfaceMesh to OpenGL index/vertex buffers - void setSurfaceMeshToRender(const PolyVox::SurfaceMesh >& surfaceMesh); - -protected: - //Qt OpenGL functions - void initializeGL(); - void resizeGL(int w, int h); - void paintGL(); - -private: - //Index/vertex buffer data - GLuint noOfIndices; - GLuint indexBuffer; - GLuint vertexBuffer; - GLuint vertexArrayObject; - - QGLShaderProgram shader; - - //Mouse data - QPoint m_LastFrameMousePos; - QPoint m_CurrentMousePos; - int m_xRotation; - int m_yRotation; -}; - -#endif //__BasicExample_OpenGLWidget_H__ diff --git a/examples/Basic/main.cpp b/examples/Basic/main.cpp index 09dc5423..a13da717 100644 --- a/examples/Basic/main.cpp +++ b/examples/Basic/main.cpp @@ -25,7 +25,7 @@ freely, subject to the following restrictions: #include "PolyVoxCore/CubicSurfaceExtractor.h" #include "PolyVoxCore/MarchingCubesSurfaceExtractor.h" -#include "PolyVoxCore/SurfaceMesh.h" +#include "PolyVoxCore/Mesh.h" #include "PolyVoxCore/SimpleVolume.h" #include @@ -77,12 +77,18 @@ int main(int argc, char *argv[]) SimpleVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(63, 63, 63))); createSphereInVolume(volData, 30); - // Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see. - auto mesh = extractCubicSurface(&volData, volData.getEnclosingRegion()); - //auto mesh = extractMarchingCubesSurface(&volData, volData.getEnclosingRegion()); + // Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see. + auto mesh = extractCubicMesh(&volData, volData.getEnclosingRegion()); + //auto mesh = extractMarchingCubesMesh(&volData, volData.getEnclosingRegion()); + + // The surface extractor outputs the mesh in an efficient compressed format which is not directly suitable for rendering. The easiest approach is to + // decode this on the CPU as shown below, though more advanced applications can upload the compressed mesh to the GPU and decompress in shader code. + auto decodedMesh = decode(mesh); //Pass the surface to the OpenGL window - openGLWidget.setSurfaceMeshToRender(mesh); + openGLWidget.addMesh(decodedMesh); + //openGLWidget.addMesh(mesh2); + openGLWidget.setViewableRegion(volData.getEnclosingRegion()); //Run the message pump. return app.exec(); diff --git a/examples/DecodeOnGPU/CMakeLists.txt b/examples/DecodeOnGPU/CMakeLists.txt new file mode 100644 index 00000000..07f87101 --- /dev/null +++ b/examples/DecodeOnGPU/CMakeLists.txt @@ -0,0 +1,75 @@ +# Copyright (c) 2010-2012 David Williams +# +# This software is provided 'as-is', without any express or implied +# warranty. In no event will the authors be held liable for any damages +# arising from the use of this software. +# +# Permission is granted to anyone to use this software for any purpose, +# including commercial applications, and to alter it and redistribute it +# freely, subject to the following restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment in the product documentation would be +# appreciated but is not required. +# +# 2. Altered source versions must be plainly marked as such, and must not be +# misrepresented as being the original software. +# +# 3. This notice may not be removed or altered from any source +# distribution. + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +PROJECT(DecodeOnGPUExample) + +#Projects source files +SET(SRC_FILES + main.cpp + ../common/OpenGLWidget.cpp +) + +#Projects headers files +SET(INC_FILES + OpenGLWidget.h +) + +add_definitions(-DGLEW_STATIC) + +FIND_PACKAGE(OpenGL REQUIRED) + +#Tell CMake the paths for OpenGL and for PolyVox (which is just relative to our current location) +INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_BINARY_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include ${GLEW_SOURCE_DIR}) +LINK_DIRECTORIES(${PolyVoxCore_BINARY_DIR}) + +#This will include the shader files inside the compiled binary +QT4_ADD_RESOURCES(COMMON_RESOURCES_RCC ../common/example.qrc) +QT4_ADD_RESOURCES(DECODE_RESOURCES_RCC decode.qrc) + +# Put the resources in a seperate folder in Visual Studio +SOURCE_GROUP("Resource Files" FILES ../common/example.qrc ${COMMON_RESOURCES_RCC} decode.qrc ${DECODE_RESOURCES_RCC}) + +#Build +ADD_EXECUTABLE(DecodeOnGPUExample ${SRC_FILES} ${COMMON_RESOURCES_RCC} ${DECODE_RESOURCES_RCC}) +IF(MSVC) + SET_TARGET_PROPERTIES(DecodeOnGPUExample PROPERTIES COMPILE_FLAGS "/W4 /wd4127") +ENDIF(MSVC) +TARGET_LINK_LIBRARIES(DecodeOnGPUExample glew ${QT_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} PolyVoxCore) +SET_PROPERTY(TARGET DecodeOnGPUExample PROPERTY FOLDER "Examples") + +#Install - Only install the example in Windows +IF(WIN32) + INSTALL(TARGETS DecodeOnGPUExample + RUNTIME DESTINATION Examples/OpenGL/bin + LIBRARY DESTINATION Examples/OpenGL/lib + ARCHIVE DESTINATION Examples/OpenGL/lib + COMPONENT example + ) + + #.dlls should be installed in shared builds. + #INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/../../release/PolyVoxCore.dll DESTINATION Examples/OpenGL/bin CONFIGURATIONS Release) + #INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/../../release/PolyVoxUtil.dll DESTINATION Examples/OpenGL/bin CONFIGURATIONS Release) + + #INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/../../debug/PolyVoxCore.dll DESTINATION Examples/OpenGL/bin CONFIGURATIONS Debug) + #INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/../../debug/PolyVoxUtil.dll DESTINATION Examples/OpenGL/bin CONFIGURATIONS Debug) +ENDIF(WIN32) diff --git a/examples/DecodeOnGPU/decode.frag b/examples/DecodeOnGPU/decode.frag new file mode 100644 index 00000000..fb576125 --- /dev/null +++ b/examples/DecodeOnGPU/decode.frag @@ -0,0 +1,19 @@ +#version 130 + +// Passed in from the vertex shader +in vec4 worldPosition; +in vec4 worldNormal; + +// the color that gets written to the display +out vec4 outputColor; + +void main() +{ + // Again, for the purposes of these examples we cannot be sure that per-vertex normals are provided. A sensible fallback + // is to use this little trick to compute per-fragment flat-shaded normals from the world positions using derivative operations. + //vec3 normal = normalize(cross(dFdy(worldPosition.xyz), dFdx(worldPosition.xyz))); + + // We are just using the normal as the output color, and making it lighter so it looks a bit nicer. + // Obviously a real shader would also do texuring, lighting, or whatever is required for the application. + outputColor = vec4(abs(worldNormal.xyz) * 0.5 + vec3(0.5, 0.5, 0.5), 1.0); +} diff --git a/examples/DecodeOnGPU/decode.qrc b/examples/DecodeOnGPU/decode.qrc new file mode 100644 index 00000000..f29bc1ad --- /dev/null +++ b/examples/DecodeOnGPU/decode.qrc @@ -0,0 +1,6 @@ + + + decode.vert + decode.frag + + diff --git a/examples/DecodeOnGPU/decode.vert b/examples/DecodeOnGPU/decode.vert new file mode 100644 index 00000000..5164468a --- /dev/null +++ b/examples/DecodeOnGPU/decode.vert @@ -0,0 +1,33 @@ +#version 140 + +in uvec4 position; // This will be the position of the vertex in model-space +in uint normal; + +// The usual matrices are provided +uniform mat4 cameraToClipMatrix; +uniform mat4 worldToCameraMatrix; +uniform mat4 modelToWorldMatrix; + +// This will be used by the fragment shader to calculate flat-shaded normals. This is an unconventional approach +// but we use it in this example framework because not all surface extractor generate surface normals. +out vec4 worldPosition; +out vec4 worldNormal; + +void main() +{ + vec4 decodedPosition = position; + decodedPosition.xyz = decodedPosition.xyz * (1.0 / 256.0); + + uint encodedX = (normal >> 10u) & 0x1Fu; + uint encodedY = (normal >> 5u) & 0x1Fu; + uint encodedZ = (normal) & 0x1Fu; + worldNormal.xyz = vec3(encodedX, encodedY, encodedZ); + worldNormal.xyz = worldNormal.xyz / 15.5; + worldNormal.xyz = worldNormal.xyz - vec3(1.0, 1.0, 1.0); + worldNormal.w = 1.0; + + // Standard sequence of OpenGL transformations. + worldPosition = modelToWorldMatrix * decodedPosition; + vec4 cameraPosition = worldToCameraMatrix * worldPosition; + gl_Position = cameraToClipMatrix * cameraPosition; +} diff --git a/examples/DecodeOnGPU/main.cpp b/examples/DecodeOnGPU/main.cpp new file mode 100644 index 00000000..2c0fff6d --- /dev/null +++ b/examples/DecodeOnGPU/main.cpp @@ -0,0 +1,164 @@ +/******************************************************************************* +Copyright (c) 2005-2009 David Williams + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*******************************************************************************/ + +#include "OpenGLWidget.h" + +#include "PolyVoxCore/CubicSurfaceExtractor.h" +#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h" +#include "PolyVoxCore/Mesh.h" +#include "PolyVoxCore/SimpleVolume.h" + +#include + +//Use the PolyVox namespace +using namespace PolyVox; + +void createSphereInVolume(SimpleVolume& volData, float fRadius) +{ + //This vector hold the position of the center of the volume + Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2); + + //This three-level for loop iterates over every voxel in the volume + for (int z = 0; z < volData.getDepth(); z++) + { + for (int y = 0; y < volData.getHeight(); y++) + { + for (int x = 0; x < volData.getWidth(); x++) + { + //Store our current position as a vector... + Vector3DFloat v3dCurrentPos(x,y,z); + //And compute how far the current position is from the center of the volume + float fDistToCenter = (v3dCurrentPos - v3dVolCenter).length(); + + uint8_t uVoxelValue = 0; + + //If the current voxel is less than 'radius' units from the center then we make it solid. + if(fDistToCenter <= fRadius) + { + //Our new voxel value + uVoxelValue = 255; + } + + //Wrte the voxel value into the volume + volData.setVoxelAt(x, y, z, uVoxelValue); + } + } + } +} + +OpenGLMeshData buildOpenGLMeshData(const PolyVox::Mesh< PolyVox::MarchingCubesVertex< uint8_t > >& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f) +{ + // Convienient access to the vertices and indices + const auto& vecIndices = surfaceMesh.getIndices(); + const auto& vecVertices = surfaceMesh.getVertices(); + + // This struct holds the OpenGL properties (buffer handles, etc) which will be used + // to render our mesh. We copy the data from the PolyVox mesh into this structure. + OpenGLMeshData meshData; + + // Create the VAO for the mesh + glGenVertexArrays(1, &(meshData.vertexArrayObject)); + glBindVertexArray(meshData.vertexArrayObject); + + // The GL_ARRAY_BUFFER will contain the list of vertex positions + glGenBuffers(1, &(meshData.vertexBuffer)); + glBindBuffer(GL_ARRAY_BUFFER, meshData.vertexBuffer); + glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(MarchingCubesVertex< uint8_t >), vecVertices.data(), GL_STATIC_DRAW); + + // and GL_ELEMENT_ARRAY_BUFFER will contain the indices + glGenBuffers(1, &(meshData.indexBuffer)); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshData.indexBuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), vecIndices.data(), GL_STATIC_DRAW); + + // Every surface extractor outputs valid positions for the vertices, so tell OpenGL how these are laid out + glEnableVertexAttribArray(0); // Attrib '0' is the vertex positions + glVertexAttribIPointer(0, 3, GL_UNSIGNED_SHORT, sizeof(MarchingCubesVertex< uint8_t >), (GLvoid*)(offsetof(MarchingCubesVertex< uint8_t >, encodedPosition))); //take the first 3 floats from every sizeof(decltype(vecVertices)::value_type) + + // Some surface extractors also generate normals, so tell OpenGL how these are laid out. If a surface extractor + // does not generate normals then nonsense values are written into the buffer here and sghould be ignored by the + // shader. This is mostly just to simplify this example code - in a real application you will know whether your + // chosen surface extractor generates normals and can skip uploading them if not. + glEnableVertexAttribArray(1); // Attrib '1' is the vertex normals. + glVertexAttribIPointer(1, 1, GL_UNSIGNED_SHORT, sizeof(MarchingCubesVertex< uint8_t >), (GLvoid*)(offsetof(MarchingCubesVertex< uint8_t >, encodedNormal))); + + // Finally a surface extractor will probably output additional data. This is highly application dependant. For this example code + // we're just uploading it as a set of bytes which we can read individually, but real code will want to do something specialised here. + glEnableVertexAttribArray(2); //We're talking about shader attribute '2' + GLint size = (std::min)(sizeof(uint8_t), size_t(4)); // Can't upload more that 4 components (vec4 is GLSL's biggest type) + glVertexAttribIPointer(2, size, GL_UNSIGNED_BYTE, sizeof(MarchingCubesVertex< uint8_t >), (GLvoid*)(offsetof(MarchingCubesVertex< uint8_t >, data))); + + // We're done uploading and can now unbind. + glBindVertexArray(0); + + // A few additional properties can be copied across for use during rendering. + meshData.noOfIndices = vecIndices.size(); + meshData.translation = QVector3D(translation.getX(), translation.getY(), translation.getZ()); + meshData.scale = scale; + + return meshData; +} + +int main(int argc, char *argv[]) +{ + //Create and show the Qt OpenGL window + QApplication app(argc, argv); + OpenGLWidget openGLWidget(0); + openGLWidget.show(); + + QSharedPointer shader(new QGLShaderProgram); + + if (!shader->addShaderFromSourceFile(QGLShader::Vertex, ":/decode.vert")) + { + std::cerr << shader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + if (!shader->addShaderFromSourceFile(QGLShader::Fragment, ":/decode.frag")) + { + std::cerr << shader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + openGLWidget.setShader(shader); + + //Create an empty volume and then place a sphere in it + SimpleVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(63, 63, 63))); + createSphereInVolume(volData, 30); + + // Extract the surface for the specified region of the volume. Uncomment the line for the kind of surface extraction you want to see. + //auto mesh = extractCubicMesh(&volData, volData.getEnclosingRegion()); + auto mesh = extractMarchingCubesMesh(&volData, volData.getEnclosingRegion()); + + // The surface extractor outputs the mesh in an efficient compressed format which is not directly suitable for rendering. The easiest approach is to + // decode this on the CPU as shown below, though more advanced applications can upload the compressed mesh to the GPU and decompress in shader code. + //auto decodedMesh = decode(mesh); + + //Pass the surface to the OpenGL window + OpenGLMeshData meshData = buildOpenGLMeshData(mesh); + openGLWidget.addMeshData(meshData); + + openGLWidget.setViewableRegion(volData.getEnclosingRegion()); + + //Run the message pump. + return app.exec(); +} \ No newline at end of file diff --git a/examples/OpenGL/CMakeLists.txt b/examples/OpenGL/CMakeLists.txt index 5cd1ed55..14e9f4d1 100644 --- a/examples/OpenGL/CMakeLists.txt +++ b/examples/OpenGL/CMakeLists.txt @@ -26,37 +26,33 @@ PROJECT(OpenGLExample) #Projects source files SET(SRC_FILES main.cpp - OpenGLImmediateModeSupport.cpp - OpenGLSupport.cpp - OpenGLVertexBufferObjectSupport.cpp - OpenGLWidget.cpp + ../common/OpenGLWidget.cpp Shapes.cpp ) #Projects headers files SET(INC_FILES - OpenGLImmediateModeSupport.h - OpenGLSupport.h - OpenGLVertexBufferObjectSupport.h OpenGLWidget.h Shapes.h ) add_definitions(-DGLEW_STATIC) -#"Sources" and "Headers" are the group names in Visual Studio. -#They may have other uses too... -SOURCE_GROUP("Sources" FILES ${SRC_FILES}) -SOURCE_GROUP("Headers" FILES ${INC_FILES}) - FIND_PACKAGE(OpenGL REQUIRED) #Tell CMake the paths for OpenGL and for PolyVox (which is just relative to our current location) INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_BINARY_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include ${GLEW_SOURCE_DIR}) LINK_DIRECTORIES(${PolyVoxCore_BINARY_DIR}) +#This will include the shader files inside the compiled binary +QT4_ADD_RESOURCES(COMMON_RESOURCES_RCC ../common/example.qrc) +QT4_ADD_RESOURCES(OPENGLEXAMPLE_RESOURCES_RCC openglexample.qrc) + +# Put the resources in a seperate folder in Visual Studio +SOURCE_GROUP("Resource Files" FILES ../common/example.qrc ${COMMON_RESOURCES_RCC} openglexample.qrc ${OPENGLEXAMPLE_RESOURCES_RCC}) + #Build -ADD_EXECUTABLE(OpenGLExample ${SRC_FILES}) +ADD_EXECUTABLE(OpenGLExample ${SRC_FILES} ${COMMON_RESOURCES_RCC} ${OPENGLEXAMPLE_RESOURCES_RCC}) IF(MSVC) SET_TARGET_PROPERTIES(OpenGLExample PROPERTIES COMPILE_FLAGS "/W4 /wd4127") ENDIF(MSVC) diff --git a/examples/OpenGL/OpenGLImmediateModeSupport.cpp b/examples/OpenGL/OpenGLImmediateModeSupport.cpp deleted file mode 100644 index 7aff64df..00000000 --- a/examples/OpenGL/OpenGLImmediateModeSupport.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#include "OpenGLImmediateModeSupport.h" -#include "OpenGLSupport.h" - -#include "PolyVoxCore/SurfaceMesh.h" - -using namespace PolyVox; -using namespace std; - -void renderRegionImmediateMode(PolyVox::SurfaceMesh >& mesh, unsigned int uLodLevel) -{ - const vector >& vecVertices = mesh.getVertices(); - const vector& vecIndices = mesh.getIndices(); - - int beginIndex = mesh.m_vecLodRecords[uLodLevel].beginIndex; - int endIndex = mesh.m_vecLodRecords[uLodLevel].endIndex; - - glBegin(GL_TRIANGLES); - //for(vector::const_iterator iterIndex = vecIndices.begin(); iterIndex != vecIndices.end(); ++iterIndex) - for(int index = beginIndex; index < endIndex; ++index) - { - const MarchingCubesVertex & vertex = vecVertices[vecIndices[index]]; - const Vector3DFloat& v3dVertexPos = vertex.getPosition(); - //const Vector3DFloat v3dRegionOffset(uRegionX * g_uRegionSideLength, uRegionY * g_uRegionSideLength, uRegionZ * g_uRegionSideLength); - const Vector3DFloat v3dFinalVertexPos = v3dVertexPos + static_cast(mesh.m_Region.getLowerCorner()); - - - - - uint8_t material = static_cast(static_cast(vertex.getMaterial().getMaterial()) + 0.5); - //uint8_t material = 1; - - - OpenGLColour colour = convertMaterialIDToColour(material); - - glColor3f(colour.red, colour.green, colour.blue); - glNormal3f(vertex.getNormal().getX(), vertex.getNormal().getY(), vertex.getNormal().getZ()); - glVertex3f(v3dFinalVertexPos.getX(), v3dFinalVertexPos.getY(), v3dFinalVertexPos.getZ()); - - - } - glEnd(); -} \ No newline at end of file diff --git a/examples/OpenGL/OpenGLImmediateModeSupport.h b/examples/OpenGL/OpenGLImmediateModeSupport.h deleted file mode 100644 index 9f5aea79..00000000 --- a/examples/OpenGL/OpenGLImmediateModeSupport.h +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#ifndef __OpenGLExample_OpenGLImmediateModeSupport_H__ -#define __OpenGLExample_OpenGLImmediateModeSupport_H__ - -#include "PolyVoxCore/MaterialDensityPair.h" -#include "PolyVoxCore/PolyVoxForwardDeclarations.h" - -#include "glew/glew.h" - -void renderRegionImmediateMode(PolyVox::SurfaceMesh >& mesh, unsigned int uLodLevel); - -#endif //__OpenGLExample_OpenGLImmediateModeSupport_H__ diff --git a/examples/OpenGL/OpenGLSupport.cpp b/examples/OpenGL/OpenGLSupport.cpp deleted file mode 100644 index 73efb444..00000000 --- a/examples/OpenGL/OpenGLSupport.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#include "OpenGLSupport.h" - -using namespace PolyVox; - -OpenGLColour convertMaterialIDToColour(uint8_t materialID) -{ - OpenGLColour colour; - - switch(materialID) - { - case 1: - colour.red = 1.0f; - colour.green = 0.0f; - colour.blue = 0.0f; - break; - case 2: - colour.red = 0.0f; - colour.green = 1.0f; - colour.blue = 0.0f; - break; - case 3: - colour.red = 0.0f; - colour.green = 0.0f; - colour.blue = 1.0f; - break; - case 4: - colour.red = 1.0f; - colour.green = 1.0f; - colour.blue = 0.0f; - break; - case 5: - colour.red = 1.0f; - colour.green = 0.0f; - colour.blue = 1.0f; - break; - default: - colour.red = 1.0f; - colour.green = 1.0f; - colour.blue = 1.0f; - } - - return colour; -} \ No newline at end of file diff --git a/examples/OpenGL/OpenGLVertexBufferObjectSupport.cpp b/examples/OpenGL/OpenGLVertexBufferObjectSupport.cpp deleted file mode 100644 index ae5afd15..00000000 --- a/examples/OpenGL/OpenGLVertexBufferObjectSupport.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#include "OpenGLSupport.h" -#include "OpenGLVertexBufferObjectSupport.h" - -#include "PolyVoxCore/MaterialDensityPair.h" -#include "PolyVoxCore/SurfaceMesh.h" - -using namespace PolyVox; -using namespace std; - -OpenGLSurfaceMesh BuildOpenGLSurfaceMesh(const SurfaceMesh >& mesh) -{ - //Represents our filled in OpenGL vertex and index buffer objects. - OpenGLSurfaceMesh result; - - //The source - result.sourceMesh = &mesh; - - //Convienient access to the vertices and indices - const vector >& vecVertices = mesh.getVertices(); - const vector& vecIndices = mesh.getIndices(); - - //If we have any indices... - if(!vecIndices.empty()) - { - //Create an OpenGL index buffer - glGenBuffers(1, &result.indexBuffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, result.indexBuffer); - - //Get a pointer to the first index - GLvoid* pIndices = (GLvoid*)(&(vecIndices[0])); - - //Fill the OpenGL index buffer with our data. - glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), pIndices, GL_STATIC_DRAW); - } - - result.noOfIndices = vecIndices.size(); - - glGenBuffers(1, &result.vertexBuffer); - glBindBuffer(GL_ARRAY_BUFFER, result.vertexBuffer); - glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(GLfloat) * 9, 0, GL_STATIC_DRAW); - GLfloat* ptr = (GLfloat*)glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); - - for (vector >::const_iterator iterVertex = vecVertices.begin(); iterVertex != vecVertices.end(); ++iterVertex) - { - const MarchingCubesVertex & vertex = *iterVertex; - const Vector3DFloat& v3dVertexPos = vertex.getPosition(); - //const Vector3DFloat v3dRegionOffset(uRegionX * g_uRegionSideLength, uRegionY * g_uRegionSideLength, uRegionZ * g_uRegionSideLength); - const Vector3DFloat v3dFinalVertexPos = v3dVertexPos + static_cast(mesh.m_Region.getLowerCorner()); - - *ptr = v3dFinalVertexPos.getX(); - ptr++; - *ptr = v3dFinalVertexPos.getY(); - ptr++; - *ptr = v3dFinalVertexPos.getZ(); - ptr++; - - *ptr = vertex.getNormal().getX(); - ptr++; - *ptr = vertex.getNormal().getY(); - ptr++; - *ptr = vertex.getNormal().getZ(); - ptr++; - - uint8_t material = static_cast(vertex.getMaterial().getMaterial() + 0.5); - //uint8_t material = 1; - - OpenGLColour colour = convertMaterialIDToColour(material); - - *ptr = colour.red; - ptr++; - *ptr = colour.green; - ptr++; - *ptr = colour.blue; - ptr++; - } - - glUnmapBuffer(GL_ARRAY_BUFFER); - - return result; -} - -void renderRegionVertexBufferObject(const OpenGLSurfaceMesh& openGLSurfaceMesh, unsigned int uLodLevel) -{ - int beginIndex = openGLSurfaceMesh.sourceMesh->m_vecLodRecords[uLodLevel].beginIndex; - int endIndex = openGLSurfaceMesh.sourceMesh->m_vecLodRecords[uLodLevel].endIndex; - glBindBuffer(GL_ARRAY_BUFFER, openGLSurfaceMesh.vertexBuffer); - glVertexPointer(3, GL_FLOAT, 36, 0); - glNormalPointer(GL_FLOAT, 36, (GLvoid*)12); - glColorPointer(3, GL_FLOAT, 36, (GLvoid*)24); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, openGLSurfaceMesh.indexBuffer); - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glEnableClientState(GL_COLOR_ARRAY); - - //glDrawElements(GL_TRIANGLES, openGLSurfaceMesh.noOfIndices, GL_UNSIGNED_INT, 0); - glDrawRangeElements(GL_TRIANGLES, beginIndex, endIndex-1, endIndex - beginIndex,/* openGLSurfaceMesh.noOfIndices,*/ GL_UNSIGNED_INT, 0); - - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); -} \ No newline at end of file diff --git a/examples/OpenGL/OpenGLVertexBufferObjectSupport.h b/examples/OpenGL/OpenGLVertexBufferObjectSupport.h deleted file mode 100644 index fc97dfb8..00000000 --- a/examples/OpenGL/OpenGLVertexBufferObjectSupport.h +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#ifndef __OpenGLExample_OpenGLVertexBufferObjectSupport_H__ -#define __OpenGLExample_OpenGLVertexBufferObjectSupport_H__ - -#include "PolyVoxCore/PolyVoxForwardDeclarations.h" - -#include "glew/glew.h" - -struct OpenGLSurfaceMesh -{ - GLulong noOfIndices; - GLuint indexBuffer; - GLuint vertexBuffer; - const PolyVox::SurfaceMesh >* sourceMesh; -}; - -OpenGLSurfaceMesh BuildOpenGLSurfaceMesh(const PolyVox::SurfaceMesh >& mesh); -void renderRegionVertexBufferObject(const OpenGLSurfaceMesh& openGLSurfaceMesh, unsigned int uLodLevel); - -#endif //__OpenGLExample_OpenGLVertexBufferObjectSupport_H__ diff --git a/examples/OpenGL/OpenGLWidget.cpp b/examples/OpenGL/OpenGLWidget.cpp deleted file mode 100644 index 475ba846..00000000 --- a/examples/OpenGL/OpenGLWidget.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#include "OpenGLWidget.h" - -#include - -#include "PolyVoxCore/GradientEstimators.h" -#include "PolyVoxCore/MaterialDensityPair.h" -#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h" - -//Some namespaces we need -using namespace std; -using namespace PolyVox; -using namespace std; - -OpenGLWidget::OpenGLWidget(QWidget *parent) - :QGLWidget(parent) - ,m_volData(0) -{ - m_xRotation = 0; - m_yRotation = 0; - m_uRegionSideLength = 32; - - timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(update())); - timer->start(0); -} - -void OpenGLWidget::setVolume(PolyVox::LargeVolume* volData) -{ - //First we free anything from the previous volume (if there was one). - m_mapOpenGLSurfaceMeshes.clear(); - m_mapSurfaceMeshes.clear(); - m_volData = volData; - - //If we have any volume data then generate the new surface patches. - if(m_volData != 0) - { - m_uVolumeWidthInRegions = volData->getWidth() / m_uRegionSideLength; - m_uVolumeHeightInRegions = volData->getHeight() / m_uRegionSideLength; - m_uVolumeDepthInRegions = volData->getDepth() / m_uRegionSideLength; - - //Our volume is broken down into cuboid regions, and we create one mesh for each region. - //This three-level for loop iterates over each region. - for(uint16_t uRegionZ = 0; uRegionZ < m_uVolumeDepthInRegions; ++uRegionZ) - { - std::cout << "uRegionZ = " << uRegionZ << " of " << m_uVolumeDepthInRegions << std::endl; - for(uint16_t uRegionY = 0; uRegionY < m_uVolumeHeightInRegions; ++uRegionY) - { - for(uint16_t uRegionX = 0; uRegionX < m_uVolumeWidthInRegions; ++uRegionX) - { - //Compute the extents of the current region - //FIXME - This is a little complex? PolyVox could - //provide more functions for dealing with regions? - int32_t regionStartX = uRegionX * m_uRegionSideLength; - int32_t regionStartY = uRegionY * m_uRegionSideLength; - int32_t regionStartZ = uRegionZ * m_uRegionSideLength; - - int32_t regionEndX = regionStartX + m_uRegionSideLength; - int32_t regionEndY = regionStartY + m_uRegionSideLength; - int32_t regionEndZ = regionStartZ + m_uRegionSideLength; - - Vector3DInt32 regLowerCorner(regionStartX, regionStartY, regionStartZ); - Vector3DInt32 regUpperCorner(regionEndX, regionEndY, regionEndZ); - - //Extract the surface for this region - //extractSurface(m_volData, 0, PolyVox::Region(regLowerCorner, regUpperCorner), meshCurrent); - - std::shared_ptr< SurfaceMesh > > mesh(new SurfaceMesh >); - MarchingCubesSurfaceExtractor< LargeVolume > surfaceExtractor(volData, PolyVox::Region(regLowerCorner, regUpperCorner), mesh.get()); - surfaceExtractor.execute(); - - //decimatedMesh->generateAveragedFaceNormals(true); - - //computeNormalsForVertices(m_volData, *(decimatedMesh.get()), SOBEL_SMOOTHED); - //*meshCurrent = getSmoothedSurface(*meshCurrent); - //mesh->smooth(0.3f); - //meshCurrent->generateAveragedFaceNormals(true); - - if(mesh->m_vecTriangleIndices.size() > 0) - { - - - Vector3DUint8 v3dRegPos(uRegionX,uRegionY,uRegionZ); - if(m_bUseOpenGLVertexBufferObjects) - { - OpenGLSurfaceMesh openGLSurfaceMesh = BuildOpenGLSurfaceMesh(*(mesh.get())); - m_mapOpenGLSurfaceMeshes.insert(make_pair(v3dRegPos, openGLSurfaceMesh)); - } - //else - //{ - m_mapSurfaceMeshes.insert(make_pair(v3dRegPos, mesh)); - //} - //delete meshCurrent; - } - } - } - } - - //Projection matrix is dependant on volume size, so we need to set it up again. - setupProjectionMatrix(); - } -} - -void OpenGLWidget::initializeGL() -{ - m_bUseOpenGLVertexBufferObjects = true; - if(m_bUseOpenGLVertexBufferObjects) - { - //We need GLEW to access recent OpenGL functionality - GLenum err = glewInit(); - if (GLEW_OK != err) - { - /* Problem: glewInit failed, something is seriously wrong. */ - cout << "GLEW Error: " << glewGetErrorString(err) << endl; - } - } - - glShadeModel(GL_SMOOTH); // Enable Smooth Shading - glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background - glClearDepth(1.0f); // Depth Buffer Setup - glEnable(GL_DEPTH_TEST); // Enables Depth Testing - glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do - glEnable ( GL_COLOR_MATERIAL ); - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - - glEnable(GL_LIGHTING); - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); - glEnable(GL_LIGHT0); - - //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - glShadeModel(GL_SMOOTH); -} - -void OpenGLWidget::resizeGL(int w, int h) -{ - //Setup the viewport based on the window size - glViewport(0, 0, w, h); - - //Projection matrix is also dependant on the size of the current volume. - if(m_volData) - { - setupProjectionMatrix(); - } -} - -void OpenGLWidget::paintGL() -{ - if(m_volData) - { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer - - glMatrixMode(GL_MODELVIEW); // Select The Model View Matrix - glLoadIdentity(); // Reset The Current Modelview Matrix - - //Moves the camera back so we can see the volume - glTranslatef(0.0f, 0.0f, -m_volData->getDiagonalLength()); - - glRotatef(m_xRotation, 1.0f, 0.0f, 0.0f); - glRotatef(m_yRotation, 0.0f, 1.0f, 0.0f); - - //Centre the volume on the origin - glTranslatef(-g_uVolumeSideLength/2,-g_uVolumeSideLength/2,-g_uVolumeSideLength/2); - - for(uint16_t uRegionZ = 0; uRegionZ < m_uVolumeDepthInRegions; ++uRegionZ) - { - for(uint16_t uRegionY = 0; uRegionY < m_uVolumeHeightInRegions; ++uRegionY) - { - for(uint16_t uRegionX = 0; uRegionX < m_uVolumeWidthInRegions; ++uRegionX) - { - Vector3DUint8 v3dRegPos(uRegionX,uRegionY,uRegionZ); - if(m_mapSurfaceMeshes.find(v3dRegPos) != m_mapSurfaceMeshes.end()) - { - std::shared_ptr< SurfaceMesh > > meshCurrent = m_mapSurfaceMeshes[v3dRegPos]; - unsigned int uLodLevel = 0; //meshCurrent->m_vecLodRecords.size() - 1; - if(m_bUseOpenGLVertexBufferObjects) - { - renderRegionVertexBufferObject(m_mapOpenGLSurfaceMeshes[v3dRegPos], uLodLevel); - } - else - { - renderRegionImmediateMode(*meshCurrent, uLodLevel); - } - } - } - } - } - - GLenum errCode; - const GLubyte *errString; - - if ((errCode = glGetError()) != GL_NO_ERROR) - { - errString = gluErrorString(errCode); - cout << "OpenGL Error: " << errString << endl; - } - } -} - -void OpenGLWidget::mousePressEvent(QMouseEvent* event) -{ - m_CurrentMousePos = event->pos(); - m_LastFrameMousePos = m_CurrentMousePos; -} - -void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) -{ - m_CurrentMousePos = event->pos(); - QPoint diff = m_CurrentMousePos - m_LastFrameMousePos; - m_xRotation += diff.x(); - m_yRotation += diff.y(); - m_LastFrameMousePos = m_CurrentMousePos;; -} - -void OpenGLWidget::setupProjectionMatrix(void) -{ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - - float frustumSize = m_volData->getDiagonalLength() / 2.0f; - float aspect = static_cast(width()) / static_cast(height()); - - glOrtho(frustumSize*aspect, -frustumSize*aspect, frustumSize, -frustumSize, 1.0, 5000); -} diff --git a/examples/OpenGL/OpenGLWidget.h b/examples/OpenGL/OpenGLWidget.h deleted file mode 100644 index 1b4b4612..00000000 --- a/examples/OpenGL/OpenGLWidget.h +++ /dev/null @@ -1,99 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#ifndef __PolyVox_OpenGLWidget_H__ -#define __PolyVox_OpenGLWidget_H__ - -#include "glew/glew.h" - -#include -#include - -#include "PolyVoxCore/LargeVolume.h" -#include "PolyVoxCore/SurfaceMesh.h" -#include "PolyVoxCore/Impl/Utility.h" - -#include "OpenGLImmediateModeSupport.h" -#include "OpenGLVertexBufferObjectSupport.h" -#include "Shapes.h" - -const int32_t g_uVolumeSideLength = 128; - -struct Vector3DUint8Compare -{ - bool operator() (const PolyVox::Vector3DUint8& a, const PolyVox::Vector3DUint8& b) const - { - const uint32_t size = 3; - for(uint32_t ct = 0; ct < size; ++ct) - { - if (a.getElement(ct) < b.getElement(ct)) - return true; - if (b.getElement(ct) < a.getElement(ct)) - return false; - } - return false; - } -}; - -class OpenGLWidget : public QGLWidget - { - - public: - OpenGLWidget(QWidget *parent); - - void setVolume(PolyVox::LargeVolume* volData); - - void mouseMoveEvent(QMouseEvent* event); - void mousePressEvent(QMouseEvent* event); - - protected: - void initializeGL(); - void resizeGL(int w, int h); - void paintGL(); - - private: - void setupProjectionMatrix(void); - QPoint m_LastFrameMousePos; - QPoint m_CurrentMousePos; - - int m_xRotation; - int m_yRotation; - - QTimer *timer; - - bool m_bUseOpenGLVertexBufferObjects; - - //Creates a volume 128x128x128 - PolyVox::LargeVolume* m_volData; - - //Rather than storing one big mesh, the volume is broken into regions and a mesh is stored for each region - std::map m_mapOpenGLSurfaceMeshes; - std::map > >, Vector3DUint8Compare> m_mapSurfaceMeshes; - - unsigned int m_uRegionSideLength; - unsigned int m_uVolumeWidthInRegions; - unsigned int m_uVolumeHeightInRegions; - unsigned int m_uVolumeDepthInRegions; - }; - -#endif //__PolyVox_OpenGLWidget_H__ diff --git a/examples/OpenGL/Shapes.cpp b/examples/OpenGL/Shapes.cpp index 558530ba..7a66b988 100644 --- a/examples/OpenGL/Shapes.cpp +++ b/examples/OpenGL/Shapes.cpp @@ -27,7 +27,7 @@ freely, subject to the following restrictions: using namespace PolyVox; -void createSphereInVolume(LargeVolume& volData, float fRadius, uint8_t uValue) +void createSphereInVolume(LargeVolume& volData, float fRadius, uint8_t uValue) { //This vector hold the position of the center of the volume Vector3DInt32 v3dVolCenter = (volData.getEnclosingRegion().getUpperCorner() - volData.getEnclosingRegion().getLowerCorner()) / static_cast(2); @@ -48,17 +48,17 @@ void createSphereInVolume(LargeVolume& volData, float fRa //then we make it solid, otherwise we make it empty space. if(fDistToCenter <= fRadius) { - volData.setVoxelAt(x,y,z, MaterialDensityPair44(uValue, uValue > 0 ? MaterialDensityPair44::getMaxDensity() : MaterialDensityPair44::getMinDensity())); + volData.setVoxelAt(x,y,z, MaterialDensityPair88(uValue, uValue > 0 ? MaterialDensityPair88::getMaxDensity() : MaterialDensityPair88::getMinDensity())); } } } } } -void createCubeInVolume(LargeVolume& volData, Vector3DInt32 lowerCorner, Vector3DInt32 upperCorner, uint8_t uValue) +void createCubeInVolume(LargeVolume& volData, Vector3DInt32 lowerCorner, Vector3DInt32 upperCorner, uint8_t uValue) { - uint8_t maxDen = MaterialDensityPair44::getMaxDensity(); - uint8_t minDen = MaterialDensityPair44::getMinDensity(); + uint8_t maxDen = MaterialDensityPair88::getMaxDensity(); + uint8_t minDen = MaterialDensityPair88::getMinDensity(); //This three-level for loop iterates over every voxel between the specified corners for (int z = lowerCorner.getZ(); z <= upperCorner.getZ(); z++) { @@ -66,7 +66,7 @@ void createCubeInVolume(LargeVolume& volData, Vector3DInt { for (int x = lowerCorner.getX() ; x <= upperCorner.getX(); x++) { - volData.setVoxelAt(x,y,z, MaterialDensityPair44(uValue, uValue > 0 ? maxDen : minDen)); + volData.setVoxelAt(x,y,z, MaterialDensityPair88(uValue, uValue > 0 ? maxDen : minDen)); } } } diff --git a/examples/OpenGL/Shapes.h b/examples/OpenGL/Shapes.h index 93f047fd..712558fd 100644 --- a/examples/OpenGL/Shapes.h +++ b/examples/OpenGL/Shapes.h @@ -27,7 +27,7 @@ freely, subject to the following restrictions: #include "PolyVoxCore/LargeVolume.h" #include "PolyVoxCore/MaterialDensityPair.h" -void createSphereInVolume(PolyVox::LargeVolume& volData, float fRadius, uint8_t uValue); -void createCubeInVolume(PolyVox::LargeVolume& volData, PolyVox::Vector3DInt32 lowerCorner, PolyVox::Vector3DInt32 upperCorner, uint8_t uValue); +void createSphereInVolume(PolyVox::LargeVolume& volData, float fRadius, uint8_t uValue); +void createCubeInVolume(PolyVox::LargeVolume& volData, PolyVox::Vector3DInt32 lowerCorner, PolyVox::Vector3DInt32 upperCorner, uint8_t uValue); #endif //__OpenGLExample_Shapes_H__ \ No newline at end of file diff --git a/examples/OpenGL/main.cpp b/examples/OpenGL/main.cpp index e6ae33d7..12d1068f 100644 --- a/examples/OpenGL/main.cpp +++ b/examples/OpenGL/main.cpp @@ -22,16 +22,15 @@ freely, subject to the following restrictions: *******************************************************************************/ #include "PolyVoxCore/FilePager.h" +#include "PolyVoxCore/MarchingCubesSurfaceExtractor.h" #include "PolyVoxCore/MaterialDensityPair.h" #include "PolyVoxCore/LargeVolume.h" #include "PolyVoxCore/LowPassFilter.h" #include "PolyVoxCore/RawVolume.h" #include "PolyVoxCore/RLEBlockCompressor.h" -#include "PolyVoxCore/SurfaceMesh.h" +#include "PolyVoxCore/Mesh.h" #include "PolyVoxCore/Impl/Utility.h" -#include "OpenGLImmediateModeSupport.h" -#include "OpenGLVertexBufferObjectSupport.h" #include "Shapes.h" #include "OpenGLWidget.h" @@ -48,11 +47,13 @@ using namespace std; using namespace PolyVox; using namespace std; +const int32_t g_uVolumeSideLength = 128; + int main(int argc, char *argv[]) { - RLEBlockCompressor* compressor = new RLEBlockCompressor(); - FilePager* pager = new FilePager("./"); - LargeVolume volData(PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(g_uVolumeSideLength-1, g_uVolumeSideLength-1, g_uVolumeSideLength-1)), compressor, pager); + RLEBlockCompressor* compressor = new RLEBlockCompressor(); + FilePager* pager = new FilePager("./"); + LargeVolume volData(PolyVox::Region(Vector3DInt32(0, 0, 0), Vector3DInt32(g_uVolumeSideLength - 1, g_uVolumeSideLength - 1, g_uVolumeSideLength - 1)), compressor, pager); //Make our volume contain a sphere in the center. int32_t minPos = 0; @@ -80,15 +81,6 @@ int main(int argc, char *argv[]) createCubeInVolume(volData, Vector3DInt32(midPos-10, 1, midPos-10), Vector3DInt32(midPos+10, maxPos-1, midPos+10), MaterialDensityPair44::getMaxDensity()); createCubeInVolume(volData, Vector3DInt32(midPos-10, midPos-10 ,1), Vector3DInt32(midPos+10, midPos+10, maxPos-1), MaterialDensityPair44::getMaxDensity()); - //I've removed this smoothing because it doesn't really make sense to apply a low pass filter to a volume with material values. - //I could implement the mathematical operators for MaterialDensityPair in such a way that they ignores the materials but this - //seems to be setting a bad example. Users can add this operators in their own classes if they want smoothing. - //RawVolume tempVolume(PolyVox::Region(0,0,0,128, 128, 128)); - //LowPassFilter< LargeVolume, RawVolume > pass1(&volData, PolyVox::Region(Vector3DInt32(62, 62, 62), Vector3DInt32(126, 126, 126)), &tempVolume, PolyVox::Region(Vector3DInt32(62, 62, 62), Vector3DInt32(126, 126, 126)), 3); - //pass1.executeSAT(); - //LowPassFilter< RawVolume, LargeVolume > pass2(&tempVolume, PolyVox::Region(Vector3DInt32(62, 62, 62), Vector3DInt32(126, 126, 126)), &volData, PolyVox::Region(Vector3DInt32(62, 62, 62), Vector3DInt32(126, 126, 126)), 3); - //pass2.executeSAT(); - QApplication app(argc, argv); OpenGLWidget openGLWidget(0); @@ -96,12 +88,62 @@ int main(int argc, char *argv[]) openGLWidget.show(); + QSharedPointer shader(new QGLShaderProgram); + + if (!shader->addShaderFromSourceFile(QGLShader::Vertex, ":/openglexample.vert")) + { + std::cerr << shader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + if (!shader->addShaderFromSourceFile(QGLShader::Fragment, ":/openglexample.frag")) + { + std::cerr << shader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + openGLWidget.setShader(shader); + QTime time; time.start(); - openGLWidget.setVolume(&volData); + //openGLWidget.setVolume(&volData); cout << endl << "Time taken = " << time.elapsed() / 1000.0f << "s" << endl << endl; - //return 0; + const int32_t extractedRegionSize = 32; + int meshCounter = 0; + + for (int32_t z = 0; z < volData.getDepth(); z += extractedRegionSize) + { + for (int32_t y = 0; y < volData.getHeight(); y += extractedRegionSize) + { + for (int32_t x = 0; x < volData.getWidth(); x += extractedRegionSize) + { + // Specify the region to extract based on a starting position and the desired region sze. + PolyVox::Region regToExtract(x, y, z, x + extractedRegionSize, y + extractedRegionSize, z + extractedRegionSize); + + // If you uncomment this line you will be able to see that the volume is rendered as multiple seperate meshes. + //regToExtract.shrink(1); + + // Perform the extraction for this region of the volume + auto mesh = extractMarchingCubesMesh(&volData, regToExtract); + + // The returned mesh needs to be decoded to be appropriate for GPU rendering. + auto decodedMesh = decode(mesh); + + // Pass the surface to the OpenGL window. Note that we are also passing an offset in this multi-mesh example. This is because + // the surface extractors return a mesh with 'local space' positions to reduce storage requirements and precision problems. + openGLWidget.addMesh(decodedMesh, decodedMesh.getOffset()); + + meshCounter++; + } + } + } + + cout << "Rendering volume as " << meshCounter << " seperate meshes" << endl; + + + openGLWidget.setViewableRegion(volData.getEnclosingRegion()); + return app.exec(); } diff --git a/examples/OpenGL/openglexample.frag b/examples/OpenGL/openglexample.frag new file mode 100644 index 00000000..75aa0e74 --- /dev/null +++ b/examples/OpenGL/openglexample.frag @@ -0,0 +1,45 @@ +#version 130 + +in vec4 worldPosition; //Passed in from the vertex shader +in vec3 normalFromVS; +flat in ivec2 materialFromVS; + +out vec4 outputColor; + +void main() +{ + // The first byte of our voxel data is the material. + // We use this to decide how to color the fragment. + vec4 surfaceColor; + switch(materialFromVS.x) + { + case 1: + surfaceColor = vec4(1.0, 0.0, 0.0, 1.0); + break; + case 2: + surfaceColor = vec4(0.0, 1.0, 0.0, 1.0); + break; + case 3: + surfaceColor = vec4(0.0, 0.0, 1.0, 1.0); + break; + case 4: + surfaceColor = vec4(1.0, 1.0, 0.0, 1.0); + break; + case 5: + surfaceColor = vec4(1.0, 0.0, 1.0, 1.0); + break; + default: + surfaceColor = vec4(1.0, 1.0, 1.0, 1.0); + break; + } + + // Quick and dirty lighting, obviously a real implementation + // should pass light properties as shader parameters, etc. + vec3 lightDir = vec3(0.0, 0.0, 1.0); + float diffuse = clamp(dot(lightDir, normalFromVS), 0.0, 1.0); + diffuse *= 0.7; // Dim the diffuse a bit + float ambient = 0.3; // Add some ambient + float lightIntensity = diffuse + ambient; // Compute the final light intensity + + outputColor = surfaceColor * lightIntensity; //Compute final rendered color +} diff --git a/examples/OpenGL/openglexample.qrc b/examples/OpenGL/openglexample.qrc new file mode 100644 index 00000000..128acb5a --- /dev/null +++ b/examples/OpenGL/openglexample.qrc @@ -0,0 +1,6 @@ + + + openglexample.vert + openglexample.frag + + diff --git a/examples/OpenGL/openglexample.vert b/examples/OpenGL/openglexample.vert new file mode 100644 index 00000000..381fac12 --- /dev/null +++ b/examples/OpenGL/openglexample.vert @@ -0,0 +1,26 @@ +#version 140 + +in vec4 position; // This will be the position of the vertex in model-space +in vec4 normal; // The normal data may not have been set +in ivec2 material; + +uniform mat4 cameraToClipMatrix; +uniform mat4 worldToCameraMatrix; +uniform mat4 modelToWorldMatrix; + +out vec4 worldPosition; //This is being passed to the fragment shader to calculate the normals +out vec3 normalFromVS; +flat out ivec2 materialFromVS; + +void main() +{ + // Compute the usual OpenGL transformation to clip space. + gl_Position = cameraToClipMatrix * worldToCameraMatrix * modelToWorldMatrix * position; + + // This example is demonstrating the marching cubes mesh, which does have per-vertex normals. We can + // just pass them through, though real code might want to deal with transforming normals appropriatly. + normalFromVS = normal.xyz; + + // Nothing special here, we just pass the material through to the fragment shader. + materialFromVS = material; +} diff --git a/examples/Paging/CMakeLists.txt b/examples/Paging/CMakeLists.txt index e8020b2d..95a3ef8a 100644 --- a/examples/Paging/CMakeLists.txt +++ b/examples/Paging/CMakeLists.txt @@ -26,7 +26,7 @@ PROJECT(PagingExample) #Projects source files SET(SRC_FILES main.cpp - OpenGLWidget.cpp + ../common/OpenGLWidget.cpp Perlin.cpp ) @@ -38,25 +38,29 @@ SET(INC_FILES add_definitions(-DGLEW_STATIC) -#"Sources" and "Headers" are the group names in Visual Studio. -#They may have other uses too... -SOURCE_GROUP("Sources" FILES ${SRC_FILES}) -SOURCE_GROUP("Headers" FILES ${INC_FILES}) - FIND_PACKAGE(OpenGL REQUIRED) #Tell CMake the paths for OpenGL and for PolyVox (which is just relative to our current location) INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_BINARY_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include ${GLEW_SOURCE_DIR}) LINK_DIRECTORIES(${PolyVoxCore_BINARY_DIR}) +#This will include the shader files inside the compiled binary +QT4_ADD_RESOURCES(COMMON_RESOURCES_RCC ../common/example.qrc) + +# Put the resources in a seperate folder in Visual Studio +SOURCE_GROUP("Resource Files" FILES ../common/example.qrc ${COMMON_RESOURCES_RCC}) + #Build -ADD_EXECUTABLE(PagingExample ${SRC_FILES}) +ADD_EXECUTABLE(PagingExample ${SRC_FILES} ${COMMON_RESOURCES_RCC}) IF(MSVC) SET_TARGET_PROPERTIES(PagingExample PROPERTIES COMPILE_FLAGS "/W4 /wd4127") ENDIF(MSVC) TARGET_LINK_LIBRARIES(PagingExample glew ${QT_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} PolyVoxCore) SET_PROPERTY(TARGET PagingExample PROPERTY FOLDER "Examples") +configure_file(../common/example.vert example.vert COPYONLY) +configure_file(../common/example.frag example.frag COPYONLY) + #Install - Only install the example in Windows IF(WIN32) INSTALL(TARGETS PagingExample diff --git a/examples/Paging/OpenGLWidget.cpp b/examples/Paging/OpenGLWidget.cpp deleted file mode 100644 index 0227a66f..00000000 --- a/examples/Paging/OpenGLWidget.cpp +++ /dev/null @@ -1,135 +0,0 @@ -#include "OpenGLWidget.h" - -#include - -using namespace PolyVox; -using namespace std; - -OpenGLWidget::OpenGLWidget(QWidget *parent) - :QGLWidget(parent) - ,m_uBeginIndex(0) - ,m_uEndIndex(0) - ,noOfIndices(0) - ,m_xRotation(0) - ,m_yRotation(0) -{ -} - -void OpenGLWidget::setSurfaceMeshToRender(const PolyVox::SurfaceMesh >& surfaceMesh) -{ - if((surfaceMesh.getNoOfIndices() == 0) || (surfaceMesh.getNoOfVertices() == 0)) - { - //We don't have a valid mesh - return; - } - - //Convienient access to the vertices and indices - const vector& vecIndices = surfaceMesh.getIndices(); - const vector >& vecVertices = surfaceMesh.getVertices(); - - //Build an OpenGL index buffer - glGenBuffers(1, &indexBuffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); - const GLvoid* pIndices = static_cast(&(vecIndices[0])); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), pIndices, GL_STATIC_DRAW); - - //Build an OpenGL vertex buffer - glGenBuffers(1, &vertexBuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); - const GLvoid* pVertices = static_cast(&(vecVertices[0])); - glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(CubicVertex), pVertices, GL_STATIC_DRAW); - - m_uBeginIndex = 0; - m_uEndIndex = vecIndices.size(); - noOfIndices = surfaceMesh.getNoOfIndices(); -} - -void OpenGLWidget::initializeGL() -{ - //We need GLEW to access recent OpenGL functionality - GLenum err = glewInit(); - if (GLEW_OK != err) - { - /* Problem: glewInit failed, something is seriously wrong. */ - std::cout << "GLEW Error: " << glewGetErrorString(err) << std::endl; - } - - //Set up the clear colour - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClearDepth(1.0f); - - //Enable the depth buffer - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - - //Enable smooth lighting - //glEnable(GL_LIGHTING); - //glEnable(GL_LIGHT0); - //glShadeModel(GL_SMOOTH); - - //We'll be rendering with index/vertex arrays - glEnableClientState(GL_VERTEX_ARRAY); - //glEnableClientState(GL_NORMAL_ARRAY); -} - -void OpenGLWidget::resizeGL(int w, int h) -{ - //Setup the viewport - glViewport(0, 0, w, h); - - //Set up the projection matrix - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - float frustumSize = 128.0f * 1.7f; //Half the volume diagonal - float aspect = static_cast(width()) / static_cast(height()); - glOrtho(frustumSize*aspect, -frustumSize*aspect, frustumSize, -frustumSize, 10.0, 10000); -} - -void OpenGLWidget::paintGL() -{ - if(noOfIndices == 0) - { - //Nothing to render - return; - } - - //Clear the screen - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - //Set up the viewing transformation - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.0f,0.0f,-5000.0f); //Centre volume and move back - glRotatef(m_xRotation, 1.0f, 0.0f, 0.0f); - glRotatef(m_yRotation, 0.0f, 1.0f, 0.0f); - glTranslatef(-128.0f,-128.0f,-128.0f); //Centre volume and move back - - //Bind the index buffer - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); - - //Bind the vertex buffer - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); - glVertexPointer(3, GL_FLOAT, sizeof(CubicVertex), 0); - //glNormalPointer(GL_FLOAT, sizeof(CubicVertex), (GLvoid*)12); - - glDrawRangeElements(GL_TRIANGLES, m_uBeginIndex, m_uEndIndex-1, m_uEndIndex - m_uBeginIndex, GL_UNSIGNED_INT, 0); -} - -void OpenGLWidget::mousePressEvent(QMouseEvent* event) -{ - m_CurrentMousePos = event->pos(); - m_LastFrameMousePos = m_CurrentMousePos; - - update(); -} - -void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) -{ - m_CurrentMousePos = event->pos(); - QPoint diff = m_CurrentMousePos - m_LastFrameMousePos; - m_xRotation += diff.x(); - m_yRotation += diff.y(); - m_LastFrameMousePos = m_CurrentMousePos; - - update(); -} diff --git a/examples/Paging/OpenGLWidget.h b/examples/Paging/OpenGLWidget.h deleted file mode 100644 index 61702be1..00000000 --- a/examples/Paging/OpenGLWidget.h +++ /dev/null @@ -1,68 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not -claim that you wrote the original software. If you use this software -in a product, an acknowledgment in the product documentation would be -appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and must not be -misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*******************************************************************************/ - -#ifndef __BasicExample_OpenGLWidget_H__ -#define __BasicExample_OpenGLWidget_H__ - -#include "PolyVoxCore/MaterialDensityPair.h" -#include "PolyVoxCore/SurfaceMesh.h" - -#include "glew/glew.h" - -#include - -class OpenGLWidget : public QGLWidget -{ -public: - //Constructor - OpenGLWidget(QWidget *parent); - - //Mouse handling - void mouseMoveEvent(QMouseEvent* event); - void mousePressEvent(QMouseEvent* event); - - //Convert a SrfaceMesh to OpenGL index/vertex buffers - void setSurfaceMeshToRender(const PolyVox::SurfaceMesh >& surfaceMesh); - -protected: - //Qt OpenGL functions - void initializeGL(); - void resizeGL(int w, int h); - void paintGL(); - -private: - //Index/vertex buffer data - GLuint m_uBeginIndex; - GLuint m_uEndIndex; - GLuint noOfIndices; - GLuint indexBuffer; - GLuint vertexBuffer; - - //Mouse data - QPoint m_LastFrameMousePos; - QPoint m_CurrentMousePos; - int m_xRotation; - int m_yRotation; -}; - -#endif //__BasicExample_OpenGLWidget_H__ diff --git a/examples/Paging/main.cpp b/examples/Paging/main.cpp index b1134fdd..ee2d2d23 100644 --- a/examples/Paging/main.cpp +++ b/examples/Paging/main.cpp @@ -29,7 +29,7 @@ freely, subject to the following restrictions: #include "PolyVoxCore/MarchingCubesSurfaceExtractor.h" #include "PolyVoxCore/Pager.h" #include "PolyVoxCore/RLEBlockCompressor.h" -#include "PolyVoxCore/SurfaceMesh.h" +#include "PolyVoxCore/Mesh.h" #include "PolyVoxCore/LargeVolume.h" #include @@ -185,12 +185,16 @@ int main(int argc, char *argv[]) std::cout << "Memory usage: " << (volData.calculateSizeInBytes()/1024.0/1024.0) << "MB" << std::endl; std::cout << "Compression ratio: 1 to " << (1.0/(volData.calculateCompressionRatio())) << std::endl; - //Extract the surface - auto mesh = extractCubicSurface(&volData, reg); + //Extract the surface + auto mesh = extractCubicMesh(&volData, reg2); std::cout << "#vertices: " << mesh.getNoOfVertices() << std::endl; + auto decodedMesh = decode(mesh); + //Pass the surface to the OpenGL window - openGLWidget.setSurfaceMeshToRender(mesh); + openGLWidget.addMesh(decodedMesh); + + openGLWidget.setViewableRegion(reg2); //Run the message pump. return app.exec(); diff --git a/examples/Python/CMakeLists.txt b/examples/Python/CMakeLists.txt index 1d101d6e..dd7176a7 100644 --- a/examples/Python/CMakeLists.txt +++ b/examples/Python/CMakeLists.txt @@ -21,6 +21,4 @@ PROJECT(PythonExample) -SOURCE_GROUP("Sources" FILES PythonExample.py) - configure_file(PythonExample.py PythonExample.py COPYONLY) diff --git a/examples/SmoothLOD/CMakeLists.txt b/examples/SmoothLOD/CMakeLists.txt index 570cda55..abdc59e5 100644 --- a/examples/SmoothLOD/CMakeLists.txt +++ b/examples/SmoothLOD/CMakeLists.txt @@ -26,7 +26,7 @@ PROJECT(SmoothLODExample) #Projects source files SET(SRC_FILES main.cpp - OpenGLWidget.cpp + ../common/OpenGLWidget.cpp ) #Projects headers files @@ -36,25 +36,29 @@ SET(INC_FILES add_definitions(-DGLEW_STATIC) -#"Sources" and "Headers" are the group names in Visual Studio. -#They may have other uses too... -SOURCE_GROUP("Sources" FILES ${SRC_FILES}) -SOURCE_GROUP("Headers" FILES ${INC_FILES}) - FIND_PACKAGE(OpenGL REQUIRED) #Tell CMake the paths for OpenGL and for PolyVox (which is just relative to our current location) INCLUDE_DIRECTORIES(${OPENGL_INCLUDE_DIR} ${PolyVoxCore_BINARY_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include ${GLEW_SOURCE_DIR}) LINK_DIRECTORIES(${PolyVoxCore_BINARY_DIR}) +#This will include the shader files inside the compiled binary +QT4_ADD_RESOURCES(COMMON_RESOURCES_RCC ../common/example.qrc) + +# Put the resources in a seperate folder in Visual Studio +SOURCE_GROUP("Resource Files" FILES ../common/example.qrc ${COMMON_RESOURCES_RCC}) + #Build -ADD_EXECUTABLE(SmoothLODExample ${SRC_FILES}) +ADD_EXECUTABLE(SmoothLODExample ${SRC_FILES} ${COMMON_RESOURCES_RCC}) IF(MSVC) SET_TARGET_PROPERTIES(SmoothLODExample PROPERTIES COMPILE_FLAGS "/W4 /wd4127") #All warnings ENDIF(MSVC) TARGET_LINK_LIBRARIES(SmoothLODExample glew ${QT_LIBRARIES} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} PolyVoxCore) SET_PROPERTY(TARGET SmoothLODExample PROPERTY FOLDER "Examples") +configure_file(../common/example.vert example.vert COPYONLY) +configure_file(../common/example.frag example.frag COPYONLY) + #Install - Only install the example in Windows IF(WIN32) INSTALL(TARGETS SmoothLODExample diff --git a/examples/SmoothLOD/OpenGLWidget.cpp b/examples/SmoothLOD/OpenGLWidget.cpp deleted file mode 100644 index e804240b..00000000 --- a/examples/SmoothLOD/OpenGLWidget.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include "OpenGLWidget.h" - -#include - -using namespace PolyVox; -using namespace std; - -OpenGLWidget::OpenGLWidget(QWidget *parent) - :QGLWidget(parent) - ,m_uBeginIndex(0) - ,m_uEndIndex(0) - ,indexBuffer(0) - ,vertexBuffer(0) - - ,m_uBeginIndexLow(0) - ,m_uEndIndexLow(0) - ,indexBufferLow(0) - ,vertexBufferLow(0) - ,m_xRotation(0) - ,m_yRotation(0) -{ -} - -void OpenGLWidget::setSurfaceMeshToRender(const PolyVox::SurfaceMesh >& surfaceMesh) -{ - //Convienient access to the vertices and indices - const vector& vecIndices = surfaceMesh.getIndices(); - const vector >& vecVertices = surfaceMesh.getVertices(); - - //Build an OpenGL index buffer - glGenBuffers(1, &indexBuffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); - const GLvoid* pIndices = static_cast(&(vecIndices[0])); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), pIndices, GL_STATIC_DRAW); - - //Build an OpenGL vertex buffer - glGenBuffers(1, &vertexBuffer); - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); - const GLvoid* pVertices = static_cast(&(vecVertices[0])); - glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(MarchingCubesVertex), pVertices, GL_STATIC_DRAW); - - m_uBeginIndex = 0; - m_uEndIndex = vecIndices.size(); -} - -void OpenGLWidget::setSurfaceMeshToRenderLowLOD(const PolyVox::SurfaceMesh >& surfaceMesh) -{ - //Convienient access to the vertices and indices - const vector& vecIndices = surfaceMesh.getIndices(); - const vector >& vecVertices = surfaceMesh.getVertices(); - - //Build an OpenGL index buffer - glGenBuffers(1, &indexBufferLow); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferLow); - const GLvoid* pIndices = static_cast(&(vecIndices[0])); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), pIndices, GL_STATIC_DRAW); - - //Build an OpenGL vertex buffer - glGenBuffers(1, &vertexBufferLow); - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferLow); - const GLvoid* pVertices = static_cast(&(vecVertices[0])); - glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(MarchingCubesVertex), pVertices, GL_STATIC_DRAW); - - m_uBeginIndexLow = 0; - m_uEndIndexLow = vecIndices.size(); -} - -void OpenGLWidget::initializeGL() -{ - //We need GLEW to access recent OpenGL functionality - std::cout << "Initialising GLEW..."; - GLenum result = glewInit(); - if (result == GLEW_OK) - { - std::cout << "success" << std::endl; - } - else - { - /* Problem: glewInit failed, something is seriously wrong. */ - std::cout << "failed" << std::endl; - std::cout << "Initialising GLEW failed with the following error: " << glewGetErrorString(result) << std::endl; - exit(EXIT_FAILURE); - } - - //Print out some information about the OpenGL implementation. - std::cout << "OpenGL Implementation Details:" << std::endl; - if(glGetString(GL_VENDOR)) - std::cout << "\tGL_VENDOR: " << glGetString(GL_VENDOR) << std::endl; - if(glGetString(GL_RENDERER)) - std::cout << "\tGL_RENDERER: " << glGetString(GL_RENDERER) << std::endl; - if(glGetString(GL_VERSION)) - std::cout << "\tGL_VERSION: " << glGetString(GL_VERSION) << std::endl; - if(glGetString(GL_SHADING_LANGUAGE_VERSION)) - std::cout << "\tGL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; - - //Check our version of OpenGL is recent enough. - //We need at least 1.5 for vertex buffer objects, - if (!GLEW_VERSION_1_5) - { - std::cout << "Error: You need OpenGL version 1.5 to run this example." << std::endl; - exit(EXIT_FAILURE); - } - - //Set up the clear colour - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClearDepth(1.0f); - - //Enable the depth buffer - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LEQUAL); - - //Anable smooth lighting - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glShadeModel(GL_SMOOTH); - - //We'll be rendering with index/vertex arrays - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - - glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); -} - -void OpenGLWidget::resizeGL(int w, int h) -{ - //Setup the viewport - glViewport(0, 0, w, h); - - //Set up the projection matrix - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - float frustumSize = 32.0f; //Half the volume size - float aspect = static_cast(width()) / static_cast(height()); - glOrtho(frustumSize*aspect, -frustumSize*aspect, frustumSize, -frustumSize, 1.0, 1000); -} - -void OpenGLWidget::paintGL() -{ - //Clear the screen - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - //Set up the viewing transformation - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.0f,0.0f,-100.0f); //Centre volume and move back - glRotatef(-m_xRotation, 0.0f, 1.0f, 0.0f); - glRotatef(-m_yRotation, 1.0f, 0.0f, 0.0f); - glTranslatef(-32.0f,-32.0f,-32.0f); //Centre volume and move back - - //Bind the index buffer - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); - - //Bind the vertex buffer - glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); - glVertexPointer(3, GL_FLOAT, sizeof(MarchingCubesVertex), 0); - glNormalPointer(GL_FLOAT, sizeof(MarchingCubesVertex), (GLvoid*)12); - - glDrawRangeElements(GL_TRIANGLES, m_uBeginIndex, m_uEndIndex-1, m_uEndIndex - m_uBeginIndex, GL_UNSIGNED_INT, 0); - - //Bind the index buffer - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferLow); - - //Bind the vertex buffer - glBindBuffer(GL_ARRAY_BUFFER, vertexBufferLow); - glVertexPointer(3, GL_FLOAT, sizeof(MarchingCubesVertex), 0); - glNormalPointer(GL_FLOAT, sizeof(MarchingCubesVertex), (GLvoid*)12); - - glDrawRangeElements(GL_TRIANGLES, m_uBeginIndexLow, m_uEndIndexLow-1, m_uEndIndexLow - m_uBeginIndexLow, GL_UNSIGNED_INT, 0); - - GLenum errCode = glGetError(); - if(errCode != GL_NO_ERROR) - { - //What has replaced getErrorString() in the latest OpenGL? - std::cout << "OpenGL Error: " << errCode << std::endl; - } -} - -void OpenGLWidget::mousePressEvent(QMouseEvent* event) -{ - m_CurrentMousePos = event->pos(); - m_LastFrameMousePos = m_CurrentMousePos; - - update(); -} - -void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) -{ - m_CurrentMousePos = event->pos(); - QPoint diff = m_CurrentMousePos - m_LastFrameMousePos; - m_xRotation += diff.x(); - m_yRotation += diff.y(); - m_LastFrameMousePos = m_CurrentMousePos; - - update(); -} diff --git a/examples/SmoothLOD/OpenGLWidget.h b/examples/SmoothLOD/OpenGLWidget.h deleted file mode 100644 index 895e9e74..00000000 --- a/examples/SmoothLOD/OpenGLWidget.h +++ /dev/null @@ -1,74 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - -1. The origin of this software must not be misrepresented; you must not -claim that you wrote the original software. If you use this software -in a product, an acknowledgment in the product documentation would be -appreciated but is not required. - -2. Altered source versions must be plainly marked as such, and must not be -misrepresented as being the original software. - -3. This notice may not be removed or altered from any source -distribution. -*******************************************************************************/ - -#ifndef __BasicExample_OpenGLWidget_H__ -#define __BasicExample_OpenGLWidget_H__ - -#include "PolyVoxCore/SurfaceMesh.h" - -#include "glew/glew.h" - -#include - -class OpenGLWidget : public QGLWidget -{ -public: - //Constructor - OpenGLWidget(QWidget *parent); - - //Mouse handling - void mouseMoveEvent(QMouseEvent* event); - void mousePressEvent(QMouseEvent* event); - - //Convert a SrfaceMesh to OpenGL index/vertex buffers - void setSurfaceMeshToRender(const PolyVox::SurfaceMesh >& surfaceMesh); - void setSurfaceMeshToRenderLowLOD(const PolyVox::SurfaceMesh >& surfaceMesh); - -protected: - //Qt OpenGL functions - void initializeGL(); - void resizeGL(int w, int h); - void paintGL(); - -private: - //Index/vertex buffer data - GLuint m_uBeginIndex; - GLuint m_uEndIndex; - //GLuint noOfIndices; - GLuint indexBuffer; - GLuint vertexBuffer; - - GLuint m_uBeginIndexLow; - GLuint m_uEndIndexLow; - //GLuint noOfIndicesLow; - GLuint indexBufferLow; - GLuint vertexBufferLow; - - //Mouse data - QPoint m_LastFrameMousePos; - QPoint m_CurrentMousePos; - int m_xRotation; - int m_yRotation; -}; - -#endif //__BasicExample_OpenGLWidget_H__ diff --git a/examples/SmoothLOD/main.cpp b/examples/SmoothLOD/main.cpp index 2e97c876..01c2fdaf 100644 --- a/examples/SmoothLOD/main.cpp +++ b/examples/SmoothLOD/main.cpp @@ -25,7 +25,7 @@ freely, subject to the following restrictions: #include "PolyVoxCore/Density.h" #include "PolyVoxCore/MarchingCubesSurfaceExtractor.h" -#include "PolyVoxCore/SurfaceMesh.h" +#include "PolyVoxCore/Mesh.h" #include "PolyVoxCore/RawVolume.h" #include "PolyVoxCore/SimpleVolume.h" #include "PolyVoxCore/VolumeResampler.h" @@ -89,17 +89,21 @@ int main(int argc, char *argv[]) VolumeResampler< SimpleVolume, RawVolume > volumeResampler(&volData, PolyVox::Region(Vector3DInt32(0,0,0), Vector3DInt32(31, 63, 63)), &volDataLowLOD, volDataLowLOD.getEnclosingRegion()); volumeResampler.execute(); - //Extract the surface - auto meshLowLOD = extractMarchingCubesSurface(&volDataLowLOD, volDataLowLOD.getEnclosingRegion()); - meshLowLOD.scaleVertices(/*2.0f*/63.0f / 31.0f); + //Extract the surface + auto meshLowLOD = extractMarchingCubesMesh(&volDataLowLOD, volDataLowLOD.getEnclosingRegion()); + // The returned mesh needs to be decoded to be appropriate for GPU rendering. + auto decodedMeshLowLOD = decode(meshLowLOD); //Extract the surface - auto meshHighLOD = extractMarchingCubesSurface(&volData, PolyVox::Region(Vector3DInt32(30, 0, 0), Vector3DInt32(63, 63, 63))); - meshHighLOD.translateVertices(Vector3DFloat(30, 0, 0)); + auto meshHighLOD = extractMarchingCubesMesh(&volData, PolyVox::Region(Vector3DInt32(30, 0, 0), Vector3DInt32(63, 63, 63))); + // The returned mesh needs to be decoded to be appropriate for GPU rendering. + auto decodedMeshHighLOD = decode(meshHighLOD); //Pass the surface to the OpenGL window - openGLWidget.setSurfaceMeshToRender(meshHighLOD); - openGLWidget.setSurfaceMeshToRenderLowLOD(meshLowLOD); + openGLWidget.addMesh(decodedMeshHighLOD, Vector3DInt32(30, 0, 0)); + openGLWidget.addMesh(decodedMeshLowLOD, Vector3DInt32(0, 0, 0), 63.0f / 31.0f); + + openGLWidget.setViewableRegion(volData.getEnclosingRegion()); //Run the message pump. return app.exec(); diff --git a/examples/common/OpenGLWidget.cpp b/examples/common/OpenGLWidget.cpp new file mode 100644 index 00000000..439264bf --- /dev/null +++ b/examples/common/OpenGLWidget.cpp @@ -0,0 +1,196 @@ +#include "OpenGLWidget.h" + +#include +#include +#include +//#include + +using namespace PolyVox; +using namespace std; + +//////////////////////////////////////////////////////////////////////////////// +// Public functions +//////////////////////////////////////////////////////////////////////////////// +OpenGLWidget::OpenGLWidget(QWidget *parent) + :QGLWidget(parent) + ,m_viewableRegion(PolyVox::Region(0, 0, 0, 255, 255, 255)) + ,m_xRotation(0) + ,m_yRotation(0) +{ +} + +void OpenGLWidget::setShader(QSharedPointer shader) +{ + mShader = shader; +} + +void OpenGLWidget::setViewableRegion(PolyVox::Region viewableRegion) +{ + m_viewableRegion = viewableRegion; + + // The user has specifed a new viewable region + // so we need to regenerate our camera matrix. + setupWorldToCameraMatrix(); +} + +void OpenGLWidget::mousePressEvent(QMouseEvent* event) +{ + // Initialise these variables which will be used when the mouse actually moves. + m_CurrentMousePos = event->pos(); + m_LastFrameMousePos = m_CurrentMousePos; +} + +void OpenGLWidget::mouseMoveEvent(QMouseEvent* event) +{ + // Update the x and y rotations based on the mouse movement. + m_CurrentMousePos = event->pos(); + QPoint diff = m_CurrentMousePos - m_LastFrameMousePos; + m_xRotation += diff.x(); + m_yRotation += diff.y(); + m_LastFrameMousePos = m_CurrentMousePos; + + // The camera rotation has changed so we need to regenerate the matrix. + setupWorldToCameraMatrix(); + + // Re-render. + update(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Protected functions +//////////////////////////////////////////////////////////////////////////////// +void OpenGLWidget::initializeGL() +{ + GLenum err = glewInit(); + if (GLEW_OK != err) + { + /* Problem: glewInit failed, something is seriously wrong. */ + std::cout << "GLEW Error: " << glewGetErrorString(err) << std::endl; + } + + //Print out some information about the OpenGL implementation. + std::cout << "OpenGL Implementation Details:" << std::endl; + if(glGetString(GL_VENDOR)) + std::cout << "\tGL_VENDOR: " << glGetString(GL_VENDOR) << std::endl; + if(glGetString(GL_RENDERER)) + std::cout << "\tGL_RENDERER: " << glGetString(GL_RENDERER) << std::endl; + if(glGetString(GL_VERSION)) + std::cout << "\tGL_VERSION: " << glGetString(GL_VERSION) << std::endl; + if(glGetString(GL_SHADING_LANGUAGE_VERSION)) + std::cout << "\tGL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl; + + //Set up the clear colour + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0f); + + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glDepthFunc(GL_LEQUAL); + glDepthRange(0.0, 1.0); + + mShader = QSharedPointer(new QGLShaderProgram); + + // This is basically a simple fallback vertex shader which does the most basic rendering possible. + // PolyVox examples are able to provide their own shaders to demonstrate certain effects if desired. + if (!mShader->addShaderFromSourceFile(QGLShader::Vertex, ":/example.vert")) + { + std::cerr << mShader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + // This is basically a simple fallback fragment shader which does the most basic rendering possible. + // PolyVox examples are able to provide their own shaders to demonstrate certain effects if desired. + if (!mShader->addShaderFromSourceFile(QGLShader::Fragment, ":/example.frag")) + { + std::cerr << mShader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + // Bind the position semantic - this is defined in the vertex shader above. + mShader->bindAttributeLocation("position", 0); + + // Bind the other semantics. Note that these don't actually exist in our example shader above! However, other + // example shaders may choose to provide them and having the binding code here does not seem to cause any problems. + mShader->bindAttributeLocation("normal", 1); + mShader->bindAttributeLocation("material", 2); + + if (!mShader->link()) + { + std::cerr << mShader->log().toStdString() << std::endl; + exit(EXIT_FAILURE); + } + + // Initial setup of camera. + setupWorldToCameraMatrix(); +} + +void OpenGLWidget::resizeGL(int w, int h) +{ + //Setup the viewport + glViewport(0, 0, w, h); + + auto aspectRatio = w / (float)h; + float zNear = 1.0; + float zFar = 1000.0; + + cameraToClipMatrix.setToIdentity(); + cameraToClipMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar); +} + +void OpenGLWidget::paintGL() +{ + //Clear the screen + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // Our example framework only uses a single shader for the scene (for all meshes). + mShader->bind(); + + // These two matrices are constant for all meshes. + mShader->setUniformValue("worldToCameraMatrix", worldToCameraMatrix); + mShader->setUniformValue("cameraToClipMatrix", cameraToClipMatrix); + + // Iterate over each mesh which the user added to our list, and render it. + for (OpenGLMeshData meshData : mMeshData) + { + //Set up the model matrrix based on provided translation and scale. + QMatrix4x4 modelToWorldMatrix; + modelToWorldMatrix.translate(meshData.translation); + modelToWorldMatrix.scale(meshData.scale); + mShader->setUniformValue("modelToWorldMatrix", modelToWorldMatrix); + + // Bind the vertex array for the current mesh + glBindVertexArray(meshData.vertexArrayObject); + // Draw the mesh + glDrawElements(GL_TRIANGLES, meshData.noOfIndices, GL_UNSIGNED_INT, 0); + // Unbind the vertex array. + glBindVertexArray(0); + } + + // We're done with the shader for this frame. + mShader->release(); + + // Check for errors. + GLenum errCode = glGetError(); + if(errCode != GL_NO_ERROR) + { + std::cerr << "OpenGL Error: " << errCode << std::endl; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Private functions +//////////////////////////////////////////////////////////////////////////////// +void OpenGLWidget::setupWorldToCameraMatrix() +{ + QVector3D lowerCorner(m_viewableRegion.getLowerX(), m_viewableRegion.getLowerY(), m_viewableRegion.getLowerZ()); + QVector3D upperCorner(m_viewableRegion.getUpperX(), m_viewableRegion.getUpperY(), m_viewableRegion.getUpperZ()); + + QVector3D centerPoint = (lowerCorner + upperCorner) * 0.5; + float fDiagonalLength = (upperCorner - lowerCorner).length(); + + worldToCameraMatrix.setToIdentity(); + worldToCameraMatrix.translate(0, 0, -fDiagonalLength / 2.0f); //Move the camera back by the required amount + worldToCameraMatrix.rotate(m_xRotation, 0, 1, 0); //rotate around y-axis + worldToCameraMatrix.rotate(m_yRotation, 1, 0, 0); //rotate around x-axis + worldToCameraMatrix.translate(-centerPoint); //centre the model on the origin +} \ No newline at end of file diff --git a/examples/common/OpenGLWidget.h b/examples/common/OpenGLWidget.h new file mode 100644 index 00000000..1bbbc1e4 --- /dev/null +++ b/examples/common/OpenGLWidget.h @@ -0,0 +1,156 @@ +/******************************************************************************* +Copyright (c) 2005-2009 David Williams + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be +misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*******************************************************************************/ + +#ifndef __BasicExample_OpenGLWidget_H__ +#define __BasicExample_OpenGLWidget_H__ + +#include "PolyVoxCore/Mesh.h" + +#include "glew/glew.h" + +#include +#include + +// This structure holds all the data required +// to render one of our meshes through OpenGL. +struct OpenGLMeshData +{ + GLuint noOfIndices; + GLuint indexBuffer; + GLuint vertexBuffer; + GLuint vertexArrayObject; + QVector3D translation; + float scale; +}; + +// Our OpenGLWidget is used by all the examples to render the extracted meshes. It is +// fairly specific to our needs (you probably won't want to use it in your own project) +// but should provide a useful illustration of how PolyVox meshes can be rendered. +class OpenGLWidget : public QGLWidget +{ +public: + // Constructor + OpenGLWidget(QWidget *parent); + + // Convert a PolyVox mesh to OpenGL index/vertex buffers. Inlined because it's templatised. + template + void addMesh(const PolyVox::Mesh< PolyVox::Vertex< DataType > >& surfaceMesh, const PolyVox::Vector3DInt32& translation = PolyVox::Vector3DInt32(0, 0, 0), float scale = 1.0f) + { + // Convienient access to the vertices and indices + const auto& vecIndices = surfaceMesh.getIndices(); + const auto& vecVertices = surfaceMesh.getVertices(); + + // This struct holds the OpenGL properties (buffer handles, etc) which will be used + // to render our mesh. We copy the data from the PolyVox mesh into this structure. + OpenGLMeshData meshData; + + // Create the VAO for the mesh + glGenVertexArrays(1, &(meshData.vertexArrayObject)); + glBindVertexArray(meshData.vertexArrayObject); + + // The GL_ARRAY_BUFFER will contain the list of vertex positions + glGenBuffers(1, &(meshData.vertexBuffer)); + glBindBuffer(GL_ARRAY_BUFFER, meshData.vertexBuffer); + glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof(PolyVox::Vertex< DataType >), vecVertices.data(), GL_STATIC_DRAW); + + // and GL_ELEMENT_ARRAY_BUFFER will contain the indices + glGenBuffers(1, &(meshData.indexBuffer)); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshData.indexBuffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, vecIndices.size() * sizeof(uint32_t), vecIndices.data(), GL_STATIC_DRAW); + + // Every surface extractor outputs valid positions for the vertices, so tell OpenGL how these are laid out + glEnableVertexAttribArray(0); // Attrib '0' is the vertex positions + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(PolyVox::Vertex< DataType >), (GLvoid*)(offsetof(PolyVox::Vertex< DataType >, position))); //take the first 3 floats from every sizeof(decltype(vecVertices)::value_type) + + // Some surface extractors also generate normals, so tell OpenGL how these are laid out. If a surface extractor + // does not generate normals then nonsense values are written into the buffer here and sghould be ignored by the + // shader. This is mostly just to simplify this example code - in a real application you will know whether your + // chosen surface extractor generates normals and can skip uploading them if not. + glEnableVertexAttribArray(1); // Attrib '1' is the vertex normals. + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(PolyVox::Vertex< DataType >), (GLvoid*)(offsetof(PolyVox::Vertex< DataType >, normal))); + + // Finally a surface extractor will probably output additional data. This is highly application dependant. For this example code + // we're just uploading it as a set of bytes which we can read individually, but real code will want to do something specialised here. + glEnableVertexAttribArray(2); //We're talking about shader attribute '2' + GLint size = (std::min)(sizeof(DataType), size_t(4)); // Can't upload more that 4 components (vec4 is GLSL's biggest type) + glVertexAttribIPointer(2, size, GL_UNSIGNED_BYTE, sizeof(PolyVox::Vertex< DataType >), (GLvoid*)(offsetof(PolyVox::Vertex< DataType >, data))); + + // We're done uploading and can now unbind. + glBindVertexArray(0); + + // A few additional properties can be copied across for use during rendering. + meshData.noOfIndices = vecIndices.size(); + meshData.translation = QVector3D(translation.getX(), translation.getY(), translation.getZ()); + meshData.scale = scale; + + // Now add the mesh to the list of meshes to render. + addMeshData(meshData); + } + + void addMeshData(OpenGLMeshData meshData) + { + mMeshData.push_back(meshData); + } + + // For our purposes we use a single shader for the whole volume, and + // this example framework is only meant to show a single volume at a time + void setShader(QSharedPointer shader); + + // The viewable region can be adjusted so that this example framework can be used for different volume sizes. + void setViewableRegion(PolyVox::Region viewableRegion); + + // Mouse handling + void mouseMoveEvent(QMouseEvent* event); + void mousePressEvent(QMouseEvent* event); + +protected: + + // Qt OpenGL functions + void initializeGL(); + void resizeGL(int w, int h); + void paintGL(); + +private: + + void setupWorldToCameraMatrix(); + + // Index/vertex buffer data + std::vector mMeshData; + + QSharedPointer mShader; + + // Matrices + QMatrix4x4 worldToCameraMatrix; + QMatrix4x4 cameraToClipMatrix; + + // Mouse data + QPoint m_LastFrameMousePos; + QPoint m_CurrentMousePos; + + // Camera setup + PolyVox::Region m_viewableRegion; + int m_xRotation; + int m_yRotation; +}; + +#endif //__BasicExample_OpenGLWidget_H__ diff --git a/examples/common/example.frag b/examples/common/example.frag new file mode 100644 index 00000000..c9cbf215 --- /dev/null +++ b/examples/common/example.frag @@ -0,0 +1,19 @@ +#version 130 + +// Passed in from the vertex shader +in vec4 worldPosition; +in vec4 worldNormal; + +// the color that gets written to the display +out vec4 outputColor; + +void main() +{ + // Again, for the purposes of these examples we cannot be sure that per-vertex normals are provided. A sensible fallback + // is to use this little trick to compute per-fragment flat-shaded normals from the world positions using derivative operations. + vec3 normal = normalize(cross(dFdy(worldPosition.xyz), dFdx(worldPosition.xyz))); + + // We are just using the normal as the output color, and making it lighter so it looks a bit nicer. + // Obviously a real shader would also do texuring, lighting, or whatever is required for the application. + outputColor = vec4(abs(normal) * 0.5 + vec3(0.5, 0.5, 0.5), 1.0); +} diff --git a/examples/common/example.qrc b/examples/common/example.qrc new file mode 100644 index 00000000..8efd5747 --- /dev/null +++ b/examples/common/example.qrc @@ -0,0 +1,6 @@ + + + example.vert + example.frag + + diff --git a/examples/common/example.vert b/examples/common/example.vert new file mode 100644 index 00000000..94d35f44 --- /dev/null +++ b/examples/common/example.vert @@ -0,0 +1,20 @@ +#version 140 + +in vec4 position; // This will be the position of the vertex in model-space + +// The usual matrices are provided +uniform mat4 cameraToClipMatrix; +uniform mat4 worldToCameraMatrix; +uniform mat4 modelToWorldMatrix; + +// This will be used by the fragment shader to calculate flat-shaded normals. This is an unconventional approach +// but we use it in this example framework because not all surface extractor generate surface normals. +out vec4 worldPosition; + +void main() +{ + // Standard sequence of OpenGL transformations. + worldPosition = modelToWorldMatrix * position; + vec4 cameraPosition = worldToCameraMatrix * worldPosition; + gl_Position = cameraToClipMatrix * cameraPosition; +} diff --git a/library/PolyVoxCore/CMakeLists.txt b/library/PolyVoxCore/CMakeLists.txt index e4289feb..db5caaa8 100644 --- a/library/PolyVoxCore/CMakeLists.txt +++ b/library/PolyVoxCore/CMakeLists.txt @@ -27,7 +27,6 @@ SET(CORE_SRC_FILES source/ArraySizes.cpp source/AStarPathfinder.cpp source/Region.cpp - source/VertexTypes.cpp ) #Projects headers files @@ -66,6 +65,8 @@ SET(CORE_INC_FILES include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl include/PolyVoxCore/Material.h include/PolyVoxCore/MaterialDensityPair.h + include/PolyVoxCore/Mesh.h + include/PolyVoxCore/Mesh.inl include/PolyVoxCore/MinizBlockCompressor.h include/PolyVoxCore/MinizBlockCompressor.inl include/PolyVoxCore/Pager.h @@ -84,13 +85,11 @@ SET(CORE_INC_FILES include/PolyVoxCore/SimpleVolume.inl include/PolyVoxCore/SimpleVolumeBlock.inl include/PolyVoxCore/SimpleVolumeSampler.inl - include/PolyVoxCore/SurfaceMesh.h - include/PolyVoxCore/SurfaceMesh.inl include/PolyVoxCore/UncompressedBlock.h include/PolyVoxCore/UncompressedBlock.inl include/PolyVoxCore/Vector.h include/PolyVoxCore/Vector.inl - include/PolyVoxCore/VertexTypes.h + include/PolyVoxCore/Vertex.h include/PolyVoxCore/VolumeResampler.h include/PolyVoxCore/VolumeResampler.inl include/PolyVoxCore/VoxelFilters.h @@ -130,11 +129,11 @@ SET(IMPL_INC_FILES #"Sources" and "Headers" are the group names in Visual Studio. #They may have other uses too... -SOURCE_GROUP("Sources" FILES ${CORE_SRC_FILES}) -SOURCE_GROUP("Headers" FILES ${CORE_INC_FILES}) +SOURCE_GROUP("Source Files" FILES ${CORE_SRC_FILES}) +SOURCE_GROUP("Header Files" FILES ${CORE_INC_FILES}) -SOURCE_GROUP("Sources\\Impl" FILES ${IMPL_SRC_FILES}) -SOURCE_GROUP("Headers\\Impl" FILES ${IMPL_INC_FILES}) +SOURCE_GROUP("Source Files\\Impl" FILES ${IMPL_SRC_FILES}) +SOURCE_GROUP("Header Files\\Impl" FILES ${IMPL_INC_FILES}) #Tell CMake the paths INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h index b4493d29..71571038 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h @@ -31,10 +31,47 @@ freely, subject to the following restrictions: #include "PolyVoxCore/Array.h" #include "PolyVoxCore/BaseVolume.h" //For wrap modes... should move these? #include "PolyVoxCore/DefaultIsQuadNeeded.h" -#include "PolyVoxCore/SurfaceMesh.h" +#include "PolyVoxCore/Mesh.h" +#include "PolyVoxCore/Vertex.h" namespace PolyVox { +#ifdef SWIG + struct CubicVertex +#else + template + struct POLYVOX_API CubicVertex +#endif + { + typedef _DataType DataType; + + // Each component of the position is stored as a single unsigned byte. + // The true position is found by offseting each component by 0.5f. + Vector3DUint8 encodedPosition; + + // User data + DataType data; + }; + + /// Decodes a position from a CubicVertex + inline Vector3DFloat decode(const Vector3DUint8& encodedPosition) + { + Vector3DFloat result(encodedPosition.getX(), encodedPosition.getY(), encodedPosition.getZ()); + result -= 0.5f; // Apply the required offset + return result; + } + + /// Decodes a MarchingCubesVertex by converting it into a regular Vertex which can then be directly used for rendering. + template + Vertex decode(const CubicVertex& cubicVertex) + { + Vertex result; + result.position = decode(cubicVertex.encodedPosition); + result.normal.setElements(0.0f, 0.0f, 0.0f); // Currently not calculated + result.data = cubicVertex.data; // Data is not encoded + return result; + } + /// The CubicSurfaceExtractor creates a mesh in which each voxel appears to be rendered as a cube //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// Introduction @@ -76,7 +113,7 @@ namespace PolyVox /// /// Another scenario which sometimes results in confusion is when you wish to extract a region which corresponds to the whole volume, partcularly when solid voxels extend right to the edge of the volume. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - template + template class CubicSurfaceExtractor { struct IndexAndMaterial @@ -113,9 +150,9 @@ namespace PolyVox // This is a bit ugly - it seems that the C++03 syntax is different from the C++11 syntax? See this thread: http://stackoverflow.com/questions/6076015/typename-outside-of-template // Long term we should probably come back to this and if the #ifdef is still needed then maybe it should check for C++11 mode instead of MSVC? #if defined(_MSC_VER) - CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType(), bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded()); + CubicSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType(), bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded()); #else - CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded()); + CubicSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded()); #endif @@ -135,7 +172,7 @@ namespace PolyVox Region m_regSizeInVoxels; //The surface patch we are currently filling. - SurfaceMesh >* m_meshCurrent; + MeshType* m_meshCurrent; //Used to avoid creating duplicate vertices. Array<3, IndexAndMaterial> m_previousSliceVertices; @@ -159,10 +196,11 @@ namespace PolyVox }; template - SurfaceMesh > extractCubicSurface(VolumeType* volData, Region region, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, bool bMergeQuads, IsQuadNeeded isQuadNeeded) + Mesh > extractCubicMesh(VolumeType* volData, Region region, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, bool bMergeQuads, IsQuadNeeded isQuadNeeded) { - SurfaceMesh > result; - CubicSurfaceExtractor extractor(volData, region, &result, eWrapMode, tBorderValue, bMergeQuads, isQuadNeeded); + typedef Mesh > MeshType; + MeshType result; + CubicSurfaceExtractor extractor(volData, region, &result, eWrapMode, tBorderValue, bMergeQuads, isQuadNeeded); extractor.execute(); return result; } @@ -171,13 +209,13 @@ namespace PolyVox // This is a bit ugly - it seems that the C++03 syntax is different from the C++11 syntax? See this thread: http://stackoverflow.com/questions/6076015/typename-outside-of-template // Long term we should probably come back to this and if the #ifdef is still needed then maybe it should check for C++11 mode instead of MSVC? #if defined(_MSC_VER) - SurfaceMesh > extractCubicSurface(VolumeType* volData, Region region, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType(), bool bMergeQuads = true) + Mesh > extractCubicMesh(VolumeType* volData, Region region, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType(), bool bMergeQuads = true) #else - SurfaceMesh > extractCubicSurface(VolumeType* volData, Region region, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true) + Mesh > extractCubicMesh(VolumeType* volData, Region region, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true) #endif { DefaultIsQuadNeeded isQuadNeeded; - return extractCubicSurface >(volData, region, eWrapMode, tBorderValue, bMergeQuads, isQuadNeeded); + return extractCubicMesh >(volData, region, eWrapMode, tBorderValue, bMergeQuads, isQuadNeeded); } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl index 822b9256..6ebec5ef 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl @@ -32,11 +32,11 @@ namespace PolyVox // happens when we have a 2x2x2 group of voxels, all with different materials and some/all partially transparent. // The vertex position at the center of this group is then going to be used by all eight voxels all with different // materials. - template - const uint32_t CubicSurfaceExtractor::MaxVerticesPerPosition = 8; + template + const uint32_t CubicSurfaceExtractor::MaxVerticesPerPosition = 8; - template - CubicSurfaceExtractor::CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, bool bMergeQuads, IsQuadNeeded isQuadNeeded) + template + CubicSurfaceExtractor::CubicSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, bool bMergeQuads, IsQuadNeeded isQuadNeeded) :m_volData(volData) ,m_regSizeInVoxels(region) ,m_meshCurrent(result) @@ -45,10 +45,16 @@ namespace PolyVox ,m_tBorderValue(tBorderValue) { m_funcIsQuadNeededCallback = isQuadNeeded; + + // This extractor has a limit as to how large the extracted region can be, because the vertex positions are encoded with a single byte per component. + int32_t maxReionDimension = 256; + POLYVOX_THROW_IF(region.getWidthInVoxels() > maxReionDimension, std::invalid_argument, "Requested extraction region exceeds maximum dimensions"); + POLYVOX_THROW_IF(region.getHeightInVoxels() > maxReionDimension, std::invalid_argument, "Requested extraction region exceeds maximum dimensions"); + POLYVOX_THROW_IF(region.getDepthInVoxels() > maxReionDimension, std::invalid_argument, "Requested extraction region exceeds maximum dimensions"); } - template - void CubicSurfaceExtractor::execute() + template + void CubicSurfaceExtractor::execute() { Timer timer; m_meshCurrent->clear(); @@ -184,28 +190,22 @@ namespace PolyVox for(typename std::list::iterator quadIter = listQuads.begin(); quadIter != iterEnd; quadIter++) { Quad& quad = *quadIter; - m_meshCurrent->addTriangleCubic(quad.vertices[0], quad.vertices[1],quad.vertices[2]); - m_meshCurrent->addTriangleCubic(quad.vertices[0], quad.vertices[2],quad.vertices[3]); + m_meshCurrent->addTriangle(quad.vertices[0], quad.vertices[1],quad.vertices[2]); + m_meshCurrent->addTriangle(quad.vertices[0], quad.vertices[2],quad.vertices[3]); } } } - m_meshCurrent->m_Region = m_regSizeInVoxels; + m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); m_meshCurrent->removeUnusedVertices(); - m_meshCurrent->m_vecLodRecords.clear(); - LodRecord lodRecord; - lodRecord.beginIndex = 0; - lodRecord.endIndex = m_meshCurrent->getNoOfIndices(); - m_meshCurrent->m_vecLodRecords.push_back(lodRecord); - POLYVOX_LOG_TRACE("Cubic surface extraction took " << timer.elapsedTimeInMilliSeconds() << "ms (Region size = " << m_regSizeInVoxels.getWidthInVoxels() << "x" << m_regSizeInVoxels.getHeightInVoxels() << "x" << m_regSizeInVoxels.getDepthInVoxels() << ")"); } - template - int32_t CubicSurfaceExtractor::addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, typename VolumeType::VoxelType uMaterialIn, Array<3, IndexAndMaterial>& existingVertices) + template + int32_t CubicSurfaceExtractor::addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, typename VolumeType::VoxelType uMaterialIn, Array<3, IndexAndMaterial>& existingVertices) { for(uint32_t ct = 0; ct < MaxVerticesPerPosition; ct++) { @@ -214,7 +214,10 @@ namespace PolyVox if(rEntry.iIndex == -1) { //No vertices matched and we've now hit an empty space. Fill it by creating a vertex. The 0.5f offset is because vertices set between voxels in order to build cubes around them. - rEntry.iIndex = m_meshCurrent->addVertex(CubicVertex(Vector3DFloat(static_cast(uX)-0.5f, static_cast(uY)-0.5f, static_cast(uZ)-0.5f), uMaterialIn)); + CubicVertex cubicVertex; + cubicVertex.encodedPosition.setElements(static_cast(uX), static_cast(uY), static_cast(uZ)); + cubicVertex.data = uMaterialIn; + rEntry.iIndex = m_meshCurrent->addVertex(cubicVertex); rEntry.uMaterial = uMaterialIn; return rEntry.iIndex; @@ -233,8 +236,8 @@ namespace PolyVox return -1; //Should never happen. } - template - bool CubicSurfaceExtractor::performQuadMerging(std::list& quads) + template + bool CubicSurfaceExtractor::performQuadMerging(std::list& quads) { bool bDidMerge = false; for(typename std::list::iterator outerIter = quads.begin(); outerIter != quads.end(); outerIter++) @@ -263,12 +266,12 @@ namespace PolyVox return bDidMerge; } - template - bool CubicSurfaceExtractor::mergeQuads(Quad& q1, Quad& q2) + template + bool CubicSurfaceExtractor::mergeQuads(Quad& q1, Quad& q2) { - //All four vertices of a given quad have the same material, + //All four vertices of a given quad have the same data, //so just check that the first pair of vertices match. - if(m_meshCurrent->getVertices()[q1.vertices[0]].getMaterial() == m_meshCurrent->getVertices()[q2.vertices[0]].getMaterial()) + if (m_meshCurrent->getVertices()[q1.vertices[0]].data == m_meshCurrent->getVertices()[q2.vertices[0]].data) { //Now check whether quad 2 is adjacent to quad one by comparing vertices. //Adjacent quads must share two vertices, and the second quad could be to the diff --git a/library/PolyVoxCore/include/PolyVoxCore/GradientEstimators.h b/library/PolyVoxCore/include/PolyVoxCore/GradientEstimators.h index cb8fcbe4..871dbcb2 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/GradientEstimators.h +++ b/library/PolyVoxCore/include/PolyVoxCore/GradientEstimators.h @@ -55,7 +55,7 @@ namespace PolyVox template Vector3DFloat computeSmoothSobelGradient(typename VolumeType::Sampler& volIter); - //POLYVOX_API void computeNormalsForVertices(VolumeType* volumeData, SurfaceMesh& mesh, NormalGenerationMethod normalGenerationMethod); + //POLYVOX_API void computeNormalsForVertices(VolumeType* volumeData, Mesh& mesh, NormalGenerationMethod normalGenerationMethod); //POLYVOX_API Vector3DFloat computeNormal(VolumeType* volumeData, const Vector3DFloat& v3dPos, NormalGenerationMethod normalGenerationMethod); } diff --git a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.h b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.h index fe541f74..4b96b432 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.h @@ -29,11 +29,72 @@ freely, subject to the following restrictions: #include "PolyVoxCore/Array.h" #include "PolyVoxCore/BaseVolume.h" //For wrap modes... should move these? -#include "PolyVoxCore/SurfaceMesh.h" +#include "PolyVoxCore/Mesh.h" #include "PolyVoxCore/DefaultMarchingCubesController.h" +#include "PolyVoxCore/Vertex.h" namespace PolyVox { +#ifdef SWIG + struct MarchingCubesVertex +#else + template + struct POLYVOX_API MarchingCubesVertex +#endif + { + typedef _DataType DataType; + + // Each component of the position is stored using 8.8 fixed-point encoding. + Vector3DUint16 encodedPosition; + + // Each component of the normal is encoded using 5 bits of this variable. + // The 16 bits are -xxxxxyyyyyzzzzz (note the left-most bit is currently + // unused). Some extra shifting and scaling is required to make it signed. + uint16_t encodedNormal; + + // User data + DataType data; + }; + + /// Decodes a position from a MarchingCubesVertex + inline Vector3DFloat decode(const Vector3DUint16& encodedPosition) + { + Vector3DFloat result(encodedPosition.getX(), encodedPosition.getY(), encodedPosition.getZ()); + result *= (1.0f / 256.0f); // Division is compile-time constant + return result; + } + + /// Decodes a normal from a MarchingCubesVertex + inline Vector3DFloat decode(const uint16_t encodedNormal) + { + // Get normal components in the range 0 to 31 + uint16_t x = (encodedNormal >> 10) & 0x1F; + uint16_t y = (encodedNormal >> 5) & 0x1F; + uint16_t z = (encodedNormal) & 0x1F; + + // Build the resulting vector + Vector3DFloat result(x, y, z); + + // Convert to range 0.0 to 2.0 + result *= (1.0f / 15.5f); // Division is compile-time constant + + // Convert to range -1.0 to 1.0 + result -= Vector3DFloat(1.0f, 1.0f, 1.0f); + + return result; + } + + /// Decodes a MarchingCubesVertex by converting it into a regular Vertex which can then be directly used for rendering. + template + Vertex decode(const MarchingCubesVertex& marchingCubesVertex) + { + Vertex result; + result.position = decode(marchingCubesVertex.encodedPosition); + result.normal = decode(marchingCubesVertex.encodedNormal); + result.data = marchingCubesVertex.data; // Data is not encoded + return result; + } + template< typename VolumeType, typename Controller = DefaultMarchingCubesController > class MarchingCubesSurfaceExtractor { @@ -41,9 +102,9 @@ namespace PolyVox // This is a bit ugly - it seems that the C++03 syntax is different from the C++11 syntax? See this thread: http://stackoverflow.com/questions/6076015/typename-outside-of-template // Long term we should probably come back to this and if the #ifdef is still needed then maybe it should check for C++11 mode instead of MSVC? #if defined(_MSC_VER) - MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType(), Controller controller = Controller()); + MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, Mesh >* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType(), Controller controller = Controller()); #else - MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), Controller controller = Controller()); + MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, Mesh >* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), Controller controller = Controller()); #endif void execute(); @@ -193,7 +254,7 @@ namespace PolyVox uint32_t m_uNoOfOccupiedCells; //The surface patch we are currently filling. - SurfaceMesh >* m_meshCurrent; + Mesh >* m_meshCurrent; //Information about the region we are currently processing Region m_regSizeInVoxels; @@ -212,9 +273,9 @@ namespace PolyVox }; template< typename VolumeType, typename Controller> - SurfaceMesh > extractMarchingCubesSurface(VolumeType* volData, Region region, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, Controller controller) + Mesh > extractMarchingCubesMesh(VolumeType* volData, Region region, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, Controller controller) { - SurfaceMesh > result; + Mesh > result; MarchingCubesSurfaceExtractor extractor(volData, region, &result, eWrapMode, tBorderValue, controller); extractor.execute(); return result; @@ -224,13 +285,13 @@ namespace PolyVox // This is a bit ugly - it seems that the C++03 syntax is different from the C++11 syntax? See this thread: http://stackoverflow.com/questions/6076015/typename-outside-of-template // Long term we should probably come back to this and if the #ifdef is still needed then maybe it should check for C++11 mode instead of MSVC? #if defined(_MSC_VER) - SurfaceMesh > extractMarchingCubesSurface(VolumeType* volData, Region region, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType()) + Mesh > extractMarchingCubesMesh(VolumeType* volData, Region region, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType()) #else - SurfaceMesh > extractMarchingCubesSurface(VolumeType* volData, Region region, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType()) + Mesh > extractMarchingCubesMesh(VolumeType* volData, Region region, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType()) #endif { DefaultMarchingCubesController controller; - return extractMarchingCubesSurface(volData, region, eWrapMode, tBorderValue, controller); + return extractMarchingCubesMesh(volData, region, eWrapMode, tBorderValue, controller); } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl index 5c2868d9..19968cd6 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl @@ -25,8 +25,8 @@ freely, subject to the following restrictions: namespace PolyVox { - template - MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, Controller controller) + template + MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, Mesh >* result, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, Controller controller) :m_volData(volData) ,m_sampVolume(volData) ,m_meshCurrent(result) @@ -122,13 +122,7 @@ namespace PolyVox m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); } - m_meshCurrent->m_Region = m_regSizeInVoxels; - - m_meshCurrent->m_vecLodRecords.clear(); - LodRecord lodRecord; - lodRecord.beginIndex = 0; - lodRecord.endIndex = m_meshCurrent->getNoOfIndices(); - m_meshCurrent->m_vecLodRecords.push_back(lodRecord); + m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); POLYVOX_LOG_TRACE("Marching cubes surface extraction took " << timer.elapsedTimeInMilliSeconds() << "ms (Region size = " << m_regSizeInVoxels.getWidthInVoxels() << "x" << m_regSizeInVoxels.getHeightInVoxels() @@ -446,6 +440,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()) + fInterp, static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast(iZVolSpace - m_regSizeInCells.getLowerZ())); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1-fInterp)); @@ -456,10 +451,23 @@ namespace PolyVox v3dNormal.normalise(); } - // Allow the controller to decide how the material should be derived from the voxels. + v3dNormal += Vector3DFloat(1.0f, 1.0f, 1.0f); + uint16_t encodedX = static_cast(roundToNearestInteger(v3dNormal.getX() * 15.5f)); + uint16_t encodedY = static_cast(roundToNearestInteger(v3dNormal.getY() * 15.5f)); + uint16_t encodedZ = static_cast(roundToNearestInteger(v3dNormal.getZ() * 15.5f)); + POLYVOX_ASSERT(encodedX < 32, "Encoded value out of range"); + POLYVOX_ASSERT(encodedY < 32, "Encoded value out of range"); + POLYVOX_ASSERT(encodedZ < 32, "Encoded value out of range"); + uint16_t encodedNormal = (encodedX << 10) | (encodedY << 5) | encodedZ; + + // Allow the controller to decide how the material should be derived from the voxels. const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v100, fInterp); - const MarchingCubesVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodedNormal; + surfaceVertex.data = uMaterial; + const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); m_pCurrentVertexIndicesX[iXVolSpace - m_regSizeInVoxels.getLowerX()][iYVolSpace - m_regSizeInVoxels.getLowerY()] = uLastVertexIndex; @@ -475,6 +483,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()) + fInterp, static_cast(iZVolSpace - m_regSizeInVoxels.getLowerZ())); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1-fInterp)); @@ -485,11 +494,24 @@ namespace PolyVox v3dNormal.normalise(); } - // Allow the controller to decide how the material should be derived from the voxels. + v3dNormal += Vector3DFloat(1.0f, 1.0f, 1.0f); + uint16_t encodedX = static_cast(roundToNearestInteger(v3dNormal.getX() * 15.5f)); + uint16_t encodedY = static_cast(roundToNearestInteger(v3dNormal.getY() * 15.5f)); + uint16_t encodedZ = static_cast(roundToNearestInteger(v3dNormal.getZ() * 15.5f)); + POLYVOX_ASSERT(encodedX < 32, "Encoded value out of range"); + POLYVOX_ASSERT(encodedY < 32, "Encoded value out of range"); + POLYVOX_ASSERT(encodedZ < 32, "Encoded value out of range"); + uint16_t encodedNormal = (encodedX << 10) | (encodedY << 5) | encodedZ; + + // Allow the controller to decide how the material should be derived from the voxels. const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v010, fInterp); - MarchingCubesVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); - uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodedNormal; + surfaceVertex.data = uMaterial; + + uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); m_pCurrentVertexIndicesY[iXVolSpace - m_regSizeInVoxels.getLowerX()][iYVolSpace - m_regSizeInVoxels.getLowerY()] = uLastVertexIndex; m_sampVolume.moveNegativeY(); @@ -504,6 +526,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast(iZVolSpace - m_regSizeInVoxels.getLowerZ()) + fInterp); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1-fInterp)); // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so @@ -513,10 +536,23 @@ namespace PolyVox v3dNormal.normalise(); } - // Allow the controller to decide how the material should be derived from the voxels. + v3dNormal += Vector3DFloat(1.0f, 1.0f, 1.0f); + uint16_t encodedX = static_cast(roundToNearestInteger(v3dNormal.getX() * 15.5f)); + uint16_t encodedY = static_cast(roundToNearestInteger(v3dNormal.getY() * 15.5f)); + uint16_t encodedZ = static_cast(roundToNearestInteger(v3dNormal.getZ() * 15.5f)); + POLYVOX_ASSERT(encodedX < 32, "Encoded value out of range"); + POLYVOX_ASSERT(encodedY < 32, "Encoded value out of range"); + POLYVOX_ASSERT(encodedZ < 32, "Encoded value out of range"); + uint16_t encodedNormal = (encodedX << 10) | (encodedY << 5) | encodedZ; + + // Allow the controller to decide how the material should be derived from the voxels. const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v001, fInterp); - const MarchingCubesVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial); + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodedNormal; + surfaceVertex.data = uMaterial; + const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); m_pCurrentVertexIndicesZ[iXVolSpace - m_regSizeInVoxels.getLowerX()][iYVolSpace - m_regSizeInVoxels.getLowerY()] = uLastVertexIndex; diff --git a/library/PolyVoxCore/include/PolyVoxCore/Mesh.h b/library/PolyVoxCore/include/PolyVoxCore/Mesh.h new file mode 100644 index 00000000..34dc50b4 --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/Mesh.h @@ -0,0 +1,94 @@ +/******************************************************************************* +Copyright (c) 2005-2009 David Williams + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*******************************************************************************/ + +#ifndef __PolyVox_Mesh_H__ +#define __PolyVox_Mesh_H__ + +#include "Impl/TypeDef.h" + +#include "PolyVoxCore/Region.h" +#include "PolyVoxCore/Vertex.h" //Should probably do away with this on in the future... + +#include +#include +#include +#include +#include +#include + +namespace PolyVox +{ + template + class Mesh + { + public: + + typedef VertexType VertexType; + typedef IndexType IndexType; + + Mesh(); + ~Mesh(); + + const std::vector& getIndices(void) const; + uint32_t getNoOfIndices(void) const; + IndexType getNoOfVertices(void) const; + const std::vector& getVertices(void) const; + const Vector3DInt32& getOffset(void) const; + + void setOffset(const Vector3DInt32& offset); + + void addTriangle(IndexType index0, IndexType index1, IndexType index2); + IndexType addVertex(const VertexType& vertex); + void clear(void); + bool isEmpty(void) const; + void removeUnusedVertices(void); + + Vector3DInt32 m_offset; + + public: + std::vector m_vecTriangleIndices; + std::vector m_vecVertices; + }; + + template + Mesh< Vertex< typename MeshType::VertexType::DataType >, typename MeshType::IndexType > decode(const MeshType& mesh) + { + Mesh< Vertex< typename MeshType::VertexType::DataType >, typename MeshType::IndexType > result; + result.m_vecVertices.resize(mesh.m_vecVertices.size()); + + for(MeshType::IndexType ct = 0; ct < mesh.m_vecVertices.size(); ct++) + { + result.m_vecVertices[ct] = decode(mesh.m_vecVertices[ct]); + } + + result.m_vecTriangleIndices = mesh.m_vecTriangleIndices; + + result.m_offset = mesh.m_offset; + + return result; + } +} + +#include "PolyVoxCore/Mesh.inl" + +#endif /* __Mesh_H__ */ diff --git a/library/PolyVoxCore/include/PolyVoxCore/Mesh.inl b/library/PolyVoxCore/include/PolyVoxCore/Mesh.inl new file mode 100644 index 00000000..e34f51ff --- /dev/null +++ b/library/PolyVoxCore/include/PolyVoxCore/Mesh.inl @@ -0,0 +1,139 @@ +/******************************************************************************* +Copyright (c) 2005-2009 David Williams + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*******************************************************************************/ + +namespace PolyVox +{ + template + Mesh::Mesh() + { + } + + template + Mesh::~Mesh() + { + } + + template + const std::vector& Mesh::getIndices(void) const + { + return m_vecTriangleIndices; + } + + template + uint32_t Mesh::getNoOfIndices(void) const + { + return m_vecTriangleIndices.size(); + } + + template + IndexType Mesh::getNoOfVertices(void) const + { + return m_vecVertices.size(); + } + + template + const std::vector& Mesh::getVertices(void) const + { + return m_vecVertices; + } + + template + const Vector3DInt32& Mesh::getOffset(void) const + { + return m_offset; + } + + template + void Mesh::setOffset(const Vector3DInt32& offset) + { + m_offset = offset; + } + + template + void Mesh::addTriangle(IndexType index0, IndexType index1, IndexType index2) + { + //Make sure the specified indices correspond to valid vertices. + POLYVOX_ASSERT(index0 < m_vecVertices.size(), "Index points at an invalid vertex."); + POLYVOX_ASSERT(index1 < m_vecVertices.size(), "Index points at an invalid vertex."); + POLYVOX_ASSERT(index2 < m_vecVertices.size(), "Index points at an invalid vertex."); + + m_vecTriangleIndices.push_back(index0); + m_vecTriangleIndices.push_back(index1); + m_vecTriangleIndices.push_back(index2); + } + + template + IndexType Mesh::addVertex(const VertexType& vertex) + { + // We should not add more vertices than our chosen index type will let us index. + POLYVOX_THROW_IF(m_vecVertices.size() >= std::numeric_limits::max(), std::out_of_range, "Mesh has more vertices that the chosen index type allows."); + + m_vecVertices.push_back(vertex); + return m_vecVertices.size() - 1; + } + + template + void Mesh::clear(void) + { + m_vecVertices.clear(); + m_vecTriangleIndices.clear(); + } + + template + bool Mesh::isEmpty(void) const + { + return (getNoOfVertices() == 0) || (getNoOfIndices() == 0); + } + + template + void Mesh::removeUnusedVertices(void) + { + std::vector isVertexUsed(m_vecVertices.size()); + std::fill(isVertexUsed.begin(), isVertexUsed.end(), false); + + for(uint32_t triCt = 0; triCt < m_vecTriangleIndices.size(); triCt++) + { + int v = m_vecTriangleIndices[triCt]; + isVertexUsed[v] = true; + } + + int noOfUsedVertices = 0; + std::vector newPos(m_vecVertices.size()); + for(IndexType vertCt = 0; vertCt < m_vecVertices.size(); vertCt++) + { + if(isVertexUsed[vertCt]) + { + m_vecVertices[noOfUsedVertices] = m_vecVertices[vertCt]; + newPos[vertCt] = noOfUsedVertices; + noOfUsedVertices++; + } + } + + m_vecVertices.resize(noOfUsedVertices); + + for(uint32_t triCt = 0; triCt < m_vecTriangleIndices.size(); triCt++) + { + m_vecTriangleIndices[triCt] = newPos[m_vecTriangleIndices[triCt]]; + } + } +} diff --git a/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h b/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h index 0d68b3e9..16151e4c 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h +++ b/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h @@ -76,12 +76,12 @@ namespace PolyVox // CubicSurfaceExtractor //////////////////////////////////////////////////////////////////////////////// template class DefaultIsQuadNeeded; - template > class CubicSurfaceExtractor; + template > class CubicSurfaceExtractor; //////////////////////////////////////////////////////////////////////////////// // CubicVertex //////////////////////////////////////////////////////////////////////////////// - template class CubicVertex; + template struct CubicVertex; //////////////////////////////////////////////////////////////////////////////// // Density @@ -108,10 +108,15 @@ namespace PolyVox //////////////////////////////////////////////////////////////////////////////// template class LargeVolume; + //////////////////////////////////////////////////////////////////////////////// + // MarchingCubesSurfaceExtractor + //////////////////////////////////////////////////////////////////////////////// + template class MarchingCubesSurfaceExtractor; + //////////////////////////////////////////////////////////////////////////////// // MarchingCubesVertex //////////////////////////////////////////////////////////////////////////////// - template class MarchingCubesVertex; + template struct MarchingCubesVertex; //////////////////////////////////////////////////////////////////////////////// // Material @@ -134,6 +139,11 @@ namespace PolyVox typedef MaterialDensityPair MaterialDensityPair44; typedef MaterialDensityPair MaterialDensityPair88; + //////////////////////////////////////////////////////////////////////////////// + // Mesh + //////////////////////////////////////////////////////////////////////////////// + template class Mesh; + //////////////////////////////////////////////////////////////////////////////// // Pager //////////////////////////////////////////////////////////////////////////////// @@ -154,16 +164,6 @@ namespace PolyVox //////////////////////////////////////////////////////////////////////////////// template class SimpleVolume; - //////////////////////////////////////////////////////////////////////////////// - // MarchingCubesSurfaceExtractor - //////////////////////////////////////////////////////////////////////////////// - template class MarchingCubesSurfaceExtractor; - - //////////////////////////////////////////////////////////////////////////////// - // SurfaceMesh - //////////////////////////////////////////////////////////////////////////////// - template class SurfaceMesh; - //////////////////////////////////////////////////////////////////////////////// // Vector //////////////////////////////////////////////////////////////////////////////// diff --git a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.h b/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.h deleted file mode 100644 index 1de4a905..00000000 --- a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.h +++ /dev/null @@ -1,104 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#ifndef __PolyVox_SurfaceMesh_H__ -#define __PolyVox_SurfaceMesh_H__ - -#include "Impl/TypeDef.h" - -#include "PolyVoxCore/Region.h" -#include "PolyVoxCore/VertexTypes.h" //Should probably do away with this on in the future... - -#include -#include -#include -#include -#include -#include - -namespace PolyVox -{ - class LodRecord - { - public: - int beginIndex; - int endIndex; //Let's put it just past the end STL style - }; - - template - class SurfaceMesh - { - public: - SurfaceMesh(); - ~SurfaceMesh(); - - const std::vector& getIndices(void) const; - uint32_t getNoOfIndices(void) const; - uint32_t getNoOfNonUniformTrianges(void) const; - uint32_t getNoOfUniformTrianges(void) const; - uint32_t getNoOfVertices(void) const; - std::vector& getRawVertexData(void); //FIXME - this should be removed - const std::vector& getVertices(void) const; - - void addTriangle(uint32_t index0, uint32_t index1, uint32_t index2); - void addTriangleCubic(uint32_t index0, uint32_t index1, uint32_t index2); - uint32_t addVertex(const VertexType& vertex); - void clear(void); - bool isEmpty(void) const; - - void scaleVertices(float amount); - void translateVertices(const Vector3DFloat& amount); - - //THESE FUNCTIONS TO BE REMOVED IN THE FUTURE. OR AT LEAST MOVED OUT OF THIS CLASS INTO FREE FUNCTIONS. - //THEY ARE CAUSING PROBLEMS WITH THE SWIG BINDINGS. THE FUNCTIONS REGARDING NORMALS MAKE NO SENSE WHEN - //A VERTEX MIGHT NOT HAVE NORMALS. THE EXTRACT SUBSET FUNCTION SHOULD MAYBE BE APPLICATION CODE, AT ANY - //RATE THE STD::SET CAUSES PROBLEMS WITH SWIG. IF YOU UNCOMMENT ANY OF THESE FUNCTIONS, PLEASE POST ON - //THE FORUM SO WE CAN KNOW THE FUNCTIONALITY IS STILL NEEDED IN SOME FORM. - //void sumNearbyNormals(bool bNormaliseResult = true); - //std::shared_ptr< SurfaceMesh > extractSubset(std::set setMaterials); - //void generateAveragedFaceNormals(bool bNormalise, bool bIncludeEdgeVertices = false); - - int noOfDegenerateTris(void); - void removeDegenerateTris(void); - void removeUnusedVertices(void); - - Region m_Region; - - int32_t m_iTimeStamp; - - int32_t m_iNoOfLod0Tris; - - public: - std::vector m_vecTriangleIndices; - std::vector m_vecVertices; - - std::vector m_vecLodRecords; - }; - - template - std::shared_ptr< SurfaceMesh > extractSubset(SurfaceMesh& inputMesh, std::set setMaterials); -} - -#include "PolyVoxCore/SurfaceMesh.inl" - -#endif /* __SurfaceMesh_H__ */ diff --git a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl b/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl deleted file mode 100644 index 9b1bf020..00000000 --- a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl +++ /dev/null @@ -1,488 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -namespace PolyVox -{ - template - SurfaceMesh::SurfaceMesh() - { - m_iTimeStamp = -1; - } - - template - SurfaceMesh::~SurfaceMesh() - { - } - - template - const std::vector& SurfaceMesh::getIndices(void) const - { - return m_vecTriangleIndices; - } - - template - uint32_t SurfaceMesh::getNoOfIndices(void) const - { - return m_vecTriangleIndices.size(); - } - - template - uint32_t SurfaceMesh::getNoOfNonUniformTrianges(void) const - { - uint32_t result = 0; - for(uint32_t i = 0; i < m_vecTriangleIndices.size() - 2; i += 3) - { - if((m_vecVertices[m_vecTriangleIndices[i]].getMaterial() == m_vecVertices[m_vecTriangleIndices[i+1]].getMaterial()) - && (m_vecVertices[m_vecTriangleIndices[i]].getMaterial() == m_vecVertices[m_vecTriangleIndices[i+2]].getMaterial())) - { - } - else - { - result++; - } - } - return result; - } - - template - uint32_t SurfaceMesh::getNoOfUniformTrianges(void) const - { - uint32_t result = 0; - for(uint32_t i = 0; i < m_vecTriangleIndices.size() - 2; i += 3) - { - if((m_vecVertices[m_vecTriangleIndices[i]].getMaterial() == m_vecVertices[m_vecTriangleIndices[i+1]].getMaterial()) - && (m_vecVertices[m_vecTriangleIndices[i]].getMaterial() == m_vecVertices[m_vecTriangleIndices[i+2]].getMaterial())) - { - result++; - } - } - return result; - } - - template - uint32_t SurfaceMesh::getNoOfVertices(void) const - { - return m_vecVertices.size(); - } - - template - std::vector& SurfaceMesh::getRawVertexData(void) - { - return m_vecVertices; - } - - template - const std::vector& SurfaceMesh::getVertices(void) const - { - return m_vecVertices; - } - - template - void SurfaceMesh::addTriangle(uint32_t index0, uint32_t index1, uint32_t index2) - { - //Make sure the specified indices correspond to valid vertices. - POLYVOX_ASSERT(index0 < m_vecVertices.size(), "Index points at an invalid vertex."); - POLYVOX_ASSERT(index1 < m_vecVertices.size(), "Index points at an invalid vertex."); - POLYVOX_ASSERT(index2 < m_vecVertices.size(), "Index points at an invalid vertex."); - - m_vecTriangleIndices.push_back(index0); - m_vecTriangleIndices.push_back(index1); - m_vecTriangleIndices.push_back(index2); - } - - template - void SurfaceMesh::addTriangleCubic(uint32_t index0, uint32_t index1, uint32_t index2) - { - //Make sure the specified indices correspond to valid vertices. - POLYVOX_ASSERT(index0 < m_vecVertices.size(), "Index points at an invalid vertex."); - POLYVOX_ASSERT(index1 < m_vecVertices.size(), "Index points at an invalid vertex."); - POLYVOX_ASSERT(index2 < m_vecVertices.size(), "Index points at an invalid vertex."); - - m_vecTriangleIndices.push_back(index0); - m_vecTriangleIndices.push_back(index1); - m_vecTriangleIndices.push_back(index2); - } - - template - uint32_t SurfaceMesh::addVertex(const VertexType& vertex) - { - m_vecVertices.push_back(vertex); - return m_vecVertices.size() - 1; - } - - template - void SurfaceMesh::clear(void) - { - m_vecVertices.clear(); - m_vecTriangleIndices.clear(); - m_vecLodRecords.clear(); - } - - template - bool SurfaceMesh::isEmpty(void) const - { - return (getNoOfVertices() == 0) || (getNoOfIndices() == 0); - } - - //////////////////////////////////////////////////////////////////////////////// - /// This function can help improve the visual appearance of a surface patch by - /// smoothing normals with other nearby normals. It iterates over each triangle - /// in the surface patch and determines the sum of its corners normals. For any - /// given vertex, these sums are in turn summed for any triangles which use the - /// vertex. Usually, the resulting normals should be renormalised afterwards. - /// Note: This function can cause lighting discontinuities accross region boundaries. - //////////////////////////////////////////////////////////////////////////////// - /*template - void SurfaceMesh::sumNearbyNormals(bool bNormaliseResult) - { - if(m_vecVertices.size() == 0) //FIXME - I don't think we should need this test, but I have seen crashes otherwise... - { - return; - } - - std::vector summedNormals(m_vecVertices.size()); - - //Initialise all normals to zero. Should be ok as the vector should store all elements contiguously. - memset(&summedNormals[0], 0, summedNormals.size() * sizeof(Vector3DFloat)); - - for(vector::iterator iterIndex = m_vecTriangleIndices.begin(); iterIndex != m_vecTriangleIndices.end();) - { - PositionMaterialNormal& v0 = m_vecVertices[*iterIndex]; - Vector3DFloat& v0New = summedNormals[*iterIndex]; - iterIndex++; - PositionMaterialNormal& v1 = m_vecVertices[*iterIndex]; - Vector3DFloat& v1New = summedNormals[*iterIndex]; - iterIndex++; - PositionMaterialNormal& v2 = m_vecVertices[*iterIndex]; - Vector3DFloat& v2New = summedNormals[*iterIndex]; - iterIndex++; - - Vector3DFloat sumOfNormals = v0.getNormal() + v1.getNormal() + v2.getNormal(); - - v0New += sumOfNormals; - v1New += sumOfNormals; - v2New += sumOfNormals; - } - - for(uint32_t uIndex = 0; uIndex < summedNormals.size(); uIndex++) - { - if(bNormaliseResult) - { - summedNormals[uIndex].normalise(); - } - m_vecVertices[uIndex].setNormal(summedNormals[uIndex]); - } - }*/ - - /*template - void SurfaceMesh::generateAveragedFaceNormals(bool bNormalise, bool bIncludeEdgeVertices) - { - Vector3DFloat offset = static_cast(m_Region.getLowerCorner()); - - //Initially zero the normals - for(vector::iterator iterVertex = m_vecVertices.begin(); iterVertex != m_vecVertices.end(); iterVertex++) - { - if(m_Region.containsPoint(iterVertex->getPosition() + offset, 0.001)) - { - iterVertex->setNormal(Vector3DFloat(0.0f,0.0f,0.0f)); - } - } - - for(vector::iterator iterIndex = m_vecTriangleIndices.begin(); iterIndex != m_vecTriangleIndices.end();) - { - PositionMaterialNormal& v0 = m_vecVertices[*iterIndex]; - iterIndex++; - PositionMaterialNormal& v1 = m_vecVertices[*iterIndex]; - iterIndex++; - PositionMaterialNormal& v2 = m_vecVertices[*iterIndex]; - iterIndex++; - - Vector3DFloat triangleNormal = (v1.getPosition()-v0.getPosition()).cross(v2.getPosition()-v0.getPosition()); - - if(m_Region.containsPoint(v0.getPosition() + offset, 0.001)) - { - v0.setNormal(v0.getNormal() + triangleNormal); - } - if(m_Region.containsPoint(v1.getPosition() + offset, 0.001)) - { - v1.setNormal(v1.getNormal() + triangleNormal); - } - if(m_Region.containsPoint(v2.getPosition() + offset, 0.001)) - { - v2.setNormal(v2.getNormal() + triangleNormal); - } - } - - if(bNormalise) - { - for(vector::iterator iterVertex = m_vecVertices.begin(); iterVertex != m_vecVertices.end(); iterVertex++) - { - Vector3DFloat normal = iterVertex->getNormal(); - normal.normalise(); - iterVertex->setNormal(normal); - } - } - }*/ - - /*template - std::shared_ptr< SurfaceMesh > SurfaceMesh::extractSubset(std::set setMaterials) - { - std::shared_ptr< SurfaceMesh > result(new SurfaceMesh); - - if(m_vecVertices.size() == 0) //FIXME - I don't think we should need this test, but I have seen crashes otherwise... - { - return result; - } - - assert(m_vecLodRecords.size() == 1); - if(m_vecLodRecords.size() != 1) - { - //If we have done progressive LOD then it's too late to split into subsets. - return result; - } - - std::vector indexMap(m_vecVertices.size()); - std::fill(indexMap.begin(), indexMap.end(), -1); - - for(uint32_t triCt = 0; triCt < m_vecTriangleIndices.size(); triCt += 3) - { - - PositionMaterialNormal& v0 = m_vecVertices[m_vecTriangleIndices[triCt]]; - PositionMaterialNormal& v1 = m_vecVertices[m_vecTriangleIndices[triCt + 1]]; - PositionMaterialNormal& v2 = m_vecVertices[m_vecTriangleIndices[triCt + 2]]; - - if( - (setMaterials.find(v0.getMaterial()) != setMaterials.end()) || - (setMaterials.find(v1.getMaterial()) != setMaterials.end()) || - (setMaterials.find(v2.getMaterial()) != setMaterials.end())) - { - uint32_t i0; - if(indexMap[m_vecTriangleIndices[triCt]] == -1) - { - indexMap[m_vecTriangleIndices[triCt]] = result->addVertex(v0); - } - i0 = indexMap[m_vecTriangleIndices[triCt]]; - - uint32_t i1; - if(indexMap[m_vecTriangleIndices[triCt+1]] == -1) - { - indexMap[m_vecTriangleIndices[triCt+1]] = result->addVertex(v1); - } - i1 = indexMap[m_vecTriangleIndices[triCt+1]]; - - uint32_t i2; - if(indexMap[m_vecTriangleIndices[triCt+2]] == -1) - { - indexMap[m_vecTriangleIndices[triCt+2]] = result->addVertex(v2); - } - i2 = indexMap[m_vecTriangleIndices[triCt+2]]; - - result->addTriangle(i0,i1,i2); - } - } - - result->m_vecLodRecords.clear(); - LodRecord lodRecord; - lodRecord.beginIndex = 0; - lodRecord.endIndex = result->getNoOfIndices(); - result->m_vecLodRecords.push_back(lodRecord); - - return result; - }*/ - - template - int SurfaceMesh::noOfDegenerateTris(void) - { - int count = 0; - for(uint32_t triCt = 0; triCt < m_vecTriangleIndices.size();) - { - int v0 = m_vecTriangleIndices[triCt]; - triCt++; - int v1 = m_vecTriangleIndices[triCt]; - triCt++; - int v2 = m_vecTriangleIndices[triCt]; - triCt++; - - if((v0 == v1) || (v1 == v2) || (v2 == v0)) - { - count++; - } - } - return count; - } - - template - void SurfaceMesh::removeDegenerateTris(void) - { - int noOfNonDegenerate = 0; - int targetCt = 0; - for(uint32_t triCt = 0; triCt < m_vecTriangleIndices.size();) - { - int v0 = m_vecTriangleIndices[triCt]; - triCt++; - int v1 = m_vecTriangleIndices[triCt]; - triCt++; - int v2 = m_vecTriangleIndices[triCt]; - triCt++; - - if((v0 != v1) && (v1 != v2) & (v2 != v0)) - { - m_vecTriangleIndices[targetCt] = v0; - targetCt++; - m_vecTriangleIndices[targetCt] = v1; - targetCt++; - m_vecTriangleIndices[targetCt] = v2; - targetCt++; - - noOfNonDegenerate++; - } - } - - m_vecTriangleIndices.resize(noOfNonDegenerate * 3); - } - - template - void SurfaceMesh::removeUnusedVertices(void) - { - std::vector isVertexUsed(m_vecVertices.size()); - std::fill(isVertexUsed.begin(), isVertexUsed.end(), false); - - for(uint32_t triCt = 0; triCt < m_vecTriangleIndices.size(); triCt++) - { - int v = m_vecTriangleIndices[triCt]; - isVertexUsed[v] = true; - } - - int noOfUsedVertices = 0; - std::vector newPos(m_vecVertices.size()); - for(uint32_t vertCt = 0; vertCt < m_vecVertices.size(); vertCt++) - { - if(isVertexUsed[vertCt]) - { - m_vecVertices[noOfUsedVertices] = m_vecVertices[vertCt]; - newPos[vertCt] = noOfUsedVertices; - noOfUsedVertices++; - } - } - - m_vecVertices.resize(noOfUsedVertices); - - for(uint32_t triCt = 0; triCt < m_vecTriangleIndices.size(); triCt++) - { - m_vecTriangleIndices[triCt] = newPos[m_vecTriangleIndices[triCt]]; - } - } - - //Currently a free function - think where this needs to go. - template - std::shared_ptr< SurfaceMesh > extractSubset(SurfaceMesh& inputMesh, std::set setMaterials) - { - std::shared_ptr< SurfaceMesh > result(new SurfaceMesh); - - result->m_Region = inputMesh.m_Region; - - if(inputMesh.m_vecVertices.size() == 0) //FIXME - I don't think we should need this test, but I have seen crashes otherwise... - { - return result; - } - - POLYVOX_ASSERT(inputMesh.m_vecLodRecords.size() == 1, "Number of LOD records must equal one."); - if(inputMesh.m_vecLodRecords.size() != 1) - { - //If we have done progressive LOD then it's too late to split into subsets. - return result; - } - - std::vector indexMap(inputMesh.m_vecVertices.size()); - std::fill(indexMap.begin(), indexMap.end(), -1); - - for(uint32_t triCt = 0; triCt < inputMesh.m_vecTriangleIndices.size(); triCt += 3) - { - - VertexType& v0 = inputMesh.m_vecVertices[inputMesh.m_vecTriangleIndices[triCt]]; - VertexType& v1 = inputMesh.m_vecVertices[inputMesh.m_vecTriangleIndices[triCt + 1]]; - VertexType& v2 = inputMesh.m_vecVertices[inputMesh.m_vecTriangleIndices[triCt + 2]]; - - if( - (setMaterials.find(v0.getMaterial()) != setMaterials.end()) || - (setMaterials.find(v1.getMaterial()) != setMaterials.end()) || - (setMaterials.find(v2.getMaterial()) != setMaterials.end())) - { - uint32_t i0; - if(indexMap[inputMesh.m_vecTriangleIndices[triCt]] == -1) - { - indexMap[inputMesh.m_vecTriangleIndices[triCt]] = result->addVertex(v0); - } - i0 = indexMap[inputMesh.m_vecTriangleIndices[triCt]]; - - uint32_t i1; - if(indexMap[inputMesh.m_vecTriangleIndices[triCt+1]] == -1) - { - indexMap[inputMesh.m_vecTriangleIndices[triCt+1]] = result->addVertex(v1); - } - i1 = indexMap[inputMesh.m_vecTriangleIndices[triCt+1]]; - - uint32_t i2; - if(indexMap[inputMesh.m_vecTriangleIndices[triCt+2]] == -1) - { - indexMap[inputMesh.m_vecTriangleIndices[triCt+2]] = result->addVertex(v2); - } - i2 = indexMap[inputMesh.m_vecTriangleIndices[triCt+2]]; - - result->addTriangle(i0,i1,i2); - } - } - - result->m_vecLodRecords.clear(); - LodRecord lodRecord; - lodRecord.beginIndex = 0; - lodRecord.endIndex = result->getNoOfIndices(); - result->m_vecLodRecords.push_back(lodRecord); - - return result; - } - - template - void SurfaceMesh::scaleVertices(float amount) - { - for(uint32_t ct = 0; ct < m_vecVertices.size(); ct++) - { - //TODO: Should rethink accessors here to provide faster access - Vector3DFloat position = m_vecVertices[ct].getPosition(); - position *= amount; - m_vecVertices[ct].setPosition(position); - } - } - - template - void SurfaceMesh::translateVertices(const Vector3DFloat& amount) - { - for(uint32_t ct = 0; ct < m_vecVertices.size(); ct++) - { - //TODO: Should rethink accessors here to provide faster access - Vector3DFloat position = m_vecVertices[ct].getPosition(); - position += amount; - m_vecVertices[ct].setPosition(position); - } - } -} diff --git a/examples/OpenGL/OpenGLSupport.h b/library/PolyVoxCore/include/PolyVoxCore/Vertex.h similarity index 72% rename from examples/OpenGL/OpenGLSupport.h rename to library/PolyVoxCore/include/PolyVoxCore/Vertex.h index 2d4d1185..1eb6f429 100644 --- a/examples/OpenGL/OpenGLSupport.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Vertex.h @@ -1,40 +1,51 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#ifndef __OpenGLExample_OpenGLSupport_H__ -#define __OpenGLExample_OpenGLSupport_H__ - -#include "PolyVoxCore/PolyVoxForwardDeclarations.h" - -#include "glew/glew.h" - -struct OpenGLColour -{ - GLfloat red; - GLfloat green; - GLfloat blue; -}; - -OpenGLColour convertMaterialIDToColour(uint8_t materialID); - -#endif //__OpenGLExample_OpenGLSupport_H__ \ No newline at end of file +/******************************************************************************* +Copyright (c) 2005-2009 David Williams + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*******************************************************************************/ + +#ifndef __PolyVox_Vertex_H__ +#define __PolyVox_Vertex_H__ + +#include "Impl/TypeDef.h" + +#include "PolyVoxCore/Vector.h" + +#include +#include + +namespace PolyVox +{ + #ifdef SWIG + struct Vertex +#else + template + struct POLYVOX_API Vertex +#endif + { + typedef _DataType DataType; + + Vector3DFloat position; + Vector3DFloat normal; + DataType data; + }; +} + +#endif // __PolyVox_Vertex_H__ diff --git a/library/PolyVoxCore/include/PolyVoxCore/VertexTypes.h b/library/PolyVoxCore/include/PolyVoxCore/VertexTypes.h deleted file mode 100644 index a5a24d79..00000000 --- a/library/PolyVoxCore/include/PolyVoxCore/VertexTypes.h +++ /dev/null @@ -1,159 +0,0 @@ -/******************************************************************************* -Copyright (c) 2005-2009 David Williams - -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. - -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. -*******************************************************************************/ - -#ifndef __PolyVox_SurfaceVertex_H__ -#define __PolyVox_SurfaceVertex_H__ - -#include "Impl/TypeDef.h" - -#include "PolyVoxCore/Vector.h" - -#include -#include - -namespace PolyVox -{ -#ifdef SWIG - class CubicVertex -#else - template - class POLYVOX_API CubicVertex -#endif - { - public: - CubicVertex() - { - } - - CubicVertex(Vector3DFloat positionToSet, VoxelType materialToSet) - :position(positionToSet) - ,material(materialToSet) - { - } - - CubicVertex(Vector3DFloat positionToSet, Vector3DFloat normalToSet, VoxelType materialToSet) - :position(positionToSet) - ,normal(normalToSet) - ,material(materialToSet) - { - } - - VoxelType getMaterial(void) const - { - return material; - } - - const Vector3DFloat& getNormal(void) const - { - return normal; - } - - const Vector3DFloat& getPosition(void) const - { - return position; - } - - void setMaterial(VoxelType materialToSet) - { - material = materialToSet; - } - - void setNormal(const Vector3DFloat& normalToSet) - { - normal = normalToSet; - } - - void setPosition(const Vector3DFloat& positionToSet) - { - position = positionToSet; - } - - public: - Vector3DFloat position; - Vector3DFloat normal; - VoxelType material; - }; - -#ifdef SWIG - class MarchingCubesVertex -#else - template - class POLYVOX_API MarchingCubesVertex -#endif - { - public: - MarchingCubesVertex() - { - } - - MarchingCubesVertex(Vector3DFloat positionToSet, VoxelType materialToSet) - :position(positionToSet) - , material(materialToSet) - { - } - - MarchingCubesVertex(Vector3DFloat positionToSet, Vector3DFloat normalToSet, VoxelType materialToSet) - :position(positionToSet) - , normal(normalToSet) - , material(materialToSet) - { - } - - VoxelType getMaterial(void) const - { - return material; - } - - const Vector3DFloat& getNormal(void) const - { - return normal; - } - - const Vector3DFloat& getPosition(void) const - { - return position; - } - - void setMaterial(VoxelType materialToSet) - { - material = materialToSet; - } - - void setNormal(const Vector3DFloat& normalToSet) - { - normal = normalToSet; - } - - void setPosition(const Vector3DFloat& positionToSet) - { - position = positionToSet; - } - - public: - Vector3DFloat position; - Vector3DFloat normal; - VoxelType material; - }; -} - -#endif diff --git a/library/PolyVoxCore/source/VertexTypes.cpp b/library/PolyVoxCore/source/VertexTypes.cpp deleted file mode 100644 index 8b137891..00000000 --- a/library/PolyVoxCore/source/VertexTypes.cpp +++ /dev/null @@ -1 +0,0 @@ - diff --git a/library/PolyVoxUtil/CMakeLists.txt b/library/PolyVoxUtil/CMakeLists.txt index 7fbdb43e..2160dc5c 100644 --- a/library/PolyVoxUtil/CMakeLists.txt +++ b/library/PolyVoxUtil/CMakeLists.txt @@ -36,8 +36,8 @@ ADD_DEFINITIONS(-DPOLYVOX_SHARED_EXPORTS) #Export symbols in the .dll #"Sources" and "Headers" are the group names in Visual Studio. #They may have other uses too... -SOURCE_GROUP("Sources" FILES ${UTIL_SRC_FILES}) -SOURCE_GROUP("Headers" FILES ${UTIL_INC_FILES}) +SOURCE_GROUP("Source Files" FILES ${UTIL_SRC_FILES}) +SOURCE_GROUP("Header Files" FILES ${UTIL_INC_FILES}) #Tell CMake the paths INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include ${PolyVoxCore_BINARY_DIR}/include ${PolyVoxCore_SOURCE_DIR}/include) diff --git a/tests/TestCubicSurfaceExtractor.cpp b/tests/TestCubicSurfaceExtractor.cpp index 3696cd42..8476b7f8 100644 --- a/tests/TestCubicSurfaceExtractor.cpp +++ b/tests/TestCubicSurfaceExtractor.cpp @@ -108,7 +108,7 @@ uint32_t testForType(void) { Region regionToExtract(x, y, z, x + uRegionSideLength - 1, y + uRegionSideLength - 1, z + uRegionSideLength - 1); - auto result = extractCubicSurface(&volData, regionToExtract); + auto result = extractCubicMesh(&volData, regionToExtract); uTotalVertices += result.getNoOfVertices(); uTotalIndices += result.getNoOfIndices(); @@ -130,7 +130,7 @@ void TestCubicSurfaceExtractor::testExecute() const static uint32_t uIndexToCheck = 2000; const static uint32_t uExpectedIndex = 1334; - SurfaceMesh mesh;*/ + Mesh mesh;*/ /*testForType(mesh); QCOMPARE(mesh.getNoOfVertices(), uExpectedVertices); diff --git a/tests/TestSurfaceExtractor.cpp b/tests/TestSurfaceExtractor.cpp index 47d5404b..682fa0dc 100644 --- a/tests/TestSurfaceExtractor.cpp +++ b/tests/TestSurfaceExtractor.cpp @@ -102,7 +102,7 @@ void writeMaterialValueToVoxel(int valueToWrite, MaterialDensityPair88& voxel) // Runs the surface extractor for a given type. template -SurfaceMesh > testForType(void) //I think we could avoid specifying this return type by using auto/decltype? +Mesh > testForType(void) //I think we could avoid specifying this return type by using auto/decltype? { const int32_t uVolumeSideLength = 32; @@ -128,12 +128,12 @@ SurfaceMesh > testForType(void) //I think we coul DefaultMarchingCubesController controller; controller.setThreshold(50); - auto result = extractMarchingCubesSurface(&volData, volData.getEnclosingRegion(), WrapModes::Border, VoxelType(), controller); + auto result = extractMarchingCubesMesh(&volData, volData.getEnclosingRegion(), WrapModes::Border, VoxelType(), controller); return result; } -void testCustomController(SurfaceMesh >& result) +void testCustomController(Mesh >& result) { const int32_t uVolumeSideLength = 32; @@ -162,68 +162,68 @@ void TestSurfaceExtractor::testExecute() const static uint32_t uExpectedVertices = 4731; const static uint32_t uExpectedIndices = 12810; const static uint32_t uMaterialToCheck = 3000; - const static float fExpectedMaterial = 42.0f; + const static float fExpectedData = 42.0f; const static float fNoMaterial = 1.0f; - SurfaceMesh > mesh; + Mesh > mesh; //Run the test for various voxel types. QBENCHMARK { mesh = testForType(); } QCOMPARE(mesh.getNoOfVertices(), uExpectedVertices); QCOMPARE(mesh.getNoOfIndices(), uExpectedIndices); - QCOMPARE(mesh.getVertices()[uMaterialToCheck].getMaterial(), static_cast(fNoMaterial)); + QCOMPARE(mesh.getVertices()[uMaterialToCheck].data, static_cast(fExpectedData)); auto mesh1 = testForType(); QCOMPARE(mesh1.getNoOfVertices(), uExpectedVertices); QCOMPARE(mesh1.getNoOfIndices(), uExpectedIndices); - QCOMPARE(mesh1.getVertices()[uMaterialToCheck].getMaterial(), static_cast(fNoMaterial)); + QCOMPARE(mesh1.getVertices()[uMaterialToCheck].data, static_cast(fExpectedData)); auto mesh2 = testForType(); QCOMPARE(mesh2.getNoOfVertices(), uExpectedVertices); QCOMPARE(mesh2.getNoOfIndices(), uExpectedIndices); - QCOMPARE(mesh2.getVertices()[uMaterialToCheck].getMaterial(), static_cast(fNoMaterial)); + QCOMPARE(mesh2.getVertices()[uMaterialToCheck].data, static_cast(fExpectedData)); auto mesh3 = testForType(); QCOMPARE(mesh3.getNoOfVertices(), uExpectedVertices); QCOMPARE(mesh3.getNoOfIndices(), uExpectedIndices); - QCOMPARE(mesh3.getVertices()[uMaterialToCheck].getMaterial(), static_cast(fNoMaterial)); + QCOMPARE(mesh3.getVertices()[uMaterialToCheck].data, static_cast(fExpectedData)); auto mesh4 = testForType(); QCOMPARE(mesh4.getNoOfVertices(), uExpectedVertices); QCOMPARE(mesh4.getNoOfIndices(), uExpectedIndices); - QCOMPARE(mesh4.getVertices()[uMaterialToCheck].getMaterial(), static_cast(fNoMaterial)); + QCOMPARE(mesh4.getVertices()[uMaterialToCheck].data, static_cast(fExpectedData)); auto mesh5 = testForType(); QCOMPARE(mesh5.getNoOfVertices(), uExpectedVertices); QCOMPARE(mesh5.getNoOfIndices(), uExpectedIndices); - QCOMPARE(mesh5.getVertices()[uMaterialToCheck].getMaterial(), static_cast(fNoMaterial)); + QCOMPARE(mesh5.getVertices()[uMaterialToCheck].data, static_cast(fExpectedData)); auto mesh6 = testForType(); QCOMPARE(mesh6.getNoOfVertices(), uExpectedVertices); QCOMPARE(mesh6.getNoOfIndices(), uExpectedIndices); - QCOMPARE(mesh6.getVertices()[uMaterialToCheck].getMaterial(), static_cast(fNoMaterial)); + QCOMPARE(mesh6.getVertices()[uMaterialToCheck].data, static_cast(fExpectedData)); auto mesh7 = testForType(); QCOMPARE(mesh7.getNoOfVertices(), uExpectedVertices); QCOMPARE(mesh7.getNoOfIndices(), uExpectedIndices); - QCOMPARE(mesh7.getVertices()[uMaterialToCheck].getMaterial(), static_cast(fNoMaterial)); + QCOMPARE(mesh7.getVertices()[uMaterialToCheck].data, static_cast(fExpectedData)); auto mesh8 = testForType(); QCOMPARE(mesh8.getNoOfVertices(), uExpectedVertices); QCOMPARE(mesh8.getNoOfIndices(), uExpectedIndices); - QCOMPARE(mesh8.getVertices()[uMaterialToCheck].getMaterial(), static_cast(fNoMaterial)); + QCOMPARE(mesh8.getVertices()[uMaterialToCheck].data, static_cast(fExpectedData)); auto mesh9 = testForType(); QCOMPARE(mesh9.getNoOfVertices(), uExpectedVertices); QCOMPARE(mesh9.getNoOfIndices(), uExpectedIndices); - //QCOMPARE(mesh9.getVertices()[uMaterialToCheck].getMaterial(), fExpectedMaterial); + //QCOMPARE(mesh9.getVertices()[uMaterialToCheck].data, fExpectedMaterial); //Test whether the CustomSurfaceExtractor works. /*testCustomController(floatMesh); QCOMPARE(floatMesh.getNoOfVertices(), uExpectedVertices); QCOMPARE(floatMesh.getNoOfIndices(), uExpectedIndices); - QCOMPARE(floatMesh.getVertices()[uMaterialToCheck].getMaterial(), fNoMaterial);*/ + QCOMPARE(floatMesh.getVertices()[uMaterialToCheck].data, fExpectedData);*/ } QTEST_MAIN(TestSurfaceExtractor) diff --git a/tests/TestVolumeSubclass.cpp b/tests/TestVolumeSubclass.cpp index 7562f1ef..73351113 100644 --- a/tests/TestVolumeSubclass.cpp +++ b/tests/TestVolumeSubclass.cpp @@ -184,7 +184,7 @@ void TestVolumeSubclass::testExtractSurface() } } - auto result = extractCubicSurface(&volumeSubclass, volumeSubclass.getEnclosingRegion()); + auto result = extractCubicMesh(&volumeSubclass, volumeSubclass.getEnclosingRegion()); QCOMPARE(result.getNoOfVertices(), static_cast(8)); }