[
  {
    "path": "DualContourSample.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 2013\nVisualStudioVersion = 12.0.31101.0\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"DualContourSample\", \"DualContouringSample\\DualContourSample.vcxproj\", \"{91867484-0299-425E-8721-AF4A7D239ECA}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Win32 = Debug|Win32\n\t\tRelease|Win32 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{91867484-0299-425E-8721-AF4A7D239ECA}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{91867484-0299-425E-8721-AF4A7D239ECA}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{91867484-0299-425E-8721-AF4A7D239ECA}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{91867484-0299-425E-8721-AF4A7D239ECA}.Release|Win32.Build.0 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "DualContouringSample/DualContourSample.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"12.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{91867484-0299-425E-8721-AF4A7D239ECA}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>DualContourStarter</RootNamespace>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v120</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>false</SDLCheck>\n      <AdditionalIncludeDirectories>$(SolutionDir)\\SDL2-2.0.3\\include;$(SolutionDir)\\glew-1.9.0\\include;$(SolutionDir)\\glm-0.9.3.4</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalLibraryDirectories>$(SolutionDir)\\SDL2-2.0.3\\lib\\x86;$(SolutionDir)\\glew-1.9.0\\lib</AdditionalLibraryDirectories>\n      <AdditionalDependencies>opengl32.lib;glew32.lib;SDL2main.lib;SDL2.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>false</SDLCheck>\n      <AdditionalIncludeDirectories>$(SolutionDir)\\SDL2-2.0.3\\include;$(SolutionDir)\\glew-1.9.0\\include;$(SolutionDir)\\glm-0.9.3.4</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalLibraryDirectories>$(SolutionDir)\\SDL2-2.0.3\\lib\\x86;$(SolutionDir)\\glew-1.9.0\\lib</AdditionalLibraryDirectories>\n      <AdditionalDependencies>opengl32.lib;glew32.lib;SDL2main.lib;SDL2.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"density.cpp\" />\n    <ClCompile Include=\"glsl_program.cpp\" />\n    <ClCompile Include=\"main.cpp\" />\n    <ClCompile Include=\"mesh.cpp\" />\n    <ClCompile Include=\"octree.cpp\" />\n    <ClCompile Include=\"qef.cpp\" />\n    <ClCompile Include=\"svd.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"density.h\" />\n    <ClInclude Include=\"glsl_program.h\" />\n    <ClInclude Include=\"mesh.h\" />\n    <ClInclude Include=\"octree.h\" />\n    <ClInclude Include=\"qef.h\" />\n    <ClInclude Include=\"svd.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"shader.frag\" />\n    <None Include=\"shader.vert\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Text Include=\"..\\README.txt\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "DualContouringSample/density.cpp",
    "content": "#include \"density.h\"\n\n#include <glm/ext.hpp>\nusing namespace glm;\n\n// ----------------------------------------------------------------------------\n\nfloat Sphere(const vec3& worldPosition, const vec3& origin, float radius)\n{\n\treturn length(worldPosition - origin) - radius;\n}\n\n// ----------------------------------------------------------------------------\n\nfloat Cuboid(const vec3& worldPosition, const vec3& origin, const vec3& halfDimensions)\n{\n\tconst vec3& local_pos = worldPosition - origin;\n\tconst vec3& pos = local_pos;\n\n\tconst vec3& d = glm::abs(pos) - halfDimensions;\n\tconst float m = max(d.x, max(d.y, d.z));\n\treturn min(m, length(max(d, vec3(0.f))));\n}\n\n// ----------------------------------------------------------------------------\n\nfloat FractalNoise(\n\tconst int octaves,\n\tconst float frequency,\n\tconst float lacunarity,\n\tconst float persistence,\n\tconst vec2& position)\n{\n\tconst float SCALE = 1.f / 128.f;\n\tvec2 p = position * SCALE;\n\tfloat noise = 0.f;\n\n\tfloat amplitude = 1.f;\n\tp *= frequency;\n\n\tfor (int i = 0; i < octaves; i++)\n\t{\n\t\tnoise += simplex(p) * amplitude;\n\t\tp *= lacunarity;\t\n\t\tamplitude *= persistence;\t\n\t}\n\n\t// move into [0, 1] range\n\treturn 0.5f + (0.5f * noise);\n}\n\n// ----------------------------------------------------------------------------\n\nfloat Density_Func(const vec3& worldPosition)\n{\n\tconst float MAX_HEIGHT = 20.f;\n\tconst float noise = FractalNoise(4, 0.5343f, 2.2324f, 0.68324f, vec2(worldPosition.x, worldPosition.z));\n\tconst float terrain = worldPosition.y - (MAX_HEIGHT * noise);\n\n\tconst float cube = Cuboid(worldPosition, vec3(-4., 10.f, -4.f), vec3(12.f));\n\tconst float sphere = Sphere(worldPosition, vec3(15.f, 2.5f, 1.f), 16.f);\n\n\treturn max(-cube, min(sphere, terrain));\n}\n"
  },
  {
    "path": "DualContouringSample/density.h",
    "content": "#ifndef\t\tHAS_DENSITY_H_BEEN_INCLUDED\n#define\t\tHAS_DENSITY_H_BEEN_INCLUDED\n\n#include <glm\\glm.hpp>\n\nfloat Density_Func(const glm::vec3& worldPosition);\n\n#endif\t//\tHAS_DENSITY_H_BEEN_INCLUDED\n"
  },
  {
    "path": "DualContouringSample/glsl_program.cpp",
    "content": "#include \"glsl_program.h\"\n#include <fstream>\n#include <sstream>\n\n// ----------------------------------------------------------------------------\n\nGLSLProgram::GLSLProgram()\n\t: program_(0)\n{\n}\n\n// ----------------------------------------------------------------------------\n\nGLSLProgram::~GLSLProgram()\n{\n\tif (program_ > 0)\n\t{\n\t\tglDeleteProgram(program_);\n\t}\n}\n\n// ----------------------------------------------------------------------------\n\nbool GLSLProgram::initialise()\n{\n\tprogram_ = glCreateProgram();\n\treturn true;\n}\n\n// ----------------------------------------------------------------------------\n\nvoid GLSLProgram::printShaderInfo(GLuint shader) const\n{\n\tint maxLength = 0;\n\tglGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);\n\n\tstatic char buffer[2048];\n\tint length = 0;\n\tglGetShaderInfoLog(shader, maxLength, &length, buffer);\n\n\tprintf(\"%s\\n\", buffer);\n}\n\n// ----------------------------------------------------------------------------\n\nvoid GLSLProgram::printProgramInfo(GLuint program) const\n{\n\tint maxLength = 0;\n\tglGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);\n\n\tstatic char buffer[2048];\n\tint length = 0;\n\tglGetProgramInfoLog(program, maxLength, &length, buffer);\n\n\tprintf(\"%s\\n\", buffer);\n}\n\n// ----------------------------------------------------------------------------\n\nvoid GLSLProgram::prependLine(const std::string& line)\n{\n\theader_ += line;\n\theader_ += \"\\n\";\n}\n\n// ----------------------------------------------------------------------------\n\nbool loadFile(const std::string& path, std::string& data)\n{\n\tstd::ifstream file(path.c_str());\n\tstd::stringstream fileData;\n\tfileData << file.rdbuf();\n\tfile.close();\n\n\tdata = fileData.str();\n\n\treturn true; \n}\n\n// ----------------------------------------------------------------------------\n\nbool GLSLProgram::compileShader(GLSLShaderTypes type, const std::string& filePath)\n{\n\tstd::string data;\n\tif (!loadFile(filePath.c_str(), data))\n\t{\n\t\tprintf(\"Error: could not load file %s\\n\", filePath.c_str());\n\t\treturn false;\n\t}\n\n\tconst GLchar* inputCode[] = { header_.c_str(), data.c_str() };\n\n\tconst GLenum glShaderType = type == ShaderType_Vertex ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER;\n\tconst GLuint shader = glCreateShader(glShaderType);\n\tglShaderSource(shader, 2, inputCode, NULL);\n\tglCompileShader(shader);\n\n\tGLint status = 0;\n\tglGetShaderiv(shader, GL_COMPILE_STATUS, &status);\n\tif (status == GL_FALSE)\n\t{\n\t\tprintShaderInfo(shader);\n\t\treturn false;\n\t}\n\n\tglAttachShader(program_, shader);\n\tshaders_.push_back(shader);\n\n\treturn true;\n}\n\n// ----------------------------------------------------------------------------\n\nbool GLSLProgram::link()\n{\n\tif (shaders_.empty())\n\t{\n\t\treturn true;\n\t}\n\n\tglLinkProgram(program_);\n\tprintProgramInfo(program_);\n\n\tif (GLenum err = glGetError() != GL_NO_ERROR)\n\t{\n\t\tprintf(\"GLSLProgram: err=%d\\n\");\n\t\treturn false;\n\t}\n\n\tGLint status = 0;\n\tglGetProgramiv(program_, GL_LINK_STATUS, &status);\n\tif (status == GL_FALSE)\n\t{\n\t\treturn false;\n\t}\n\n\tfor (size_t i = 0; i < shaders_.size(); i++)\n\t{\n\t\tglDetachShader(program_, shaders_[i]);\n\t\tglDeleteShader(shaders_[i]);\n\t}\n\n\tshaders_.clear();\n\n\treturn true;\n}\n\n// ----------------------------------------------------------------------------\n\nGLuint GLSLProgram::getId() const\n{\n\treturn program_;\n}\n\n// ----------------------------------------------------------------------------\n\nconst GLint GLSLProgram::getUniformLocation(const std::string& name)\n{\n\tconst auto iter = uniformLocations_.find(name);\t\n\tif (iter == end(uniformLocations_))\n\t{\n\t\tconst GLint location = glGetUniformLocation(program_, name.c_str());\n\t\tuniformLocations_[name] = location;\n\t}\n\n\treturn uniformLocations_[name];\n}\n\n// ----------------------------------------------------------------------------\n\nbool GLSLProgram::getSubroutineIndex(const std::string& name, GLuint& uniform)\n{\n\t// TODO hardcoded to fragment shaders\n\tuniform = glGetSubroutineIndex(program_, GL_FRAGMENT_SHADER, name.c_str());\n\treturn uniform != GL_INVALID_INDEX;\n}\n\n// ----------------------------------------------------------------------------\n\nbool GLSLProgram::setUniform(const std::string& name, const glm::mat4& uniform)\n{\n\tconst GLint location = getUniformLocation(name);\n\tif (location == -1)\n\t{\n\t\treturn false;\n\t}\n\n\tglUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(uniform));\n\treturn true;\n}\n\n// ----------------------------------------------------------------------------\n\nbool GLSLProgram::setUniform(const std::string& name, const glm::mat3& uniform)\n{\n\tconst GLint location = getUniformLocation(name);\n\tif (location == -1)\n\t{\n\t\treturn false;\n\t}\n\n\tglUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(uniform));\n\treturn true;\n}\n\n// ----------------------------------------------------------------------------\n\nbool GLSLProgram::setUniform(const std::string& name, const glm::vec4& uniform)\n{\n\tconst GLint location = getUniformLocation(name);\n\tif (location == -1)\n\t{\n\t\treturn false;\n\t}\n\n\tglUniform4fv(location, 1, glm::value_ptr(uniform));\n\treturn true;\n}\n\n// ----------------------------------------------------------------------------\n\nbool GLSLProgram::setUniform(const std::string& name, const glm::vec3& uniform)\n{\n\tconst GLint location = getUniformLocation(name);\n\tif (location == -1)\n\t{\n\t\treturn false;\n\t}\n\n\tglUniform3fv(location, 1, glm::value_ptr(uniform));\n\treturn true;\n}\n\n// ----------------------------------------------------------------------------\n\nbool GLSLProgram::setUniformFloat(const std::string& name, const float uniform)\n{\n\tconst GLint location = getUniformLocation(name);\n\tif (location == -1)\n\t{\n\t\treturn false;\n\t}\n\n\tglUniform1f(location, uniform);\n\treturn true;\n}\n\n// ----------------------------------------------------------------------------\n\nbool GLSLProgram::setUniformInt(const std::string& name, const GLuint uniform)\n{\n\tconst GLint location = getUniformLocation(name);\n\tif (location == -1)\n\t{\n\t\treturn false;\n\t}\n\n\tglUniform1i(location, uniform);\n\treturn true;\n}\n\n"
  },
  {
    "path": "DualContouringSample/glsl_program.h",
    "content": "#ifndef\t\tHAS_GLSL_PROGRAM_H_BEEN_INCLUDED\n#define\t\tHAS_GLSL_PROGRAM_H_BEEN_INCLUDED\n\n#include <GL/glew.h>\n#include <SDL.h>\n#include <SDL_opengl.h>\n#include <vector>\n#include <glm/glm.hpp>\n#include <glm/ext.hpp>\n#include <hash_map>\n\nenum GLSLShaderTypes\n{\n\tShaderType_Vertex,\n\tShaderType_Fragment\n};\n\nclass GLSLProgram\n{\npublic:\n\n\tGLSLProgram();\n\tvirtual ~GLSLProgram();\n\n\tvirtual bool initialise();\n\tvoid prependLine(const std::string& line);\n\n\tbool compileShader(GLSLShaderTypes type, const std::string& filePath);\n\tbool link();\n\n\tGLuint getId() const;\n\tbool getUniform(const std::string& name, glm::mat4& uniform);\n\tbool getSubroutineIndex(const std::string& name, GLuint& uniform);\n\n\tbool setUniform(const std::string& name, const glm::mat4& uniform);\n\tbool setUniform(const std::string& name, const glm::mat3& uniform);\n\tbool setUniform(const std::string& name, const glm::vec4& uniform);\n\tbool setUniform(const std::string& name, const glm::vec3& uniform);\n\n\t// NB: overloading deliberately avoided here to prevent problems with literals\n\t// being converted, e.g. with an integer setUniform func setUniform(\"bob\", 1.f)\n\t// will call the variant, which can be very confusing (although it does generate a warning)\n\tbool setUniformFloat(const std::string& name, const float uniform);\n\tbool setUniformInt(const std::string& name, const GLuint uniform);\n\nprivate:\n\n\tvoid printShaderInfo(GLuint shader) const;\n\tvoid printProgramInfo(GLuint program) const;\n\n\tGLuint\t\t\t\t\tprogram_;\n\tstd::vector<GLuint>\t\tshaders_;\n\tstd::string\t\t\t\theader_;\n\n\t// Hash the locations of the uniforms to prevent glGet calls during frames\n\ttypedef std::hash_map<std::string, GLint> UniformLocations;\n\tUniformLocations\t\tuniformLocations_;\n\n\tconst GLint getUniformLocation(const std::string& name);\n};\n\n#endif\t//\tHAS_GLSL_PROGRAM_H_BEEN_INCLUDED\n\n"
  },
  {
    "path": "DualContouringSample/main.cpp",
    "content": "#include <stdio.h>\n#include <stdlib.h>\n\n#include <GL\\glew.h>\n#include <SDL.h>\n#include <SDL_opengl.h>\n#include <glm\\glm.hpp>\n\n#include \"glsl_program.h\"\n#include \"mesh.h\"\n#include \"octree.h\"\n\n// ----------------------------------------------------------------------------\n\nvoid HandleMouseMove(const SDL_MouseMotionEvent& e, float& rotateXAxis, float& rotateYAxis)\n{\n\tif (e.state & SDL_BUTTON_LMASK)\n\t{\n\t\trotateXAxis += (float)e.yrel * 0.5f;\n\t\trotateYAxis += (float)e.xrel * 0.5f;\n\n\t\trotateXAxis = glm::min(80.f, rotateXAxis);\n\t\trotateXAxis = glm::max(-80.f, rotateXAxis);\n\t}\n}\n\n// ----------------------------------------------------------------------------\n\nvoid HandleMouseWheel(const SDL_MouseWheelEvent& e, float& distance)\n{\n\tdistance += -e.y * 10.f;\n}\n\n// ----------------------------------------------------------------------------\n\nvoid HandleKeyPress(const SDL_KeyboardEvent& e, bool& drawWireframe, bool& refreshMesh)\n{\n\tif (e.type != SDL_KEYUP)\n\t{\n\t\treturn;\n\t}\n\n\tswitch (e.keysym.sym)\n\t{\n\tcase SDLK_F1:\n\t\tdrawWireframe = !drawWireframe;\n\t\tbreak;\n\n\tcase SDLK_F2:\n\t\trefreshMesh = true;\n\t\tbreak;\n\t}\n}\n\n// ----------------------------------------------------------------------------\n\nvoid DrawFrame(GLSLProgram& program, Mesh& mesh, const glm::vec3& pos, const glm::vec3& fwd, bool drawWireframe)\n{\n\tglClearColor(0.f, 0.f, 0.f, 0.f);\n\tglClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);\n\n\tglEnable(GL_DEPTH_TEST);\n\tglEnable(GL_CULL_FACE);\n\tglCullFace(GL_BACK);\n\n\tglm::mat4 projection = glm::perspective(60.f, 16.f/9.f, 0.1f, 500.f);\n\tglm::mat4 modelview = glm::lookAt(pos + fwd, glm::vec3(0.f), glm::vec3(0.f, 1.f, 0.f));\n\n\tglUseProgram(program.getId());\n\tprogram.setUniform(\"MVP\", projection * modelview);\n\tprogram.setUniformInt(\"useUniformColour\", 0);\n\tglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n\n\tglBindVertexArray(mesh.vertexArrayObj_);\n\tglDrawElements(GL_TRIANGLES, mesh.numIndices_, GL_UNSIGNED_INT, (void*)0);\n\n\tif (drawWireframe)\n\t{\n\t\tglm::mat4 wireframe = glm::translate(glm::mat4(1), 0.02f * -fwd);\n\n\t\tprogram.setUniform(\"MVP\", projection * modelview * wireframe);\n\t\tprogram.setUniformInt(\"useUniformColour\", 1);\n\t\tprogram.setUniform(\"colour\", glm::vec4(1));\n\t\tglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\n\t\tglDrawElements(GL_TRIANGLES, mesh.numIndices_, GL_UNSIGNED_INT, (void*)0);\n\t}\n\n\tglUseProgram(0);\n}\n\n// ----------------------------------------------------------------------------\n\nint main(int argc, char** argv)\n{\n\tif (SDL_Init(SDL_INIT_EVERYTHING) < 0)\n\t{\n\t\tprintf(\"Error: SDL_Init failed: %s\\n\", SDL_GetError());\n\t\treturn EXIT_FAILURE;\n\t}\n\n\tSDL_Window* window = SDL_CreateWindow(\"DualContourStarter\", 100, 100, 1280, 720, SDL_WINDOW_OPENGL);\n\tif (!window)\n\t{\n\t\tprintf(\"Error: SDL_CreateWindow failed: %s\\n\", SDL_GetError());\n\t\treturn EXIT_FAILURE;\n\t}\n\n\tSDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);\n\tSDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);\n\tSDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);\n\tSDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);\n\n\tSDL_GLContext context = SDL_GL_CreateContext(window);\n\tif (!context)\n\t{\n\t\tprintf(\"Error: SDL_GL_CreateContext failed: %s\\n\", SDL_GetError());\n\t\treturn EXIT_FAILURE;\n\t}\n\n\tSDL_GL_MakeCurrent(window, context);\n\n\tglewExperimental = true;\n\tif (glewInit() != GLEW_OK)\n\t{\n\t\tprintf(\"Error: glewInit failed\\n\");\n\t\treturn EXIT_FAILURE;\n\t}\n\n\tglViewport(0, 0, 1280, 720);\n\n\t// getting an (suprious?) error from glew here, just ignore\n\tglGetError();\n\n\tprintf(\"----------------------------------------------------------------\\n\");\n\tprintf(\"The controls are:\\n\");\n\tprintf(\"\t- hold left mouse and drag to rotate the view\\n\");\n\tprintf(\"\t- use the mouse wheel to zoom in/out\\n\");\n\tprintf(\"\t- press F1 to render a wireframe\\n\");\n\tprintf(\"\t- press F2 to regenerate the octree using a new error threshold (and generate a new mesh)\\n\");\n\tprintf(\"----------------------------------------------------------------\\n\");\n\tprintf(\"\\n\\n\");\n\n\tprintf(\"OpenGL version: %s\\n\", glGetString(GL_VERSION));\n\tprintf(\"OpenGL shading version: %s\\n\", glGetString(GL_SHADING_LANGUAGE_VERSION));\n\n\tGLSLProgram program;\n\tif (!program.initialise() ||\n\t\t!program.compileShader(ShaderType_Vertex, \"shader.vert\") ||\n\t\t!program.compileShader(ShaderType_Fragment, \"shader.frag\") ||\n\t\t!program.link())\n\t{\n\t\tprintf(\"Error: failed to create GLSL program\\n\");\n\t\treturn EXIT_FAILURE;\n\t}\n\n\tconst int MAX_THRESHOLDS = 5;\n\tconst float THRESHOLDS[MAX_THRESHOLDS] = { -1.f, 0.1f, 1.f, 10.f, 50.f };\n\tint thresholdIndex = -1;\n\n\tMesh mesh;\n\tmesh.initialise();\n\n\tOctreeNode* root = nullptr;\n\tUint32 lastFrameTime = 0;\n\n\t// octreeSize must be a power of two!\n\tconst int octreeSize = 64;\n\n\tfloat rotateX = -60.f, rotateY = 0.f;\n\tfloat distance = 100.f;\n\tbool drawWireframe = false;\n\tbool refreshMesh = true;\n\n\tbool quit = false;\n\twhile (!quit)\n\t{\n\t\tSDL_Event event;\n\t\twhile (SDL_PollEvent(&event))\n\t\t{\n\t\t\tswitch (event.type)\n\t\t\t{\n\t\t\tcase SDL_QUIT:\n\t\t\t\tquit = true;\n\t\t\t\tbreak;\n\n\t\t\tcase SDL_MOUSEMOTION:\n\t\t\t\tHandleMouseMove(event.motion, rotateX, rotateY);\n\t\t\t\tbreak;\n\n\t\t\tcase SDL_MOUSEWHEEL:\n\t\t\t\tHandleMouseWheel(event.wheel, distance);\n\t\t\t\tbreak;\n\n\t\t\tcase SDL_KEYUP:\n\t\t\t\tHandleKeyPress(event.key, drawWireframe, refreshMesh);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (refreshMesh)\n\t\t{\n\t\t\trefreshMesh = false;\n\t\t\tthresholdIndex = (thresholdIndex + 1) % MAX_THRESHOLDS;\n\t\t\tprintf(\"Generating mesh with error threshold=%.1f...\\n\", THRESHOLDS[thresholdIndex]);\n\t\t\tauto startTime = SDL_GetTicks();\n\n\t\t\tVertexBuffer vertices;\n\t\t\tIndexBuffer indices;\n\n\t\t\troot = BuildOctree(glm::ivec3(-octreeSize / 2), octreeSize, THRESHOLDS[thresholdIndex]);\n\t\t\tGenerateMeshFromOctree(root, vertices, indices);\n\t\t\tmesh.uploadData(vertices, indices);\n\t\t\tprintf(\"Generated mesh (%.1fs)\\n\\n\", (float)(SDL_GetTicks() - startTime) / 1000.f);\n\t\t}\n\n\t\tif ((SDL_GetTicks() - lastFrameTime) < 33)\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\n\t\tlastFrameTime = SDL_GetTicks();\n\n\t\t// calculate the forward vector and then use that find the camera position\n\t\tglm::vec3 dir(0.f, 0.f, 1.f);\n\t\tdir = glm::rotateX(dir, rotateX);\n\t\tdir = glm::rotateY(dir, rotateY);\n\n\t\tglm::vec3 position = dir * distance;\n\n\t\tDrawFrame(program, mesh, position, -dir, drawWireframe);\n\n\t\tSDL_GL_SwapWindow(window);\n\t}\n\n\tDestroyOctree(root);\n\tmesh.destroy();\n\n\tSDL_GL_DeleteContext(context);\n\tSDL_Quit();\n\n\treturn EXIT_SUCCESS;\n}\n\n// ----------------------------------------------------------------------------\n\n"
  },
  {
    "path": "DualContouringSample/mesh.cpp",
    "content": "#include \"mesh.h\"\n\n#include <stdio.h>\n\n// ----------------------------------------------------------------------------\n\nvoid Mesh::initialise()\n{\n\tglGenVertexArrays(1, &vertexArrayObj_);\n\tglGenBuffers(1, &vertexBuffer_);\n\tglGenBuffers(1, &indexBuffer_);\n\n\tglBindVertexArray(vertexArrayObj_);\n\tglBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_);\n\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer_);\n\n\tglEnableVertexAttribArray(0);\n\tglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), 0);\n\t\n\tglEnableVertexAttribArray(1);\n\tglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(MeshVertex), (void*)(sizeof(glm::vec3) * 1));\n\n\tglBindVertexArray(0);\n}\n\n// ----------------------------------------------------------------------------\n\nvoid Mesh::uploadData(const VertexBuffer& vertices, const IndexBuffer& indices)\n{\n\tif (vertices.empty() || indices.empty())\n\t{\n\t\treturn;\n\t}\n\n\tglBindVertexArray(vertexArrayObj_);\n\n\tglBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_);\n\tglBufferData(GL_ARRAY_BUFFER, sizeof(MeshVertex) * vertices.size(), &vertices[0], GL_STATIC_DRAW);\n\n\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer_);\n\tglBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * indices.size(), &indices[0], GL_STATIC_DRAW);\n\tnumIndices_ = indices.size();\n\n\tprintf(\"Mesh: %d vertices %d triangles\\n\", vertices.size(), indices.size() / 3);\n\n\tglBindVertexArray(0);\n}\n\n// ----------------------------------------------------------------------------\n\nvoid Mesh::destroy()\n{\n\tglDeleteBuffers(1, &indexBuffer_);\n\tglDeleteBuffers(1, &vertexBuffer_);\n\tglDeleteVertexArrays(1, &vertexArrayObj_);\n}\n\n"
  },
  {
    "path": "DualContouringSample/mesh.h",
    "content": "#ifndef\t\tHAS_MESH_H_BEEN_INCLUDED\n#define\t\tHAS_MESH_H_BEEN_INCLUDED\n\n#include <vector>\n\n#include <GL\\glew.h>\n#include <SDL_opengl.h>\n#include <glm\\glm.hpp>\n\n// ----------------------------------------------------------------------------\n\nstruct MeshVertex\n{\n\tMeshVertex(const glm::vec3& _xyz, const glm::vec3& _normal)\n\t\t: xyz(_xyz)\n\t\t, normal(_normal)\n\t{\n\t}\n\n\tglm::vec3\t\txyz, normal;\n};\n\ntypedef std::vector<MeshVertex> VertexBuffer;\ntypedef std::vector<int> IndexBuffer;\n\n// ----------------------------------------------------------------------------\n\nclass Mesh\n{\npublic:\n\n\tMesh()\n\t\t: vertexArrayObj_(0)\n\t\t, vertexBuffer_(0)\n\t\t, indexBuffer_(0)\n\t\t, numIndices_(0)\n\t{\n\t}\n\n\tvoid initialise();\n\tvoid uploadData(const VertexBuffer& vertices, const IndexBuffer& indices);\n\tvoid destroy();\n\n\tGLuint\t\t\tvertexArrayObj_, vertexBuffer_, indexBuffer_;\n\tint\t\t\t\tnumIndices_;\n};\n\n// ----------------------------------------------------------------------------\n\n#endif\t//\tHAS_MESH_H_BEEN_INCLUDED\n"
  },
  {
    "path": "DualContouringSample/octree.cpp",
    "content": "/*\n\nImplementations of Octree member functions.\n\nCopyright (C) 2011  Tao Ju\n\nThis library is free software; you can redistribute it and/or\nmodify it under the terms of the GNU Lesser General Public License\n(LGPL) as published by the Free Software Foundation; either\nversion 2.1 of the License, or (at your option) any later version.\n\nThis library is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\nLesser General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public\nLicense along with this library; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n*/\n\n#include\t\"octree.h\"\n#include\t\"density.h\"\n\n// ----------------------------------------------------------------------------\n\nconst int MATERIAL_AIR = 0;\nconst int MATERIAL_SOLID = 1;\n\nconst float QEF_ERROR = 1e-6f;\nconst int QEF_SWEEPS = 4;\n\n// ----------------------------------------------------------------------------\n\nconst ivec3 CHILD_MIN_OFFSETS[] =\n{\n\t// needs to match the vertMap from Dual Contouring impl\n\tivec3( 0, 0, 0 ),\n\tivec3( 0, 0, 1 ),\n\tivec3( 0, 1, 0 ),\n\tivec3( 0, 1, 1 ),\n\tivec3( 1, 0, 0 ),\n\tivec3( 1, 0, 1 ),\n\tivec3( 1, 1, 0 ),\n\tivec3( 1, 1, 1 ),\n};\n\n// ----------------------------------------------------------------------------\n// data from the original DC impl, drives the contouring process\n\nconst int edgevmap[12][2] = \n{\n\t{0,4},{1,5},{2,6},{3,7},\t// x-axis \n\t{0,2},{1,3},{4,6},{5,7},\t// y-axis\n\t{0,1},{2,3},{4,5},{6,7}\t\t// z-axis\n};\n\nconst int edgemask[3] = { 5, 3, 6 } ;\n\nconst int vertMap[8][3] = \n{\n\t{0,0,0},\n\t{0,0,1},\n\t{0,1,0},\n\t{0,1,1},\n\t{1,0,0},\n\t{1,0,1},\n\t{1,1,0},\n\t{1,1,1}\n};\n\nconst int faceMap[6][4] = {{4, 8, 5, 9}, {6, 10, 7, 11},{0, 8, 1, 10},{2, 9, 3, 11},{0, 4, 2, 6},{1, 5, 3, 7}} ;\nconst int cellProcFaceMask[12][3] = {{0,4,0},{1,5,0},{2,6,0},{3,7,0},{0,2,1},{4,6,1},{1,3,1},{5,7,1},{0,1,2},{2,3,2},{4,5,2},{6,7,2}} ;\nconst int cellProcEdgeMask[6][5] = {{0,1,2,3,0},{4,5,6,7,0},{0,4,1,5,1},{2,6,3,7,1},{0,2,4,6,2},{1,3,5,7,2}} ;\n\nconst int faceProcFaceMask[3][4][3] = {\n\t{{4,0,0},{5,1,0},{6,2,0},{7,3,0}},\n\t{{2,0,1},{6,4,1},{3,1,1},{7,5,1}},\n\t{{1,0,2},{3,2,2},{5,4,2},{7,6,2}}\n} ;\n\nconst int faceProcEdgeMask[3][4][6] = {\n\t{{1,4,0,5,1,1},{1,6,2,7,3,1},{0,4,6,0,2,2},{0,5,7,1,3,2}},\n\t{{0,2,3,0,1,0},{0,6,7,4,5,0},{1,2,0,6,4,2},{1,3,1,7,5,2}},\n\t{{1,1,0,3,2,0},{1,5,4,7,6,0},{0,1,5,0,4,1},{0,3,7,2,6,1}}\n};\n\nconst int edgeProcEdgeMask[3][2][5] = {\n\t{{3,2,1,0,0},{7,6,5,4,0}},\n\t{{5,1,4,0,1},{7,3,6,2,1}},\n\t{{6,4,2,0,2},{7,5,3,1,2}},\n};\n\nconst int processEdgeMask[3][4] = {{3,2,1,0},{7,5,6,4},{11,10,9,8}} ;\n\n// -------------------------------------------------------------------------------\n\nOctreeNode* SimplifyOctree(OctreeNode* node, float threshold)\n{\n\tif (!node)\n\t{\n\t\treturn NULL;\n\t}\n\n\tif (node->type != Node_Internal)\n\t{\n\t\t// can't simplify!\n\t\treturn node;\n\t}\n\n\tsvd::QefSolver qef;\n\tint signs[8] = { -1, -1, -1, -1, -1, -1, -1, -1 };\n\tint midsign = -1;\n\tint edgeCount = 0;\n\tbool isCollapsible = true;\n\n\tfor (int i = 0; i < 8; i++)\n\t{\n\t\tnode->children[i] = SimplifyOctree(node->children[i], threshold);\n\t\tif (node->children[i])\n\t\t{\n\t\t\tOctreeNode* child = node->children[i];\n\t\t\tif (child->type == Node_Internal)\n\t\t\t{\n\t\t\t\tisCollapsible = false;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tqef.add(child->drawInfo->qef);\n\n\t\t\t\tmidsign = (child->drawInfo->corners >> (7 - i)) & 1; \n\t\t\t\tsigns[i] = (child->drawInfo->corners >> i) & 1; \n\n\t\t\t\tedgeCount++;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!isCollapsible)\n\t{\n\t\t// at least one child is an internal node, can't collapse\n\t\treturn node;\n\t}\n\n\tsvd::Vec3 qefPosition;\n\tqef.solve(qefPosition, QEF_ERROR, QEF_SWEEPS, QEF_ERROR);\n\tfloat error = qef.getError();\n\n\t// convert to glm vec3 for ease of use\n\tvec3 position(qefPosition.x, qefPosition.y, qefPosition.z);\n\n\t// at this point the masspoint will actually be a sum, so divide to make it the average\n\tif (error > threshold)\n\t{\n\t\t// this collapse breaches the threshold\n\t\treturn node;\n\t}\n\n\tif (position.x < node->min.x || position.x > (node->min.x + node->size) ||\n\t\tposition.y < node->min.y || position.y > (node->min.y + node->size) ||\n\t\tposition.z < node->min.z || position.z > (node->min.z + node->size))\n\t{\n\t\tconst auto& mp = qef.getMassPoint();\n\t\tposition = vec3(mp.x, mp.y, mp.z);\n\t}\n\n\t// change the node from an internal node to a 'psuedo leaf' node\n\tOctreeDrawInfo* drawInfo = new OctreeDrawInfo;\n\n\tfor (int i = 0; i < 8; i++)\n\t{\n\t\tif (signs[i] == -1)\n\t\t{\n\t\t\t// Undetermined, use centre sign instead\n\t\t\tdrawInfo->corners |= (midsign << i);\n\t\t}\n\t\telse \n\t\t{\n\t\t\tdrawInfo->corners |= (signs[i] << i);\n\t\t}\n\t}\n\n\tdrawInfo->averageNormal = vec3(0.f);\n\tfor (int i = 0; i < 8; i++)\n\t{\n\t\tif (node->children[i])\n\t\t{\n\t\t\tOctreeNode* child = node->children[i];\n\t\t\tif (child->type == Node_Psuedo || \n\t\t\t\tchild->type == Node_Leaf)\n\t\t\t{\n\t\t\t\tdrawInfo->averageNormal += child->drawInfo->averageNormal;\n\t\t\t}\n\t\t}\n\t}\n\n\tdrawInfo->averageNormal = glm::normalize(drawInfo->averageNormal);\n\tdrawInfo->position = position;\n\tdrawInfo->qef = qef.getData();\n\n\tfor (int i = 0; i < 8; i++)\n\t{\n\t\tDestroyOctree(node->children[i]);\n\t\tnode->children[i] = nullptr;\n\t}\n\n\tnode->type = Node_Psuedo;\n\tnode->drawInfo = drawInfo;\n\n\treturn node;\n}\n\n// ----------------------------------------------------------------------------\n\nvoid GenerateVertexIndices(OctreeNode* node, VertexBuffer& vertexBuffer)\n{\n\tif (!node)\n\t{\n\t\treturn;\n\t}\n\n\tif (node->type != Node_Leaf)\n\t{\n\t\tfor (int i = 0; i < 8; i++)\n\t\t{\n\t\t\tGenerateVertexIndices(node->children[i], vertexBuffer);\n\t\t}\n\t}\n\n\tif (node->type != Node_Internal)\n\t{\n\t\tOctreeDrawInfo* d = node->drawInfo;\n\t\tif (!d)\n\t\t{\n\t\t\tprintf(\"Error! Could not add vertex!\\n\");\n\t\t\texit(EXIT_FAILURE);\n\t\t}\n\n\t\td->index = vertexBuffer.size();\n\t\tvertexBuffer.push_back(MeshVertex(d->position, d->averageNormal));\n\t}\n}\n\n// ----------------------------------------------------------------------------\n\nvoid ContourProcessEdge(OctreeNode* node[4], int dir, IndexBuffer& indexBuffer)\n{\n\tint minSize = 1000000;\t\t// arbitrary big number\n\tint minIndex = 0;\n\tint indices[4] = { -1, -1, -1, -1 };\n\tbool flip = false;\n\tbool signChange[4] = { false, false, false, false };\n\n\tfor (int i = 0; i < 4; i++)\n\t{\n\t\tconst int edge = processEdgeMask[dir][i];\n\t\tconst int c1 = edgevmap[edge][0];\n\t\tconst int c2 = edgevmap[edge][1];\n\n\t\tconst int m1 = (node[i]->drawInfo->corners >> c1) & 1;\n\t\tconst int m2 = (node[i]->drawInfo->corners >> c2) & 1;\n\n\t\tif (node[i]->size < minSize)\n\t\t{\n\t\t\tminSize = node[i]->size;\n\t\t\tminIndex = i;\n\t\t\tflip = m1 != MATERIAL_AIR; \n\t\t}\n\n\t\tindices[i] = node[i]->drawInfo->index;\n\n\t\tsignChange[i] = \n\t\t\t(m1 == MATERIAL_AIR && m2 != MATERIAL_AIR) ||\n\t\t\t(m1 != MATERIAL_AIR && m2 == MATERIAL_AIR);\n\t}\n\n\tif (signChange[minIndex])\n\t{\n\t\tif (!flip)\n\t\t{\n\t\t\tindexBuffer.push_back(indices[0]);\n\t\t\tindexBuffer.push_back(indices[1]);\n\t\t\tindexBuffer.push_back(indices[3]);\n\n\t\t\tindexBuffer.push_back(indices[0]);\n\t\t\tindexBuffer.push_back(indices[3]);\n\t\t\tindexBuffer.push_back(indices[2]);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tindexBuffer.push_back(indices[0]);\n\t\t\tindexBuffer.push_back(indices[3]);\n\t\t\tindexBuffer.push_back(indices[1]);\n\n\t\t\tindexBuffer.push_back(indices[0]);\n\t\t\tindexBuffer.push_back(indices[2]);\n\t\t\tindexBuffer.push_back(indices[3]);\n\t\t}\n\t}\n}\n\n// ----------------------------------------------------------------------------\n\nvoid ContourEdgeProc(OctreeNode* node[4], int dir, IndexBuffer& indexBuffer)\n{\n\tif (!node[0] || !node[1] || !node[2] || !node[3])\n\t{\n\t\treturn;\n\t}\n\n\tif (node[0]->type != Node_Internal &&\n\t\tnode[1]->type != Node_Internal &&\n\t\tnode[2]->type != Node_Internal &&\n\t\tnode[3]->type != Node_Internal)\n\t{\n\t\tContourProcessEdge(node, dir, indexBuffer);\n\t}\n\telse\n\t{\n\t\tfor (int i = 0; i < 2; i++)\n\t\t{\n\t\t\tOctreeNode* edgeNodes[4];\n\t\t\tconst int c[4] = \n\t\t\t{\n\t\t\t\tedgeProcEdgeMask[dir][i][0],\n\t\t\t\tedgeProcEdgeMask[dir][i][1],\n\t\t\t\tedgeProcEdgeMask[dir][i][2],\n\t\t\t\tedgeProcEdgeMask[dir][i][3],\n\t\t\t};\n\n\t\t\tfor (int j = 0; j < 4; j++)\n\t\t\t{\n\t\t\t\tif (node[j]->type == Node_Leaf || node[j]->type == Node_Psuedo)\n\t\t\t\t{\n\t\t\t\t\tedgeNodes[j] = node[j];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tedgeNodes[j] = node[j]->children[c[j]];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tContourEdgeProc(edgeNodes, edgeProcEdgeMask[dir][i][4], indexBuffer);\n\t\t}\n\t}\n}\n\n// ----------------------------------------------------------------------------\n\nvoid ContourFaceProc(OctreeNode* node[2], int dir, IndexBuffer& indexBuffer)\n{\n\tif (!node[0] || !node[1])\n\t{\n\t\treturn;\n\t}\n\n\tif (node[0]->type == Node_Internal || \n\t\tnode[1]->type == Node_Internal)\n\t{\n\t\tfor (int i = 0; i < 4; i++)\n\t\t{\n\t\t\tOctreeNode* faceNodes[2];\n\t\t\tconst int c[2] = \n\t\t\t{\n\t\t\t\tfaceProcFaceMask[dir][i][0], \n\t\t\t\tfaceProcFaceMask[dir][i][1], \n\t\t\t};\n\n\t\t\tfor (int j = 0; j < 2; j++)\n\t\t\t{\n\t\t\t\tif (node[j]->type != Node_Internal)\n\t\t\t\t{\n\t\t\t\t\tfaceNodes[j] = node[j];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tfaceNodes[j] = node[j]->children[c[j]];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tContourFaceProc(faceNodes, faceProcFaceMask[dir][i][2], indexBuffer);\n\t\t}\n\t\t\n\t\tconst int orders[2][4] =\n\t\t{\n\t\t\t{ 0, 0, 1, 1 },\n\t\t\t{ 0, 1, 0, 1 },\n\t\t};\n\t\tfor (int i = 0; i < 4; i++)\n\t\t{\n\t\t\tOctreeNode* edgeNodes[4];\n\t\t\tconst int c[4] =\n\t\t\t{\n\t\t\t\tfaceProcEdgeMask[dir][i][1],\n\t\t\t\tfaceProcEdgeMask[dir][i][2],\n\t\t\t\tfaceProcEdgeMask[dir][i][3],\n\t\t\t\tfaceProcEdgeMask[dir][i][4],\n\t\t\t};\n\n\t\t\tconst int* order = orders[faceProcEdgeMask[dir][i][0]];\n\t\t\tfor (int j = 0; j < 4; j++)\n\t\t\t{\n\t\t\t\tif (node[order[j]]->type == Node_Leaf ||\n\t\t\t\t\tnode[order[j]]->type == Node_Psuedo)\n\t\t\t\t{\n\t\t\t\t\tedgeNodes[j] = node[order[j]];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tedgeNodes[j] = node[order[j]]->children[c[j]];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tContourEdgeProc(edgeNodes, faceProcEdgeMask[dir][i][5], indexBuffer);\n\t\t}\n\t}\n}\n\n// ----------------------------------------------------------------------------\n\nvoid ContourCellProc(OctreeNode* node, IndexBuffer& indexBuffer)\n{\n\tif (node == NULL)\n\t{\n\t\treturn;\n\t}\n\n\tif (node->type == Node_Internal)\n\t{\n\t\tfor (int i = 0; i < 8; i++)\n\t\t{\n\t\t\tContourCellProc(node->children[i], indexBuffer);\n\t\t}\n\n\t\tfor (int i = 0; i < 12; i++)\n\t\t{\n\t\t\tOctreeNode* faceNodes[2];\n\t\t\tconst int c[2] = { cellProcFaceMask[i][0], cellProcFaceMask[i][1] };\n\t\t\t\n\t\t\tfaceNodes[0] = node->children[c[0]];\n\t\t\tfaceNodes[1] = node->children[c[1]];\n\n\t\t\tContourFaceProc(faceNodes, cellProcFaceMask[i][2], indexBuffer);\n\t\t}\n\n\t\tfor (int i = 0; i < 6; i++)\n\t\t{\n\t\t\tOctreeNode* edgeNodes[4];\n\t\t\tconst int c[4] = \n\t\t\t{\n\t\t\t\tcellProcEdgeMask[i][0],\n\t\t\t\tcellProcEdgeMask[i][1],\n\t\t\t\tcellProcEdgeMask[i][2],\n\t\t\t\tcellProcEdgeMask[i][3],\n\t\t\t};\n\n\t\t\tfor (int j = 0; j < 4; j++)\n\t\t\t{\n\t\t\t\tedgeNodes[j] = node->children[c[j]];\n\t\t\t}\n\n\t\t\tContourEdgeProc(edgeNodes, cellProcEdgeMask[i][4], indexBuffer);\n\t\t}\n\t}\n}\n\n// ----------------------------------------------------------------------------\n\nvec3 ApproximateZeroCrossingPosition(const vec3& p0, const vec3& p1)\n{\n\t// approximate the zero crossing by finding the min value along the edge\n\tfloat minValue = 100000.f;\n\tfloat t = 0.f;\n\tfloat currentT = 0.f;\n\tconst int steps = 8;\n\tconst float increment = 1.f / (float)steps;\n\twhile (currentT <= 1.f)\n\t{\n\t\tconst vec3 p = p0 + ((p1 - p0) * currentT);\n\t\tconst float density = glm::abs(Density_Func(p));\n\t\tif (density < minValue)\n\t\t{\n\t\t\tminValue = density;\n\t\t\tt = currentT;\n\t\t}\n\n\t\tcurrentT += increment;\n\t}\n\n\treturn p0 + ((p1 - p0) * t);\n}\n\n// ----------------------------------------------------------------------------\n\nvec3 CalculateSurfaceNormal(const vec3& p)\n{\n\tconst float H = 0.001f;\n\tconst float dx = Density_Func(p + vec3(H, 0.f, 0.f)) - Density_Func(p - vec3(H, 0.f, 0.f));\n\tconst float dy = Density_Func(p + vec3(0.f, H, 0.f)) - Density_Func(p - vec3(0.f, H, 0.f));\n\tconst float dz = Density_Func(p + vec3(0.f, 0.f, H)) - Density_Func(p - vec3(0.f, 0.f, H));\n\n\treturn glm::normalize(vec3(dx, dy, dz));\n}\n\n// ----------------------------------------------------------------------------\n\nOctreeNode* ConstructLeaf(OctreeNode* leaf)\n{\n\tif (!leaf || leaf->size != 1)\n\t{\n\t\treturn nullptr;\n\t}\n\n\tint corners = 0;\n\tfor (int i = 0; i < 8; i++)\n\t{\n\t\tconst ivec3 cornerPos = leaf->min + CHILD_MIN_OFFSETS[i];\n\t\tconst float density = Density_Func(vec3(cornerPos));\n\t\tconst int material = density < 0.f ? MATERIAL_SOLID : MATERIAL_AIR;\n\t\tcorners |= (material << i);\n\t}\n\n\tif (corners == 0 || corners == 255)\n\t{\n\t\t// voxel is full inside or outside the volume\n\t\tdelete leaf;\n\t\treturn nullptr;\n\t}\n\n\t// otherwise the voxel contains the surface, so find the edge intersections\n\tconst int MAX_CROSSINGS = 6;\n\tint edgeCount = 0;\n\tvec3 averageNormal(0.f);\n\tsvd::QefSolver qef;\n\n\tfor (int i = 0; i < 12 && edgeCount < MAX_CROSSINGS; i++)\n\t{\n\t\tconst int c1 = edgevmap[i][0];\n\t\tconst int c2 = edgevmap[i][1];\n\n\t\tconst int m1 = (corners >> c1) & 1;\n\t\tconst int m2 = (corners >> c2) & 1;\n\n\t\tif ((m1 == MATERIAL_AIR && m2 == MATERIAL_AIR) ||\n\t\t\t(m1 == MATERIAL_SOLID && m2 == MATERIAL_SOLID))\n\t\t{\n\t\t\t// no zero crossing on this edge\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst vec3 p1 = vec3(leaf->min + CHILD_MIN_OFFSETS[c1]);\n\t\tconst vec3 p2 = vec3(leaf->min + CHILD_MIN_OFFSETS[c2]);\n\t\tconst vec3 p = ApproximateZeroCrossingPosition(p1, p2);\n\t\tconst vec3 n = CalculateSurfaceNormal(p);\n\t\tqef.add(p.x, p.y, p.z, n.x, n.y, n.z);\n\n\t\taverageNormal += n;\n\n\t\tedgeCount++;\n\t}\n\n\tsvd::Vec3 qefPosition;\n\tqef.solve(qefPosition, QEF_ERROR, QEF_SWEEPS, QEF_ERROR);\n\n\tOctreeDrawInfo* drawInfo = new OctreeDrawInfo;\n\tdrawInfo->position = vec3(qefPosition.x, qefPosition.y, qefPosition.z);\n\tdrawInfo->qef = qef.getData();\n\n\tconst vec3 min = vec3(leaf->min);\n\tconst vec3 max = vec3(leaf->min + ivec3(leaf->size));\n\tif (drawInfo->position.x < min.x || drawInfo->position.x > max.x ||\n\t\tdrawInfo->position.y < min.y || drawInfo->position.y > max.y ||\n\t\tdrawInfo->position.z < min.z || drawInfo->position.z > max.z)\n\t{\n\t\tconst auto& mp = qef.getMassPoint();\n\t\tdrawInfo->position = vec3(mp.x, mp.y, mp.z);\n\t}\n\n\tdrawInfo->averageNormal = glm::normalize(averageNormal / (float)edgeCount);\n\tdrawInfo->corners = corners;\n\n\tleaf->type = Node_Leaf;\n\tleaf->drawInfo = drawInfo;\n\n\treturn leaf;\n}\n\n// -------------------------------------------------------------------------------\n\nOctreeNode* ConstructOctreeNodes(OctreeNode* node)\n{\n\tif (!node)\n\t{\n\t\treturn nullptr;\n\t}\n\n\tif (node->size == 1)\n\t{\n\t\treturn ConstructLeaf(node);\n\t}\n\t\n\tconst int childSize = node->size / 2;\n\tbool hasChildren = false;\n\n\tfor (int i = 0; i < 8; i++)\n\t{\n\t\tOctreeNode* child = new OctreeNode;\n\t\tchild->size = childSize;\n\t\tchild->min = node->min + (CHILD_MIN_OFFSETS[i] * childSize);\n\t\tchild->type = Node_Internal;\n\n\t\tnode->children[i] = ConstructOctreeNodes(child);\n\t\thasChildren |= (node->children[i] != nullptr);\n\t}\n\n\tif (!hasChildren)\n\t{\n\t\tdelete node;\n\t\treturn nullptr;\n\t}\n\n\treturn node;\n}\n\n// -------------------------------------------------------------------------------\n\nOctreeNode* BuildOctree(const ivec3& min, const int size, const float threshold)\n{\n\tOctreeNode* root = new OctreeNode;\n\troot->min = min;\n\troot->size = size;\n\troot->type = Node_Internal;\n\n\tConstructOctreeNodes(root);\n\troot = SimplifyOctree(root, threshold);\n\n\treturn root;\n}\n\n// ----------------------------------------------------------------------------\n\nvoid GenerateMeshFromOctree(OctreeNode* node, VertexBuffer& vertexBuffer, IndexBuffer& indexBuffer)\n{\n\tif (!node)\n\t{\n\t\treturn;\n\t}\n\n\tvertexBuffer.clear();\n\tindexBuffer.clear();\n\n\tGenerateVertexIndices(node, vertexBuffer);\n\tContourCellProc(node, indexBuffer);\n}\n\n// -------------------------------------------------------------------------------\n\nvoid DestroyOctree(OctreeNode* node)\n{\n\tif (!node)\n\t{\n\t\treturn;\n\t}\n\n\tfor (int i = 0; i < 8; i++)\n\t{\n\t\tDestroyOctree(node->children[i]);\n\t}\n\n\tif (node->drawInfo)\n\t{\n\t\tdelete node->drawInfo;\n\t}\n\n\tdelete node;\n}\n\n// -------------------------------------------------------------------------------"
  },
  {
    "path": "DualContouringSample/octree.h",
    "content": "/*\n\nImplementations of Octree member functions.\n\nCopyright (C) 2011  Tao Ju\n\nThis library is free software; you can redistribute it and/or\nmodify it under the terms of the GNU Lesser General Public License\n(LGPL) as published by the Free Software Foundation; either\nversion 2.1 of the License, or (at your option) any later version.\n\nThis library is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\nLesser General Public License for more details.\n\nYou should have received a copy of the GNU Lesser General Public\nLicense along with this library; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n*/\n\n\n#ifndef\t\tHAS_OCTREE_H_BEEN_INCLUDED\n#define\t\tHAS_OCTREE_H_BEEN_INCLUDED\n\n#include \"qef.h\"\n#include \"mesh.h\"\n\n#include <glm/glm.hpp>\nusing glm::vec3;\nusing glm::ivec3;\n\n// ----------------------------------------------------------------------------\n\nenum OctreeNodeType\n{\n\tNode_None,\n\tNode_Internal,\n\tNode_Psuedo,\n\tNode_Leaf,\n};\n\n// ----------------------------------------------------------------------------\n\nstruct OctreeDrawInfo \n{\n\tOctreeDrawInfo()\n\t\t: index(-1)\n\t\t, corners(0)\n\t{\n\t}\n\n\tint\t\t\t\tindex;\n\tint\t\t\t\tcorners;\n\tvec3\t\t\tposition;\n\tvec3\t\t\taverageNormal;\n\tsvd::QefData\tqef;\n};\n\n// ----------------------------------------------------------------------------\n\nclass OctreeNode\n{\npublic:\n\n\tOctreeNode()\n\t\t: type(Node_None)\n\t\t, min(0, 0, 0)\n\t\t, size(0)\n\t\t, drawInfo(nullptr)\n\t{\n\t\tfor (int i = 0; i < 8; i++)\n\t\t{\n\t\t\tchildren[i] = nullptr;\n\t\t}\n\t}\n\n\tOctreeNode(const OctreeNodeType _type)\n\t\t: type(_type)\n\t\t, min(0, 0, 0)\n\t\t, size(0)\n\t\t, drawInfo(nullptr)\n\t{\n\t\tfor (int i = 0; i < 8; i++)\n\t\t{\n\t\t\tchildren[i] = nullptr;\n\t\t}\n\t}\n\n\tOctreeNodeType\ttype;\n\tivec3\t\t\tmin;\n\tint\t\t\t\tsize;\n\tOctreeNode*\t\tchildren[8];\n\tOctreeDrawInfo*\tdrawInfo;\n};\n\n// ----------------------------------------------------------------------------\n\nOctreeNode* BuildOctree(const ivec3& min, const int size, const float threshold);\nvoid DestroyOctree(OctreeNode* node);\nvoid GenerateMeshFromOctree(OctreeNode* node, VertexBuffer& vertexBuffer, IndexBuffer& indexBuffer);\n\n// ----------------------------------------------------------------------------\n\n#endif\t// HAS_OCTREE_H_BEEN_INCLUDED\n\n"
  },
  {
    "path": "DualContouringSample/qef.cpp",
    "content": "/*\n * This is free and unencumbered software released into the public domain.\n *\n * Anyone is free to copy, modify, publish, use, compile, sell, or\n * distribute this software, either in source code form or as a compiled\n * binary, for any purpose, commercial or non-commercial, and by any\n * means.\n *\n * In jurisdictions that recognize copyright laws, the author or authors\n * of this software dedicate any and all copyright interest in the\n * software to the public domain. We make this dedication for the benefit\n * of the public at large and to the detriment of our heirs and\n * successors. We intend this dedication to be an overt act of\n * relinquishment in perpetuity of all present and future rights to this\n * software under copyright law.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n *\n * For more information, please refer to <http://unlicense.org/>\n */\n#include \"qef.h\"\n#include <stdexcept>\nnamespace svd\n{\n\n    QefData::QefData()\n    {\n        this->clear();\n    }\n\n    QefData::QefData(const float ata_00, const float ata_01,\n                     const float ata_02, const float ata_11, const float ata_12,\n                     const float ata_22, const float atb_x, const float atb_y,\n                     const float atb_z, const float btb, const float massPoint_x,\n                     const float massPoint_y, const float massPoint_z,\n                     const int numPoints)\n    {\n        this->set(ata_00, ata_01, ata_02, ata_11, ata_12, ata_22, atb_x, atb_y,\n                  atb_z, btb, massPoint_x, massPoint_y, massPoint_z, numPoints);\n    }\n\n    QefData::QefData(const QefData &rhs)\n    {\n        this->set(rhs);\n    }\n\n\tQefData& QefData::operator=(const QefData& rhs)\n\t{\n\t\tthis->set(rhs);\n\t\treturn *this;\n\t}\n\n    void QefData::add(const QefData &rhs)\n    {\n        this->ata_00 += rhs.ata_00;\n        this->ata_01 += rhs.ata_01;\n        this->ata_02 += rhs.ata_02;\n        this->ata_11 += rhs.ata_11;\n        this->ata_12 += rhs.ata_12;\n        this->ata_22 += rhs.ata_22;\n        this->atb_x += rhs.atb_x;\n        this->atb_y += rhs.atb_y;\n        this->atb_z += rhs.atb_z;\n        this->btb += rhs.btb;\n        this->massPoint_x += rhs.massPoint_x;\n        this->massPoint_y += rhs.massPoint_y;\n        this->massPoint_z += rhs.massPoint_z;\n        this->numPoints += rhs.numPoints;\n    }\n\n    void QefData::clear()\n    {\n        this->set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);\n    }\n\n    void QefData::set(const float ata_00, const float ata_01,\n                      const float ata_02, const float ata_11, const float ata_12,\n                      const float ata_22, const float atb_x, const float atb_y,\n                      const float atb_z, const float btb, const float massPoint_x,\n                      const float massPoint_y, const float massPoint_z,\n                      const int numPoints)\n    {\n        this->ata_00 = ata_00;\n        this->ata_01 = ata_01;\n        this->ata_02 = ata_02;\n        this->ata_11 = ata_11;\n        this->ata_12 = ata_12;\n        this->ata_22 = ata_22;\n        this->atb_x = atb_x;\n        this->atb_y = atb_y;\n        this->atb_z = atb_z;\n        this->btb = btb;\n        this->massPoint_x = massPoint_x;\n        this->massPoint_y = massPoint_y;\n        this->massPoint_z = massPoint_z;\n        this->numPoints = numPoints;\n    }\n\n    void QefData::set(const QefData &rhs)\n    {\n        this->set(rhs.ata_00, rhs.ata_01, rhs.ata_02, rhs.ata_11, rhs.ata_12,\n                  rhs.ata_22, rhs.atb_x, rhs.atb_y, rhs.atb_z, rhs.btb,\n                  rhs.massPoint_x, rhs.massPoint_y, rhs.massPoint_z,\n                  rhs.numPoints);\n    }\n\n#ifndef NO_OSTREAM\n    std::ostream &operator<<(std::ostream &os, const QefData &qef)\n    {\n        SMat3 ata;\n        Vec3 atb, mp;\n        ata.setSymmetric(qef.ata_00, qef.ata_01, qef.ata_02, qef.ata_11,\n                         qef.ata_12, qef.ata_22);\n        atb.set(qef.atb_x, qef.atb_y, qef.atb_z);\n        mp.set(qef.massPoint_x, qef.massPoint_y, qef.massPoint_z);\n\n        if (qef.numPoints > 0) {\n            VecUtils::scale(mp, 1.0f / qef.numPoints);\n        }\n\n        os << \"QefData [ \" << std::endl\n           << \" ata =\" << std::endl <<  ata << \",\" << std::endl\n           << \" atb = \" << atb << \",\" << std::endl\n           << \" btb = \" << qef.btb << \",\" << std::endl\n           << \" massPoint = \" << mp << \",\" << std::endl\n           << \" numPoints = \" << qef.numPoints << \"]\";\n        return os;\n    }\n#endif\n\n    QefSolver::QefSolver() : data(), ata(), atb(), massPoint(), x(),\n        hasSolution(false) {}\n\n    static void normalize(float &nx, float &ny, float &nz)\n    {\n        Vec3 tmpv(nx, ny, nz);\n        VecUtils::normalize(tmpv);\n        nx = tmpv.x;\n        ny = tmpv.y;\n        nz = tmpv.z;\n    }\n\n    void QefSolver::add(const float px, const float py, const float pz,\n                        float nx, float ny, float nz)\n    {\n        this->hasSolution = false;\n        normalize(nx, ny, nz);\n        this->data.ata_00 += nx * nx;\n        this->data.ata_01 += nx * ny;\n        this->data.ata_02 += nx * nz;\n        this->data.ata_11 += ny * ny;\n        this->data.ata_12 += ny * nz;\n        this->data.ata_22 += nz * nz;\n        const float dot = nx * px + ny * py + nz * pz;\n        this->data.atb_x += dot * nx;\n        this->data.atb_y += dot * ny;\n        this->data.atb_z += dot * nz;\n        this->data.btb += dot * dot;\n        this->data.massPoint_x += px;\n        this->data.massPoint_y += py;\n        this->data.massPoint_z += pz;\n        ++this->data.numPoints;\n    }\n\n    void QefSolver::add(const Vec3 &p, const Vec3 &n)\n    {\n        this->add(p.x, p.y, p.z, n.x, n.y, n.z);\n    }\n\n    void QefSolver::add(const QefData &rhs)\n    {\n        this->hasSolution = false;\n        this->data.add(rhs);\n    }\n\n\tQefData QefSolver::getData()\n\t{\n\t\treturn data;\n\t}\n\n    float QefSolver::getError()\n    {\n        if (!this->hasSolution) {\n            throw std::runtime_error(\"illegal state\");\n        }\n\n        return this->getError(this->x);\n    }\n\n    float QefSolver::getError(const Vec3 &pos)\n    {\n        if (!this->hasSolution) {\n            this->setAta();\n            this->setAtb();\n        }\n\n        Vec3 atax;\n        MatUtils::vmul_symmetric(atax, this->ata, pos);\n        return VecUtils::dot(pos, atax) - 2 * VecUtils::dot(pos, this->atb)\n               + this->data.btb;\n    }\n\n    void QefSolver::reset()\n    {\n        this->hasSolution = false;\n        this->data.clear();\n    }\n\n    void QefSolver::setAta()\n    {\n        this->ata.setSymmetric(this->data.ata_00, this->data.ata_01,\n                               this->data.ata_02, this->data.ata_11, this->data.ata_12,\n                               this->data.ata_22);\n    }\n\n    void QefSolver::setAtb()\n    {\n        this->atb.set(this->data.atb_x, this->data.atb_y, this->data.atb_z);\n    }\n\n    float QefSolver::solve(Vec3 &outx, const float svd_tol,\n                            const int svd_sweeps, const float pinv_tol)\n    {\n        if (this->data.numPoints == 0) {\n            throw std::invalid_argument(\"...\");\n        }\n\n        this->massPoint.set(this->data.massPoint_x, this->data.massPoint_y,\n                            this->data.massPoint_z);\n        VecUtils::scale(this->massPoint, 1.0f / this->data.numPoints);\n        this->setAta();\n        this->setAtb();\n        Vec3 tmpv;\n        MatUtils::vmul_symmetric(tmpv, this->ata, this->massPoint);\n        VecUtils::sub(this->atb, this->atb, tmpv);\n        this->x.clear();\n        const float result = Svd::solveSymmetric(this->ata, this->atb,\n                              this->x, svd_tol, svd_sweeps, pinv_tol);\n        VecUtils::addScaled(this->x, 1, this->massPoint);\n        this->setAtb();\n        outx.set(x);\n        this->hasSolution = true;\n        return result;\n    }\n}"
  },
  {
    "path": "DualContouringSample/qef.h",
    "content": "/*\n * This is free and unencumbered software released into the public domain.\n *\n * Anyone is free to copy, modify, publish, use, compile, sell, or\n * distribute this software, either in source code form or as a compiled\n * binary, for any purpose, commercial or non-commercial, and by any\n * means.\n *\n * In jurisdictions that recognize copyright laws, the author or authors\n * of this software dedicate any and all copyright interest in the\n * software to the public domain. We make this dedication for the benefit\n * of the public at large and to the detriment of our heirs and\n * successors. We intend this dedication to be an overt act of\n * relinquishment in perpetuity of all present and future rights to this\n * software under copyright law.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n *\n * For more information, please refer to <http://unlicense.org/>\n */\n#ifndef QEF_H\n#define QEF_H\n#ifndef NO_OSTREAM\n#include <iostream>\n#endif\n\n#include \"svd.h\"\nnamespace svd\n{\n    class QefData\n    {\n    public:\n        float ata_00, ata_01, ata_02, ata_11, ata_12, ata_22;\n        float atb_x, atb_y, atb_z;\n        float btb;\n        float massPoint_x, massPoint_y, massPoint_z;\n        int numPoints;\n\n        QefData();\n\n        QefData(const float ata_00, const float ata_01,\n                const float ata_02, const float ata_11, const float ata_12,\n                const float ata_22, const float atb_x, const float atb_y,\n                const float atb_z, const float btb, const float massPoint_x,\n                const float massPoint_y, const float massPoint_z,\n                const int numPoints) ;\n\n        void add(const QefData &rhs) ;\n\n        void clear() ;\n\n        void set(const float ata_00, const float ata_01,\n                 const float ata_02, const float ata_11, const float ata_12,\n                 const float ata_22, const float atb_x, const float atb_y,\n                 const float atb_z, const float btb, const float massPoint_x,\n                 const float massPoint_y, const float massPoint_z,\n                 const int numPoints) ;\n\n        void set(const QefData &rhs);\n\n        QefData(const QefData &rhs);\n        QefData &operator= (const QefData &rhs);\n    };\n#ifndef NO_OSTREAM\n    std::ostream &operator<<(std::ostream &os, const QefData &d) ;\n#endif\n    class QefSolver\n    {\n    private:\n        QefData data;\n        SMat3 ata;\n        Vec3 atb, massPoint, x;\n        bool hasSolution;\n    public:\n        QefSolver() ;\n    public:\n\n\t\tconst Vec3& getMassPoint() const { return massPoint; }\n\n        void add(const float px, const float py, const float pz,\n                 float nx, float ny, float nz) ;\n        void add(const Vec3 &p, const Vec3 &n);\n        void add(const QefData &rhs) ;\n\t\tQefData getData() ;\n        float getError();\n        float getError(const Vec3 &pos);\n        void reset();\n        float solve(Vec3 &outx, const float svd_tol,\n                     const int svd_sweeps, const float pinv_tol) ;\n    private:\n        QefSolver(const QefSolver &rhs);\n        QefSolver &operator=(const QefSolver &rhs);\n        void setAta();\n        void setAtb() ;\n    };\n};\n#endif"
  },
  {
    "path": "DualContouringSample/shader.frag",
    "content": "#version 330\n\nsmooth in vec3 vertexColour;\nsmooth in vec3 vertexNormal;\n\nuniform int useUniformColour;\nuniform vec4 colour;\n\nvoid main()\n{\n\tif (useUniformColour > 0)\n\t{\n\t\tgl_FragColor = colour;\n\t}\n\telse\n\t{\t\n\t\tvec3 lightDir = -normalize(vec3(1, 5, -5));\n\t\tfloat d = dot(vertexNormal, -lightDir);\n\t\td = max(0.2, d);\n\t\tgl_FragColor = vec4(vertexColour, 1) * d;\n\t}\n}\n"
  },
  {
    "path": "DualContouringSample/shader.vert",
    "content": "#version 330\n\nlayout(location=0) in vec3 position;\nlayout(location=1) in vec3 normal;\n\nuniform mat4 MVP;\nsmooth out vec3 vertexColour;\nsmooth out vec3 vertexNormal;\n\nvoid main()\n{\n\tvertexColour = vec3(0.7f, 0.f, 0.f);\n\tvertexNormal = normal;\n\n\tgl_Position = MVP * vec4(position, 1);\n}\n\n"
  },
  {
    "path": "DualContouringSample/svd.cpp",
    "content": "/*\n * This is free and unencumbered software released into the public domain.\n *\n * Anyone is free to copy, modify, publish, use, compile, sell, or\n * distribute this software, either in source code form or as a compiled\n * binary, for any purpose, commercial or non-commercial, and by any\n * means.\n *\n * In jurisdictions that recognize copyright laws, the author or authors\n * of this software dedicate any and all copyright interest in the\n * software to the public domain. We make this dedication for the benefit\n * of the public at large and to the detriment of our heirs and\n * successors. We intend this dedication to be an overt act of\n * relinquishment in perpetuity of all present and future rights to this\n * software under copyright law.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n *\n * For more information, please refer to <http://unlicense.org/>\n */\n#include \"svd.h\"\n#include <math.h>\n\nnamespace svd\n{\n\n    Mat3::Mat3()\n    {\n        this->clear();\n    }\n\n    Mat3::Mat3(const float m00, const float m01, const float m02,\n               const float m10, const float m11, const float m12,\n               const float m20, const float m21, const float m22)\n    {\n        this->set(m00, m01, m02, m10, m11, m12, m20, m21, m22);\n    }\n\n    Mat3::Mat3(const Mat3 &rhs)\n    {\n        this->set(rhs);\n    }\n\n    void Mat3::clear()\n    {\n        this->set(0, 0, 0, 0, 0, 0, 0, 0, 0);\n    }\n\n    void Mat3::set(const float m00, const float m01, const float m02,\n                   const float m10, const float m11, const float m12,\n                   const float m20, const float m21, const float m22)\n    {\n        this->m00 = m00;\n        this->m01 = m01;\n        this->m02 = m02;\n        this->m10 = m10;\n        this->m11 = m11;\n        this->m12 = m12;\n        this->m20 = m20;\n        this->m21 = m21;\n        this->m22 = m22;\n    }\n\n    void Mat3::set(const Mat3 &rhs)\n    {\n        this->set(rhs.m00, rhs.m01, rhs.m02, rhs.m10, rhs.m11, rhs.m12, rhs.m20,\n                  rhs.m21, rhs.m22);\n    }\n\n    void Mat3::setSymmetric(const SMat3 &rhs)\n    {\n        this->setSymmetric(rhs.m00, rhs.m01, rhs.m02, rhs.m11, rhs.m12, rhs.m22);\n    }\n\n    void Mat3::setSymmetric(const float a00, const float a01, const float a02,\n                            const float a11, const float a12, const float a22)\n    {\n        this->set(a00, a01, a02, a01, a11, a12, a02, a12, a22);\n    }\n\n    SMat3::SMat3()\n    {\n        this->clear();\n    }\n\n    SMat3::SMat3(const float m00, const float m01, const float m02,\n                 const float m11, const float m12, const float m22)\n    {\n        this->setSymmetric(m00, m01, m02, m11, m12, m22);\n    }\n\n    SMat3::SMat3(const SMat3 &rhs)\n    {\n        this->setSymmetric(rhs);\n    }\n\n    void SMat3::clear()\n    {\n        this->setSymmetric(0, 0, 0, 0, 0, 0);\n    }\n\n    void SMat3::setSymmetric(const SMat3 &rhs)\n    {\n        this->setSymmetric(rhs.m00, rhs.m01, rhs.m02, rhs.m11, rhs.m12, rhs.m22);\n    }\n\n    void SMat3::setSymmetric(const float a00, const float a01, const float a02,\n                             const float a11, const float a12, const float a22)\n    {\n        this->m00 = a00;\n        this->m01 = a01;\n        this->m02 = a02;\n        this->m11 = a11;\n        this->m12 = a12;\n        this->m22 = a22;\n    }\n\n    Vec3::Vec3() : x(0), y(0), z(0) { }\n\n    Vec3::Vec3(const Vec3 &rhs)// : Vec3()\n    {\n        this->set(rhs);\n    }\n\n    Vec3::Vec3(const float x, const float y, const float z)// : Vec3()\n    {\n        this->set(x, y, z);\n    }\n\n    void Vec3::clear()\n    {\n        this->set(0, 0, 0);\n    }\n\n    void Vec3::set(const float x, const float y, const float z)\n    {\n        this->x = x;\n        this->y = y;\n        this->z = z;\n    }\n\n    void Vec3::set(const Vec3 &rhs)\n    {\n        this->set(rhs.x, rhs.y, rhs.z);\n    }\n\n#ifndef NO_OSTREAM\n    std::ostream &operator<<(std::ostream &os, const Mat3 &m)\n    {\n        os << \"[[\" << m.m00 << \", \" << m.m01 << \", \" << m.m02 << \"]\" <<\n           std::endl;\n        os << \" [\" << m.m10 << \", \" << m.m11 << \", \" << m.m12 << \"]\" <<\n           std::endl;\n        os << \" [\" << m.m20 << \", \" << m.m21 << \", \" << m.m22 << \"]]\";\n        return os;\n    }\n\n    std::ostream &operator<<(std::ostream &os, const SMat3 &m)\n    {\n        os << \"[[\" << m.m00 << \", \" << m.m01 << \", \" << m.m02 << \"]\" <<\n           std::endl;\n        os << \" [\" << m.m01 << \", \" << m.m11 << \", \" << m.m12 << \"]\" <<\n           std::endl;\n        os << \" [\" << m.m02 << \", \" << m.m12 << \", \" << m.m22 << \"]]\";\n        return os;\n    }\n\n    std::ostream &operator<<(std::ostream &os, const Vec3 &v)\n    {\n        os << \"[\" << v.x << \", \" << v.y << \", \" << v.z << \"]\";\n        return os;\n    }\n#endif\n\n    float MatUtils::fnorm(const Mat3 &a)\n    {\n        return sqrt((a.m00 * a.m00) + (a.m01 * a.m01) + (a.m02 * a.m02)\n                    + (a.m10 * a.m10) + (a.m11 * a.m11) + (a.m12 * a.m12)\n                    + (a.m20 * a.m20) + (a.m21 * a.m21) + (a.m22 * a.m22));\n    }\n\n    float MatUtils::fnorm(const SMat3 &a)\n    {\n        return sqrt((a.m00 * a.m00) + (a.m01 * a.m01) + (a.m02 * a.m02)\n                    + (a.m01 * a.m01) + (a.m11 * a.m11) + (a.m12 * a.m12)\n                    + (a.m02 * a.m02) + (a.m12 * a.m12) + (a.m22 * a.m22));\n    }\n\n    float MatUtils::off(const Mat3 &a)\n    {\n        return sqrt((a.m01 * a.m01) + (a.m02 * a.m02) + (a.m10 * a.m10)\n                    + (a.m12 * a.m12) + (a.m20 * a.m20) + (a.m21 * a.m21));\n    }\n\n    float MatUtils::off(const SMat3 &a)\n    {\n        return sqrt(2 * ((a.m01 * a.m01) + (a.m02 * a.m02) + (a.m12 * a.m12)));\n    }\n\n    void MatUtils::mmul(Mat3 &out, const Mat3 &a, const Mat3 &b)\n    {\n        out.set(a.m00 * b.m00 + a.m01 * b.m10 + a.m02 * b.m20,\n                a.m00 * b.m01 + a.m01 * b.m11 + a.m02 * b.m21,\n                a.m00 * b.m02 + a.m01 * b.m12 + a.m02 * b.m22,\n                a.m10 * b.m00 + a.m11 * b.m10 + a.m12 * b.m20,\n                a.m10 * b.m01 + a.m11 * b.m11 + a.m12 * b.m21,\n                a.m10 * b.m02 + a.m11 * b.m12 + a.m12 * b.m22,\n                a.m20 * b.m00 + a.m21 * b.m10 + a.m22 * b.m20,\n                a.m20 * b.m01 + a.m21 * b.m11 + a.m22 * b.m21,\n                a.m20 * b.m02 + a.m21 * b.m12 + a.m22 * b.m22);\n    }\n\n    void MatUtils::mmul_ata(SMat3 &out, const Mat3 &a)\n    {\n        out.setSymmetric(a.m00 * a.m00 + a.m10 * a.m10 + a.m20 * a.m20,\n                         a.m00 * a.m01 + a.m10 * a.m11 + a.m20 * a.m21,\n                         a.m00 * a.m02 + a.m10 * a.m12 + a.m20 * a.m22,\n                         a.m01 * a.m01 + a.m11 * a.m11 + a.m21 * a.m21,\n                         a.m01 * a.m02 + a.m11 * a.m12 + a.m21 * a.m22,\n                         a.m02 * a.m02 + a.m12 * a.m12 + a.m22 * a.m22);\n    }\n\n    void MatUtils::transpose(Mat3 &out, const Mat3 &a)\n    {\n        out.set(a.m00, a.m10, a.m20, a.m01, a.m11, a.m21, a.m02, a.m12, a.m22);\n    }\n\n    void MatUtils::vmul(Vec3 &out, const Mat3 &a, const Vec3 &v)\n    {\n        out.x = (a.m00 * v.x) + (a.m01 * v.y) + (a.m02 * v.z);\n        out.y = (a.m10 * v.x) + (a.m11 * v.y) + (a.m12 * v.z);\n        out.z = (a.m20 * v.x) + (a.m21 * v.y) + (a.m22 * v.z);\n    }\n\n    void MatUtils::vmul_symmetric(Vec3 &out, const SMat3 &a, const Vec3 &v)\n    {\n        out.x = (a.m00 * v.x) + (a.m01 * v.y) + (a.m02 * v.z);\n        out.y = (a.m01 * v.x) + (a.m11 * v.y) + (a.m12 * v.z);\n        out.z = (a.m02 * v.x) + (a.m12 * v.y) + (a.m22 * v.z);\n    }\n\n    void VecUtils::addScaled(Vec3 &v, const float s, const Vec3 &rhs)\n    {\n        v.x += s * rhs.x;\n        v.y += s * rhs.y;\n        v.z += s * rhs.z;\n    }\n\n    float VecUtils::dot(const Vec3 &a, const Vec3 &b)\n    {\n        return a.x * b.x + a.y * b.y + a.z * b.z;\n    }\n\n    void VecUtils::normalize(Vec3 &v)\n    {\n        const float len2 = VecUtils::dot(v, v);\n\n        if (fabs(len2) < 1e-12) {\n            v.clear();\n        } else {\n            VecUtils::scale(v, 1 / sqrt(len2));\n        }\n    }\n\n    void VecUtils::scale(Vec3 &v, const float s)\n    {\n        v.x *= s;\n        v.y *= s;\n        v.z *= s;\n    }\n\n    void VecUtils::sub(Vec3 &c, const Vec3 &a, const Vec3 &b)\n    {\n        const float v0 = a.x - b.x;\n        const float v1 = a.y - b.y;\n        const float v2 = a.z - b.z;\n        c.x = v0;\n        c.y = v1;\n        c.z = v2;\n    }\n\n    void Givens::rot01_post(Mat3 &m, const float c, const float s)\n    {\n        const float m00 = m.m00, m01 = m.m01, m10 = m.m10, m11 = m.m11, m20 = m.m20,\n                     m21 = m.m21;\n        m.set(c * m00 - s * m01, s * m00 + c * m01, m.m02, c * m10 - s * m11,\n              s * m10 + c * m11, m.m12, c * m20 - s * m21, s * m20 + c * m21, m.m22);\n    }\n\n    void Givens::rot02_post(Mat3 &m, const float c, const float s)\n    {\n        const float m00  = m.m00, m02  = m.m02, m10  = m.m10, m12  = m.m12,\n                     m20 = m.m20, m22  = m.m22 ;\n        m.set(c * m00 - s * m02, m.m01, s * m00 + c * m02, c * m10 - s * m12, m.m11,\n              s * m10 + c * m12, c * m20 - s * m22, m.m21, s * m20 + c * m22);\n    }\n\n    void Givens::rot12_post(Mat3 &m, const float c, const float s)\n    {\n        const float m01  = m.m01, m02  = m.m02, m11  = m.m11, m12  = m.m12,\n                     m21  = m.m21, m22  = m.m22;\n        m.set(m.m00, c * m01 - s * m02, s * m01 + c * m02, m.m10, c * m11 - s * m12,\n              s * m11 + c * m12, m.m20, c * m21 - s * m22, s * m21 + c * m22);\n    }\n\n    static void calcSymmetricGivensCoefficients(const float a_pp,\n            const float a_pq, const float a_qq, float &c, float &s)\n    {\n        if (a_pq == 0) {\n            c = 1;\n            s = 0;\n            return;\n        }\n\n        const float tau = (a_qq - a_pp) / (2 * a_pq);\n        const float stt = sqrt(1.0f + tau * tau);\n        const float tan = 1.0f / ((tau >= 0) ? (tau + stt) : (tau - stt));\n        c = 1.0f / sqrt(1.f + tan * tan);\n        s = tan * c;\n    }\n\n    void Schur2::rot01(SMat3 &m, float &c, float &s)\n    {\n        svd::calcSymmetricGivensCoefficients(m.m00, m.m01, m.m11, c, s);\n        const float cc = c * c;\n        const float ss = s * s;\n        const float mix = 2 * c * s * m.m01;\n        m.setSymmetric(cc * m.m00 - mix + ss * m.m11, 0, c * m.m02 - s * m.m12,\n                       ss * m.m00 + mix + cc * m.m11, s * m.m02 + c * m.m12, m.m22);\n    }\n\n    void Schur2::rot02(SMat3 &m, float &c, float &s)\n    {\n        svd::calcSymmetricGivensCoefficients(m.m00, m.m02, m.m22, c, s);\n        const float cc = c * c;\n        const float ss = s * s;\n        const float mix = 2 * c * s * m.m02;\n        m.setSymmetric(cc * m.m00 - mix + ss * m.m22, c * m.m01 - s * m.m12, 0,\n                       m.m11, s * m.m01 + c * m.m12, ss * m.m00 + mix + cc * m.m22);\n    }\n\n    void Schur2::rot12(SMat3 &m, float &c, float &s)\n    {\n        svd::calcSymmetricGivensCoefficients(m.m11, m.m12, m.m22, c, s);\n        const float cc = c * c;\n        const float ss = s * s;\n        const float mix = 2 * c * s * m.m12;\n        m.setSymmetric(m.m00, c * m.m01 - s * m.m02, s * m.m01 + c * m.m02,\n                       cc * m.m11 - mix + ss * m.m22, 0, ss * m.m11 + mix + cc * m.m22);\n    }\n\n    static void rotate01(SMat3 &vtav, Mat3 &v)\n    {\n        if (vtav.m01 == 0) {\n            return;\n        }\n\n        float c, s;\n        Schur2::rot01(vtav, c, s);\n        Givens::rot01_post(v, c, s);\n    }\n\n    static void rotate02(SMat3 &vtav, Mat3 &v)\n    {\n        if (vtav.m02 == 0) {\n            return;\n        }\n\n        float c, s;\n        Schur2::rot02(vtav, c, s);\n        Givens::rot02_post(v, c, s);\n    }\n\n    static void rotate12(SMat3 &vtav, Mat3 &v)\n    {\n        if (vtav.m12 == 0) {\n            return;\n        }\n\n        float c, s;\n        Schur2::rot12(vtav, c, s);\n        Givens::rot12_post(v, c, s);\n    }\n\n    void Svd::getSymmetricSvd(const SMat3 &a, SMat3 &vtav, Mat3 &v,\n                              const float tol,\n                              const int max_sweeps)\n    {\n        vtav.setSymmetric(a);\n        v.set(1, 0, 0, 0, 1, 0, 0, 0, 1);\n        const float delta = tol * MatUtils::fnorm(vtav);\n\n        for (int i = 0; i < max_sweeps\n                && MatUtils::off(vtav) > delta; ++i) {\n            rotate01(vtav, v);\n            rotate02(vtav, v);\n            rotate12(vtav, v);\n        }\n    }\n\n    static float calcError(const Mat3 &A, const Vec3 &x,\n                            const Vec3 &b)\n    {\n        Vec3 vtmp;\n        MatUtils::vmul(vtmp, A, x);\n        VecUtils::sub(vtmp, b, vtmp);\n        return VecUtils::dot(vtmp, vtmp);\n    }\n\n    static float calcError(const SMat3 &origA, const Vec3 &x,\n                            const Vec3 &b)\n    {\n        Mat3 A;\n        Vec3 vtmp;\n        A.setSymmetric(origA);\n        MatUtils::vmul(vtmp, A, x);\n        VecUtils::sub(vtmp, b, vtmp);\n        return VecUtils::dot(vtmp, vtmp);\n    }\n\n    static float pinv(const float x, const float tol)\n    {\n        return (fabs(x) < tol || fabs(1 / x) < tol) ? 0 : (1 / x);\n    }\n\n    void Svd::pseudoinverse(Mat3 &out, const SMat3 &d, const Mat3 &v,\n                            const float tol)\n    {\n        const float d0 = pinv(d.m00, tol), d1 = pinv(d.m11, tol), d2 = pinv(d.m22,\n                          tol);\n        out.set(v.m00 * d0 * v.m00 + v.m01 * d1 * v.m01 + v.m02 * d2 * v.m02,\n                v.m00 * d0 * v.m10 + v.m01 * d1 * v.m11 + v.m02 * d2 * v.m12,\n                v.m00 * d0 * v.m20 + v.m01 * d1 * v.m21 + v.m02 * d2 * v.m22,\n                v.m10 * d0 * v.m00 + v.m11 * d1 * v.m01 + v.m12 * d2 * v.m02,\n                v.m10 * d0 * v.m10 + v.m11 * d1 * v.m11 + v.m12 * d2 * v.m12,\n                v.m10 * d0 * v.m20 + v.m11 * d1 * v.m21 + v.m12 * d2 * v.m22,\n                v.m20 * d0 * v.m00 + v.m21 * d1 * v.m01 + v.m22 * d2 * v.m02,\n                v.m20 * d0 * v.m10 + v.m21 * d1 * v.m11 + v.m22 * d2 * v.m12,\n                v.m20 * d0 * v.m20 + v.m21 * d1 * v.m21 + v.m22 * d2 * v.m22);\n    }\n\n    float Svd::solveSymmetric(const SMat3 &A, const Vec3 &b, Vec3 &x,\n                               const float svd_tol, const int svd_sweeps, const float pinv_tol)\n    {\n        Mat3 mtmp, pinv, V;\n        SMat3 VTAV;\n        Svd::getSymmetricSvd(A, VTAV, V, svd_tol, svd_sweeps);\n        Svd::pseudoinverse(pinv, VTAV, V, pinv_tol);\n        MatUtils::vmul(x, pinv, b);\n        return svd::calcError(A, x, b);\n    }\n\n    float\n    LeastSquares::solveLeastSquares(const Mat3 &a, const Vec3 &b, Vec3 &x,\n                                    const float svd_tol, const int svd_sweeps, const float pinv_tol)\n    {\n        Mat3 at;\n        SMat3 ata;\n        Vec3 atb;\n        MatUtils::transpose(at, a);\n        MatUtils::mmul_ata(ata, a);\n        MatUtils::vmul(atb, at, b);\n        return Svd::solveSymmetric(ata, atb, x, svd_tol, svd_sweeps, pinv_tol);\n    }\n\n}"
  },
  {
    "path": "DualContouringSample/svd.h",
    "content": "/*\n * This is free and unencumbered software released into the public domain.\n *\n * Anyone is free to copy, modify, publish, use, compile, sell, or\n * distribute this software, either in source code form or as a compiled\n * binary, for any purpose, commercial or non-commercial, and by any\n * means.\n *\n * In jurisdictions that recognize copyright laws, the author or authors\n * of this software dedicate any and all copyright interest in the\n * software to the public domain. We make this dedication for the benefit\n * of the public at large and to the detriment of our heirs and\n * successors. We intend this dedication to be an overt act of\n * relinquishment in perpetuity of all present and future rights to this\n * software under copyright law.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\n * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\n * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\n * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n * OTHER DEALINGS IN THE SOFTWARE.\n *\n * For more information, please refer to <http://unlicense.org/>\n */\n#ifndef SVD_H\n#define SVD_H\n#ifndef NO_OSTREAM\n#include <iostream>\n#endif\n\nnamespace svd\n{\n    class SMat3\n    {\n    public:\n        float m00, m01, m02, m11, m12, m22;\n    public:\n        SMat3();\n        SMat3(const float m00, const float m01, const float m02,\n              const float m11, const float m12, const float m22);\n        void clear() ;\n        void setSymmetric(const float m00, const float m01, const float m02,\n                          const float m11,\n                          const float m12, const float m22) ;\n        void setSymmetric(const SMat3 &rhs) ;\n    private:\n        SMat3(const SMat3 &rhs);\n        SMat3 &operator=(const SMat3 &rhs);\n    };\n    class Mat3\n    {\n    public:\n        float m00, m01, m02, m10, m11, m12, m20, m21, m22;\n    public:\n        Mat3();\n        Mat3(const float m00, const float m01, const float m02,\n             const float m10, const float m11, const float m12,\n             const float m20, const float m21, const float m22);\n        void clear() ;\n        void set(const float m00, const float m01, const float m02,\n                 const float m10, const float m11, const float m12,\n                 const float m20, const float m21, const float m22) ;\n        void set(const Mat3 &rhs) ;\n        void setSymmetric(const float a00, const float a01, const float a02,\n                          const float a11, const float a12, const float a22) ;\n        void setSymmetric(const SMat3 &rhs);\n    private:\n        Mat3(const Mat3 &rhs);\n        Mat3 &operator=(const Mat3 &rhs);\n    };\n    class Vec3\n    {\n    public:\n        float x, y, z;\n    public:\n        Vec3();\n        Vec3(const float x, const float y, const float z);\n        void clear();\n        void set(const float x, const float y, const float z);\n        void set(const Vec3 &rhs);\n    private:\n        Vec3(const Vec3 &rhs);\n        Vec3 &operator=(const Vec3 &rhs);\n    };\n#ifndef NO_OSTREAM\n    std::ostream &operator<<(std::ostream &os, const Mat3 &m) ;\n    std::ostream &operator<<(std::ostream &os, const SMat3 &m) ;\n    std::ostream &operator<<(std::ostream &os, const Vec3 &v) ;\n#endif\n    class MatUtils\n    {\n    public:\n        static float fnorm(const Mat3 &a) ;\n        static float fnorm(const SMat3 &a) ;\n        static float off(const Mat3 &a) ;\n        static float off(const SMat3 &a) ;\n\n    public:\n        static void mmul(Mat3 &out, const Mat3 &a, const Mat3 &b) ;\n        static void mmul_ata(SMat3 &out, const Mat3 &a) ;\n        static void transpose(Mat3 &out, const Mat3 &a);\n        static void vmul(Vec3 &out, const Mat3 &a, const Vec3 &v) ;\n        static void vmul_symmetric(Vec3 &out, const SMat3 &a, const Vec3 &v) ;\n    };\n    class VecUtils\n    {\n    public:\n        static void addScaled(Vec3 &v, const float s, const Vec3 &rhs) ;\n        static float dot(const Vec3 &a, const Vec3 &b) ;\n        static void normalize(Vec3 &v) ;\n        static void scale(Vec3 &v, const float s) ;\n        static void sub(Vec3 &c, const Vec3 &a, const Vec3 &b) ;\n    };\n    class Givens\n    {\n    public:\n        static void rot01_post(Mat3 &m, const float c, const float s);\n        static void rot02_post(Mat3 &m, const float c, const float s);\n        static void rot12_post(Mat3 &m, const float c, const float s);\n    };\n    class Schur2\n    {\n    public:\n        static void rot01(SMat3 &out, float &c, float &s) ;\n        static void rot02(SMat3 &out, float &c, float &s) ;\n        static void rot12(SMat3 &out, float &c, float &s) ;\n    };\n    class Svd\n    {\n    public:\n        static void getSymmetricSvd(const SMat3 &a, SMat3 &vtav, Mat3 &v,\n                                    const float tol, const int max_sweeps);\n        static void pseudoinverse(Mat3 &out, const SMat3 &d, const Mat3 &v,\n                                  const float tol);\n        static float solveSymmetric(const SMat3 &A, const Vec3 &b, Vec3 &x,\n                                     const float svd_tol, const int svd_sweeps, const float pinv_tol);\n    };\n    class LeastSquares\n    {\n    public:\n        static float solveLeastSquares(const Mat3 &a, const Vec3 &b, Vec3 &x,\n                                        const float svd_tol, const int svd_sweeps, const float pinv_tol) ;\n    };\n};\n#endif"
  },
  {
    "path": "README.txt",
    "content": "A sample Dual Contouring implementation. For more info see http://ngildea.blogspot.co.uk/2014/11/implementing-dual-contouring.html\n\nThe octree code is based on the original reference code by Tao Ju. The QEF implementation was written by /u/unzret (on reddit.com).\nAll other code is written by Nicholas Gildea and free for any purpose, assuming that does not conflict with another license.\n\nThe sample depends on SDL2, GLM and GLEW. I don't think the particular version matters (beyond the paths in the .vcxproj file). \n\nOnly build materials for VS2013 are provided but it should be easy to move to another environment.\n\nThe controls are:\n\t- hold left mouse and drag to rotate the view\n\t- use the mouse wheel to zoom in/out\n\t- press F1 to render a wireframe\n\t- press F2 to regenerate the octree using a new error threshold (and generate a new mesh)\n\nSend any questions to nick.gildea@gmail.com or @ngildea85 on Twitter\n\n"
  }
]