This commit is contained in:
2017-11-02 12:44:44 +10:00
parent f2815b796a
commit 7b2946a961
27 changed files with 2048 additions and 742 deletions

206
src/AlignedAllocator.h Normal file
View File

@ -0,0 +1,206 @@
#pragma once
#include <malloc.h>
#include <assert.h>
#include <type_traits>
#include <memory>
enum class Alignment
: size_t
{
Normal = sizeof(void*), SSE = 16, AVX = 32,
};
namespace detail {
void* allocate_aligned_memory(size_t align, size_t size);
void deallocate_aligned_memory(void* ptr) noexcept;
}
template<typename T, Alignment Align = Alignment::SSE>
class AlignedAllocator;
template<Alignment Align>
class AlignedAllocator<void, Align> {
public:
typedef void* pointer;
typedef const void* const_pointer;
typedef void value_type;
template<class U> struct rebind {
typedef AlignedAllocator<U, Align> other;
};
};
template<typename T, Alignment Align>
class AlignedAllocator {
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef std::true_type propagate_on_container_move_assignment;
template<class U>
struct rebind {
typedef AlignedAllocator<U, Align> other;
};
public:
AlignedAllocator() noexcept
{
}
template<class U>
AlignedAllocator(const AlignedAllocator<U, Align>&) noexcept
{
}
size_type max_size() const noexcept
{
return (size_type(~0) - size_type(Align)) / sizeof(T);
}
pointer address(reference x) const noexcept
{
return std::addressof(x);
}
const_pointer address(const_reference x) const noexcept
{
return std::addressof(x);
}
pointer allocate(size_type n,
typename AlignedAllocator<void, Align>::const_pointer = 0) {
const size_type alignment = static_cast<size_type>(Align);
void* ptr = detail::allocate_aligned_memory(alignment, n * sizeof(T));
if (ptr == nullptr) {
throw std::bad_alloc();
}
return reinterpret_cast<pointer>(ptr);
}
void deallocate(pointer p, size_type) noexcept
{
detail::deallocate_aligned_memory(p);
}
template<class U, class ...Args>
void construct(U* p, Args&&... args) {
::new (reinterpret_cast<void*>(p)) U(std::forward<Args>(args)...);
}
void destroy(pointer p) {
p->~T();
}
};
template<typename T, Alignment Align>
class AlignedAllocator<const T, Align> {
public:
typedef T value_type;
typedef const T* pointer;
typedef const T* const_pointer;
typedef const T& reference;
typedef const T& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef std::true_type propagate_on_container_move_assignment;
template<class U>
struct rebind {
typedef AlignedAllocator<U, Align> other;
};
public:
AlignedAllocator() noexcept
{
}
template<class U>
AlignedAllocator(const AlignedAllocator<U, Align>&) noexcept
{
}
size_type max_size() const noexcept
{
return (size_type(~0) - size_type(Align)) / sizeof(T);
}
const_pointer address(const_reference x) const noexcept
{
return std::addressof(x);
}
pointer allocate(size_type n,
typename AlignedAllocator<void, Align>::const_pointer = 0) {
const size_type alignment = static_cast<size_type>(Align);
void* ptr = detail::allocate_aligned_memory(alignment, n * sizeof(T));
if (ptr == nullptr) {
throw std::bad_alloc();
}
return reinterpret_cast<pointer>(ptr);
}
void deallocate(pointer p, size_type) noexcept
{
detail::deallocate_aligned_memory(p);
}
template<class U, class ...Args>
void construct(U* p, Args&&... args) {
::new (reinterpret_cast<void*>(p)) U(std::forward<Args>(args)...);
}
void destroy(pointer p) {
p->~T();
}
};
template<typename T, Alignment TAlign, typename U, Alignment UAlign>
inline
bool operator==(const AlignedAllocator<T, TAlign>&,
const AlignedAllocator<U, UAlign>&) noexcept
{
return TAlign == UAlign;
}
template<typename T, Alignment TAlign, typename U, Alignment UAlign>
inline
bool operator!=(const AlignedAllocator<T, TAlign>&,
const AlignedAllocator<U, UAlign>&) noexcept
{
return TAlign != UAlign;
}
inline void*
detail::allocate_aligned_memory(size_t align, size_t size) {
assert(align >= sizeof(void*));
//assert(nail::is_power_of_two(align));
if (size == 0) {
return nullptr;
}
void* ptr = nullptr;
int rc = posix_memalign(&ptr, align, size);
if (rc != 0) {
return nullptr;
}
return ptr;
}
inline void detail::deallocate_aligned_memory(void *ptr) noexcept
{
free(ptr);
}

View File

@ -1,5 +1,6 @@
#include "Application.h"
#include "Mesh.h"
#include "Shader.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
@ -82,7 +83,8 @@ Application::Application() :
textureSize), programId(0), vPositionLoc(-1), vTexCoordLoc(-1), vNormalLoc(
-1), meteoridCount(1000), meteroidMinRadius(0.005), meteroidMaxRadius(
0.2), meteroidSizeExponent(2048), densityFrequency(2), densityOctave(
2), densityScale(1.0f), resolution(0.1), viewDistance(3.0f), fpsMode(
2), densityScale(1.0f), resolution(0.1), smoothMesh(true), viewDistance(
3.0f), fpsMode(false), meshUploadRequest(false), textureUploadRequest(
false) {
init();
}
@ -157,7 +159,6 @@ void Application::init() {
loadShader();
updateVertexArrayObject();
generateAsteroid();
uploadMesh();
}
void Application::shutdown() {
@ -215,47 +216,98 @@ void Application::toogleFpsMode() {
}
void Application::generateAsteroid() {
std::srand(123);
if (meshProgress.begin("Random Impacts", 1)) {
//if (density.getImpacts().size() == 0)
density.addRandomImpacts(1000, densityIsolevel, 0.01, 0.005, 0.2, 256);
if (density.getImpacts().size() == 0)
density.addRandomImpacts(1000, 0.2, 0.01, 0.005, 0.2, 4096);
//density.saveCrossSection("density.png", 512);
//density.saveCrossSection("density.png", 512);
}
polygonizer.polygonize(resolution, meshProgress);
polygonizer.polygonize(resolution);
if (smoothMesh && meshProgress.begin("Smooth", 1)) {
smooth(polygonizer.vertices, polygonizer.indices);
// {
// std::ofstream out("stage2.obj");
// saveAttrib(out, "v ", polygonizer.vertices);
// saveFaces(out, polygonizer.indices, 1);
// }
}
uvec4v_t edges;
if (meshProgress.begin("Find Edges", 1)) {
findEdges(polygonizer.vertices, polygonizer.indices, edges);
}
uvec3v_t adjacents;
if (meshProgress.begin("Find Adjacent", 1)) {
findAdjacent(edges, polygonizer.indices.size(), adjacents);
}
vec3v_t faceNormals;
calculateFaceNormals(polygonizer.vertices, polygonizer.indices,
faceNormals);
vec3v_t positions;
uvec3v_t indices;
uintv_t patches;
createPatches(polygonizer.vertices, polygonizer.indices, faceNormals,
adjacents, positions, indices, patches, 0.9);
{
std::ofstream out("stage1.obj");
saveAttrib(out, "v ", polygonizer.vertices);
saveFaces(out, polygonizer.indices, 1);
saveAttrib(out, "v ", positions);
saveFaces(out, indices, 1);
}
smooth(polygonizer.vertices, polygonizer.indices);
{
std::ofstream out("stage2.obj");
saveAttrib(out, "v ", polygonizer.vertices);
saveFaces(out, polygonizer.indices, 1);
}
calculateNormals(polygonizer.vertices, polygonizer.indices, normals);
{
std::ofstream out("stage3.obj");
saveAttrib(out, "v ", polygonizer.vertices);
saveAttrib(out, "vn ", normals);
saveFaces(out, polygonizer.indices, 2);
if (meshProgress.begin("Calculate Vertex Normals", 1)) {
calculateVertexNormals(polygonizer.vertices, polygonizer.indices,
normals);
// {
// std::ofstream out("stage3.obj");
// saveAttrib(out, "v ", polygonizer.vertices);
// saveAttrib(out, "vn ", normals);
// saveFaces(out, polygonizer.indices, 2);
// }
}
vector<glm::uvec4> edges;
std::cout << "Vertices: " << polygonizer.vertices.size() << std::endl;
std::cout << "Triangles: " << polygonizer.indices.size() << std::endl;
texturemapper.map(polygonizer.vertices, normals, polygonizer.indices);
moveToMean(texturemapper.vertices);
{
std::ofstream out("stage4.obj");
saveAttrib(out, "v ", texturemapper.vertices);
saveAttrib(out, "vn ", texturemapper.normals);
saveAttrib(out, "vt ", texturemapper.texcoords);
saveFaces(out, texturemapper.indices, 3);
if (meshProgress.begin("Map Textures", 1)) {
texturemapper.map(polygonizer.vertices, normals, polygonizer.indices);
}
if (meshProgress.begin("Move To Mean", 1)) {
moveToMean(texturemapper.vertices);
// {
// std::ofstream out("stage4.obj");
// saveAttrib(out, "v ", texturemapper.vertices);
// saveAttrib(out, "vn ", texturemapper.normals);
// saveAttrib(out, "vt ", texturemapper.texcoords);
// saveFaces(out, texturemapper.indices, 3);
// }
}
if (meshProgress.begin("Save", 4)) {
std::ofstream out("asteroid.obj");
saveAttrib(out, "v ", texturemapper.vertices);
meshProgress.advance();
saveAttrib(out, "vn ", texturemapper.normals);
meshProgress.advance();
saveAttrib(out, "vt ", texturemapper.texcoords);
meshProgress.advance();
saveFaces(out, texturemapper.indices, 3);
meshProgress.advance();
}
meshProgress.finish();
if (!meshProgress.isCanceled()) {
meshUploadRequest = true;
textureUploadRequest = true;
}
}
bool Application::bindVertexAttrib(GLuint id, GLint loc, GLuint size) {
@ -267,7 +319,7 @@ bool Application::bindVertexAttrib(GLuint id, GLint loc, GLuint size) {
size,// size
GL_FLOAT,// type
GL_FALSE,// normalized?
0, // stride
0,// stride
(void* ) 0// array buffer offset
))
return true;
@ -290,102 +342,7 @@ void Application::updateVertexArrayObject() {
GLCK(glBindVertexArray(0))
}
GLuint Application::loadProgram(const std::string &name) {
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// Read the Vertex Shader code from the file
std::string VertexShaderCode;
std::string vertex_file_path = "shader/" + name + ".vertex.glsl";
std::ifstream VertexShaderStream(vertex_file_path, std::ios::in);
if (VertexShaderStream.is_open()) {
std::string Line = "";
while (getline(VertexShaderStream, Line))
VertexShaderCode += "\n" + Line;
VertexShaderStream.close();
} else {
std::cout << "Failed to open " << vertex_file_path << std::endl;
return 0;
}
// Read the Fragment Shader code from the file
std::string FragmentShaderCode;
std::string fragment_file_path = "shader/" + name + ".fragment.glsl";
std::ifstream FragmentShaderStream(fragment_file_path, std::ios::in);
if (FragmentShaderStream.is_open()) {
std::string Line = "";
while (getline(FragmentShaderStream, Line))
FragmentShaderCode += "\n" + Line;
FragmentShaderStream.close();
} else {
std::cout << "Failed to open " << vertex_file_path << std::endl;
return 0;
}
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
std::cout << "Compiling vertex shader : " << name << std::endl;
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL,
&VertexShaderErrorMessage[0]);
printf("%s\n", &VertexShaderErrorMessage[0]);
}
// Compile Fragment Shader
std::cout << "Compiling fragment shader : " << name << std::endl;
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL);
glCompileShader(FragmentShaderID);
// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL,
&FragmentShaderErrorMessage[0]);
printf("%s\n", &FragmentShaderErrorMessage[0]);
}
// Link the program
std::cout << "Linking program : " << name << std::endl;
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
vector<char> ProgramErrorMessage(InfoLogLength + 1);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL,
&ProgramErrorMessage[0]);
printf("%s\n", &ProgramErrorMessage[0]);
}
glDetachShader(ProgramID, VertexShaderID);
glDetachShader(ProgramID, FragmentShaderID);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
return ProgramID;
}
void Application::loadShader() {
if (programId >= 0)
@ -409,6 +366,7 @@ void Application::loadShader() {
}
void Application::uploadMesh() {
printf("upload mesh\n");
GLCK(glBindVertexArray(vertexArrayId))
GLCK(glBindBuffer(GL_ARRAY_BUFFER, vPositionId))
@ -428,10 +386,13 @@ void Application::uploadMesh() {
glBufferData(GL_ELEMENT_ARRAY_BUFFER, texturemapper.indices.size() * sizeof(uvec3), texturemapper.indices.data(), GL_STATIC_DRAW))
GLCK(glBindVertexArray(0))
}
void Application::uploadTexture() {
printf("upload texture\n");
glBindTexture(GL_TEXTURE_2D, tAlbedoId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texturemapper.getTextureSize(),
texturemapper.getTextureSize(), 0, GL_BGR, GL_UNSIGNED_BYTE,
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texturemapper.getTextureSize(),
texturemapper.getTextureSize(), 0, GL_RGBA, GL_UNSIGNED_BYTE,
texturemapper.albedo.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -446,9 +407,11 @@ void Application::renderMesh() {
}
void Application::prepareShader() {
glm::mat4 model(1.0f);
glm::mat4 view;
double mouseX, mouseY;
glfwGetCursorPos(window, &mouseX, &mouseY);
if (fpsMode) {
glm::mat4 fpsTrafoInv = glm::inverse(fpsTrafo);
@ -458,37 +421,53 @@ void Application::prepareShader() {
} else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
movement -= glm::vec4(0.0, 0.0, 0.1, 0.0);
}
double mouseX, mouseY;
glfwGetCursorPos(window, &mouseX, &mouseY);
glm::vec3 up = fpsTrafoInv * glm::vec4(0.0, 1.0, 0.0, 0.0);
glm::vec3 side = fpsTrafoInv * glm::vec4(1.0, 0.0, 0.0, 0.0);
glm::vec3 front = fpsTrafoInv * glm::vec4(0.0, 0.0, 1.0, 0.0);
fpsTrafo = glm::rotate(fpsTrafo, (float)(mouseX - lastMouseX) * 0.01f, up);
fpsTrafo = glm::rotate(fpsTrafo, (float)(mouseY - lastMouseY) * 0.01f, side);
if (glfwGetMouseButton(window, 0) == GLFW_PRESS) {
glm::vec3 up = fpsTrafoInv * glm::vec4(0.0, 1.0, 0.0, 0.0);
glm::vec3 side = fpsTrafoInv * glm::vec4(1.0, 0.0, 0.0, 0.0);
glm::vec3 front = fpsTrafoInv * glm::vec4(0.0, 0.0, 1.0, 0.0);
fpsTrafo = glm::rotate(fpsTrafo,
(float) (mouseX - lastMouseX) * 0.01f, up);
fpsTrafo = glm::rotate(fpsTrafo,
(float) (mouseY - lastMouseY) * 0.01f, side);
}
//fpsTrafo = glm::rotate(fpsTrafo, mouseX - lastMouseX, up);
glm::vec3 absolute = fpsTrafoInv * movement;
fpsTrafo = glm::translate(fpsTrafo, absolute);
lastMouseX = mouseX;
lastMouseY = mouseY;
view = fpsTrafo;
} else {
model = glm::rotate(model, (float) glfwGetTime(), vec3(0.f, 1.f, 0.f));
if (!ImGui::IsMouseHoveringAnyWindow() && glfwGetMouseButton(window, 0) == GLFW_PRESS) {
glm::mat4 modelTrafoInv = glm::inverse(modelTrafo);
modelTrafo = glm::rotate(modelTrafo,
(float) (mouseX - lastMouseX) * 0.01f,
vec3(modelTrafoInv * glm::vec4(0.0, 1.0, 0.0, 0.0)));
modelTrafo = glm::rotate(modelTrafo,
(float) (mouseY - lastMouseY) * 0.01f,
vec3(modelTrafoInv * glm::vec4(1.0, 0.0, 0.0, 0.0)));
}
//model = glm::rotate(model, (float) glfwGetTime(), vec3(0.f, 1.f, 0.f));
view = glm::lookAt(vec3(0, 0, viewDistance), // Camera is at (4,3,3), in World Space
vec3(0, 0, 0), // and looks at the origin
vec3(0, 1, 0) // Head is up (set to 0,-1,0 to look upside-down)
);
}
lastMouseX = mouseX;
lastMouseY = mouseY;
glm::mat4 perspective = glm::perspective(glm::radians(45.0f),
(float) width / (float) height, 0.1f, 100.0f);
glm::mat4 mvp = perspective * view * model;
glm::mat4 mvp = perspective * view * modelTrafo;
GLCK(glUseProgram(programId))
if (MVPloc >= 0) {
GLCK(glUniformMatrix4fv(MVPloc, 1, GL_FALSE, glm::value_ptr(mvp)))
}
if (Mloc >= 0) {
GLCK(glUniformMatrix4fv(Mloc, 1, GL_FALSE, glm::value_ptr(model)))
GLCK(glUniformMatrix4fv(Mloc, 1, GL_FALSE, glm::value_ptr(modelTrafo)))
}
if (Vloc >= 0) {
GLCK(glUniformMatrix4fv(Vloc, 1, GL_FALSE, glm::value_ptr(view)))
@ -536,6 +515,7 @@ void Application::gui() {
density.setFrequency(densityFrequency);
if (ImGui::SliderFloat("Octave", &densityOctave, 1, 10, "%.0f", 1))
density.setOctave(densityOctave);
ImGui::Checkbox("Smooth", &smoothMesh);
// if (ImGui::InputFloat("Frequency", &densityFrequency))
// if (ImGui::InputFloat("Octave", &densityOctave))
@ -549,9 +529,17 @@ void Application::gui() {
texturemapper.setTextureSize(textureSizes[currentTextureSize]);
}
if (ImGui::Button("Generate")) {
generateAsteroid();
uploadMesh();
if (meshProgress.isRunning()) {
if (ImGui::Button("Cancel"))
meshProgress.cancel();
ImGui::Text("Task: %s", meshProgress.getTask().c_str());
ImGui::ProgressBar(meshProgress.getProgress());
} else {
if (meshProgress.isFinished() && meshThread.joinable())
meshThread.join();
if (ImGui::Button("Generate"))
meshThread = std::thread(&Application::generateAsteroid, this);
}
ImGui::End();
@ -590,6 +578,14 @@ void Application::run() {
glDepthFunc(GL_LESS);
glEnable(GL_CULL_FACE);
if (meshUploadRequest) {
uploadMesh();
meshUploadRequest = false;
}
if (textureUploadRequest) {
uploadTexture();
textureUploadRequest = false;
}
prepareShader();
renderMesh();

View File

@ -3,11 +3,13 @@
#include "Density.h"
#include "Polygoniser.h"
#include "TextureMapper.h"
#include "ProgressMonitor.h"
#include <glm/mat4x4.hpp>
#include <glm/vec3.hpp>
#include <string>
#include <thread>
struct GLFWwindow;
@ -29,10 +31,10 @@ class Application {
int vPositionLoc, vTexCoordLoc, vNormalLoc, tAlbedoLoc, tNormalLoc,
tRoughnessLoc, tMetalicLoc;
std::vector<glm::vec3> vertices;
std::vector<glm::vec3> normals;
std::vector<glm::vec2> texcoords;
std::vector<glm::uvec3> indices;
vec3v_t vertices;
vec3v_t normals;
vec2v_t texcoords;
uvec3v_t indices;
size_t meteoridCount;
float meteroidMinRadius;
@ -41,12 +43,18 @@ class Application {
float densityFrequency, densityOctave;
glm::vec3 densityScale;
float resolution;
bool smoothMesh;
float viewDistance;
glm::mat4 fpsTrafo;
bool fpsMode;
double lastMouseX, lastMouseY;
glm::mat4 modelTrafo;
ProgressMonitor meshProgress, textureProgress;
std::thread meshThread, textureThread;
bool meshUploadRequest, textureUploadRequest;
void toogleFpsMode();
public:
@ -74,11 +82,10 @@ public:
void updateVertexArrayObject();
unsigned int loadProgram(const std::string &name);
void loadShader();
void uploadMesh();
void uploadTexture();
void renderMesh();

View File

@ -53,6 +53,7 @@ public:
void setSeed(uint32_t seed) {
noise.reseed(seed);
version++;
impacts.clear();
}
@ -77,7 +78,7 @@ public:
}
float operator()(const glm::vec3 &p, bool includeImpacts = true) const {
if (includeImpacts & impacts.size()) {
if (includeImpacts && impacts.size() > 0) {
bool insideImpact = false;
impactTree.Search(&p.x, &p.x, [&](int idx) -> bool {
if (impacts[idx].contains(p)) {
@ -119,6 +120,7 @@ public:
Impact impact;
if (intersectIsolevel(start, end, impact.pos, isolevel,
resolution)) {
impact.pos -= (impact.r / 1.5f) * normalize(end-start);
impact.r = minRadius
+ pow(glm::linearRand(0.f, 1.f), exponent) * maxRadius;
addImpact(impact);

394
src/MarchingCube.cpp Normal file
View File

@ -0,0 +1,394 @@
#include "MarchingCube.h"
#include <math.h>
using namespace glm;
static const int edgeTable[256] = { 0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f,
0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895,
0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 0x230, 0x339, 0x33, 0x13a,
0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33,
0xc39, 0xd30, 0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac,
0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 0x460, 0x569,
0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66,
0x86a, 0x963, 0xa69, 0xb60, 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff,
0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c, 0xe5c, 0xf55,
0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca,
0x3c6, 0x2cf, 0x1c5, 0xcc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3,
0x9c9, 0x8c0, 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 0x950, 0x859,
0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55, 0x35f, 0x256,
0x55a, 0x453, 0x759, 0x650, 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff,
0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265,
0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460, 0xca0, 0xda9, 0xea3, 0xfaa,
0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3,
0x2a9, 0x3a0, 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230, 0xe90, 0xf99,
0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596,
0x29a, 0x393, 0x99, 0x190, 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f,
0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 };
static const int triTable[256][16] = { { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1 }, { 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1 }, { 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1 }, { 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0,
8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9,
2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 2,
8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1 }, { 3, 11,
2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0,
11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1,
9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1,
11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1 }, { 3,
10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0,
10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1 }, { 3,
9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 8,
10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 7,
8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
{ 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 1, 9,
8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 1, 9, 4,
7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 8, 4,
7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 4, 7, 3, 0, 4,
1, 2, 10, -1, -1, -1, -1, -1, -1, -1 }, { 9, 2, 10, 9, 0, 2, 8,
4, 7, -1, -1, -1, -1, -1, -1, -1 }, { 2, 10, 9, 2, 9, 7, 2, 7,
3, 7, 9, 4, -1, -1, -1, -1 }, { 8, 4, 7, 3, 11, 2, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1 }, { 11, 4, 7, 11, 2, 4, 2, 0, 4, -1,
-1, -1, -1, -1, -1, -1 }, { 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1,
-1, -1, -1, -1, -1 }, { 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1,
-1, -1, -1, -1 }, { 3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1,
-1, -1, -1, -1 }, { 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1,
-1, -1, -1 }, { 4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1,
-1, -1 }, { 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1,
-1, -1 }, { 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1 }, { 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1 }, { 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1 }, { 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1,
-1 }, { 1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1 },
{ 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, { 5, 2, 10,
5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1 }, { 2, 10, 5, 3,
2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1 }, { 9, 5, 4, 2, 3, 11,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 11, 2, 0, 8, 11,
4, 9, 5, -1, -1, -1, -1, -1, -1, -1 }, { 0, 5, 4, 0, 1, 5, 2, 3,
11, -1, -1, -1, -1, -1, -1, -1 }, { 2, 1, 5, 2, 5, 8, 2, 8, 11,
4, 8, 5, -1, -1, -1, -1 }, { 10, 3, 11, 10, 1, 3, 9, 5, 4, -1,
-1, -1, -1, -1, -1, -1 }, { 4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11,
10, -1, -1, -1, -1 }, { 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3,
-1, -1, -1, -1 }, { 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1,
-1, -1, -1, -1 }, { 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1 }, { 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1,
-1, -1, -1 }, { 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1,
-1, -1 }, { 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1 }, { 9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1,
-1 }, { 10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1 }, {
8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1 }, { 2, 10,
5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1 }, { 7, 9, 5, 7,
8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 7, 9, 7,
2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1 }, { 2, 3, 11, 0, 1, 8, 1,
7, 8, 1, 5, 7, -1, -1, -1, -1 }, { 11, 2, 1, 11, 1, 7, 7, 1, 5,
-1, -1, -1, -1, -1, -1, -1 }, { 9, 5, 8, 8, 5, 7, 10, 1, 3, 10,
3, 11, -1, -1, -1, -1 }, { 5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10,
11, 10, 0, -1 }, { 11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7,
0, -1 }, { 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1 }, { 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1 }, { 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1 }, { 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1 }, { 1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1,
-1, -1 }, { 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1 }, { 1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1,
-1 }, { 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1 },
{ 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1 }, { 2, 3, 11, 10,
6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 11, 0, 8, 11,
2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1 }, { 0, 1, 9, 2, 3,
11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1 }, { 5, 10, 6, 1, 9, 2,
9, 11, 2, 9, 8, 11, -1, -1, -1, -1 }, { 6, 3, 11, 6, 5, 3, 5, 1,
3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 11, 0, 11, 5, 0, 5, 1,
5, 11, 6, -1, -1, -1, -1 }, { 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5,
9, -1, -1, -1, -1 }, { 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1,
-1, -1, -1, -1 }, { 5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1 }, { 4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1,
-1, -1, -1 }, { 1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1,
-1, -1 },
{ 10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1 }, { 6, 1, 2, 6,
5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 5, 5, 2, 6,
3, 0, 4, 3, 4, 7, -1, -1, -1, -1 }, { 8, 4, 7, 9, 0, 5, 0, 6, 5,
0, 2, 6, -1, -1, -1, -1 }, { 7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6,
2, 6, 9, -1 }, { 3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1,
-1, -1, -1 }, { 5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1,
-1, -1 },
{ 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1 }, { 9, 2, 1, 9,
11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1 }, { 8, 4, 7, 3, 11, 5,
3, 5, 1, 5, 11, 6, -1, -1, -1, -1 }, { 5, 1, 11, 5, 11, 6, 1, 0,
11, 7, 11, 4, 0, 4, 11, -1 }, { 0, 5, 9, 0, 6, 5, 0, 3, 6, 11,
6, 3, 8, 4, 7, -1 }, { 6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1,
-1, -1, -1 }, { 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1 }, { 4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1,
-1, -1 }, { 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1,
-1 }, { 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1 }, {
1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0,
8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1 }, { 0, 2, 4, 4, 2,
6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 3, 2, 8, 2, 4,
4, 2, 6, -1, -1, -1, -1, -1, -1, -1 }, { 10, 4, 9, 10, 6, 4, 11,
2, 3, -1, -1, -1, -1, -1, -1, -1 }, { 0, 8, 2, 2, 8, 11, 4, 9,
10, 4, 10, 6, -1, -1, -1, -1 }, { 3, 11, 2, 0, 1, 6, 0, 6, 4, 6,
1, 10, -1, -1, -1, -1 }, { 6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11,
8, 11, 1, -1 }, { 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1,
-1, -1 }, { 8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1 },
{ 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1 }, { 6, 4, 8,
11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 7, 10, 6,
7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, { 0, 7, 3, 0,
10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1 }, { 10, 6, 7, 1, 10,
7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1 }, { 10, 6, 7, 10, 7, 1, 1,
7, 3, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 6, 1, 6, 8, 1, 8, 9,
8, 6, 7, -1, -1, -1, -1 }, { 2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3,
7, 3, 9, -1 }, { 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1,
-1, -1 }, { 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1 }, { 2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1,
-1 }, { 2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1 }, {
1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1 }, { 11, 2,
1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1 }, { 8, 9, 6, 8,
6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1 }, { 0, 9, 1, 11, 6, 7, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 7, 8, 0, 7, 0, 6, 3, 11,
0, 11, 6, 0, -1, -1, -1, -1 }, { 7, 11, 6, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 }, { 7, 6, 11, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 8, 11, 7, 6, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 1, 9, 11, 7, 6, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 8, 1, 9, 8, 3, 1, 11, 7,
6, -1, -1, -1, -1, -1, -1, -1 }, { 10, 1, 2, 6, 11, 7, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2, 10, 3, 0, 8, 6, 11, 7,
-1, -1, -1, -1, -1, -1, -1 }, { 2, 9, 0, 2, 10, 9, 6, 11, 7, -1,
-1, -1, -1, -1, -1, -1 }, { 6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9,
8, -1, -1, -1, -1 }, { 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1 }, { 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1,
-1, -1, -1 }, { 2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1,
-1, -1 },
{ 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1 }, { 10, 7, 6, 10,
1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, { 10, 7, 6, 1, 7,
10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1 }, { 0, 3, 7, 0, 7, 10, 0,
10, 9, 6, 10, 7, -1, -1, -1, -1 }, { 7, 6, 10, 7, 10, 8, 8, 10,
9, -1, -1, -1, -1, -1, -1, -1 }, { 6, 8, 4, 11, 8, 6, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 6, 11, 3, 0, 6, 0, 4, 6,
-1, -1, -1, -1, -1, -1, -1 }, { 8, 6, 11, 8, 4, 6, 9, 0, 1, -1,
-1, -1, -1, -1, -1, -1 }, { 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6,
-1, -1, -1, -1 }, { 6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1,
-1, -1, -1 }, { 1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1,
-1, -1 }, { 4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1,
-1 }, { 10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1 }, {
8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, { 0, 4,
2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 9, 0,
2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1 }, { 1, 9, 4, 1, 4, 2,
2, 4, 6, -1, -1, -1, -1, -1, -1, -1 }, { 8, 1, 3, 8, 6, 1, 8, 4,
6, 6, 10, 1, -1, -1, -1, -1 }, { 10, 1, 0, 10, 0, 6, 6, 0, 4,
-1, -1, -1, -1, -1, -1, -1 }, { 4, 6, 3, 4, 3, 8, 6, 10, 3, 0,
3, 9, 10, 9, 3, -1 }, { 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1 }, { 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1 }, { 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1,
-1, -1, -1, -1 }, { 5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1,
-1, -1, -1 }, { 11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1,
-1 },
{ 9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1 }, { 6, 11, 7,
1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1 }, { 7, 6, 11, 5, 4,
10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1 }, { 3, 4, 8, 3, 5, 4, 3,
2, 5, 10, 5, 2, 11, 7, 6, -1 }, { 7, 2, 3, 7, 6, 2, 5, 4, 9, -1,
-1, -1, -1, -1, -1, -1 }, { 9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7,
-1, -1, -1, -1 }, { 3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1,
-1, -1 }, { 6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1 }, {
9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1 }, { 1, 6,
10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1 }, { 4, 0, 10, 4, 10,
5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1 }, { 7, 6, 10, 7, 10, 8, 5,
4, 10, 4, 8, 10, -1, -1, -1, -1 }, { 6, 9, 5, 6, 11, 9, 11, 8,
9, -1, -1, -1, -1, -1, -1, -1 }, { 3, 6, 11, 0, 6, 3, 0, 5, 6,
0, 9, 5, -1, -1, -1, -1 }, { 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6,
11, -1, -1, -1, -1 }, { 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1,
-1, -1, -1, -1 }, { 1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1,
-1, -1, -1 }, { 0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10,
-1 }, { 11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1 }, {
6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1 }, { 5, 8,
9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1 }, { 9, 5, 6, 9, 6,
0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1 }, { 1, 5, 8, 1, 8, 0, 5,
6, 8, 3, 8, 2, 6, 2, 8, -1 }, { 1, 5, 6, 2, 1, 6, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1 }, { 1, 3, 6, 1, 6, 10, 3, 8, 6, 5,
6, 9, 8, 9, 6, -1 }, { 10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1,
-1, -1, -1 }, { 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1 }, { 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1 }, { 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1 }, { 11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1,
-1, -1, -1, -1 }, { 5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1,
-1, -1, -1, -1 }, { 10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1,
-1, -1, -1 }, { 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1,
-1, -1 },
{ 0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1 }, { 9, 7, 5, 9,
2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1 }, { 7, 5, 2, 7, 2, 11,
5, 9, 2, 3, 2, 8, 9, 8, 2, -1 }, { 2, 5, 10, 2, 3, 5, 3, 7, 5,
-1, -1, -1, -1, -1, -1, -1 }, { 8, 2, 0, 8, 5, 2, 8, 7, 5, 10,
2, 5, -1, -1, -1, -1 }, { 9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2,
-1, -1, -1, -1 }, { 9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5,
2, -1 }, { 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1 }, { 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1 },
{ 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1 }, { 9, 8, 7, 5,
9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 5, 8, 4, 5,
10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, { 5, 0, 4, 5,
11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1 }, { 0, 1, 9, 8, 4,
10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1 }, { 10, 11, 4, 10, 4,
5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1 }, { 2, 5, 1, 2, 8, 5, 2, 11,
8, 4, 5, 8, -1, -1, -1, -1 }, { 0, 4, 11, 0, 11, 3, 4, 5, 11, 2,
11, 1, 5, 1, 11, -1 }, { 0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8,
11, 8, 5, -1 }, { 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1 }, { 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1,
-1 },
{ 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1 }, { 3, 10, 2,
3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1 }, { 5, 10, 2, 5, 2, 4,
1, 9, 2, 9, 4, 2, -1, -1, -1, -1 }, { 8, 4, 5, 8, 5, 3, 3, 5, 1,
-1, -1, -1, -1, -1, -1, -1 }, { 0, 4, 5, 1, 0, 5, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1 }, { 8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3,
5, -1, -1, -1, -1 }, { 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1 }, { 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1,
-1, -1, -1, -1, -1 }, { 0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11,
-1, -1, -1, -1 }, { 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1,
-1, -1, -1 }, { 3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4,
-1 }, { 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1 },
{ 9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1 }, { 11, 7, 4, 11,
4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1 }, { 11, 7, 4, 11, 4,
2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1 }, { 2, 9, 10, 2, 7, 9, 2,
3, 7, 7, 4, 9, -1, -1, -1, -1 }, { 9, 10, 7, 9, 7, 4, 10, 2, 7,
8, 7, 0, 2, 0, 7, -1 }, { 3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10,
0, 4, 0, 10, -1 }, { 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1 }, { 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1,
-1, -1, -1 }, { 4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1,
-1 },
{ 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 4, 8, 7,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 9, 10,
8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0,
9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1 }, { 0, 1,
10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1 }, { 3, 1,
10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 2,
11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1 }, { 3, 0, 9,
3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1 }, { 0, 2, 11, 8, 0,
11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 3, 2, 11, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 2, 3, 8, 2,
8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1 }, { 9, 10, 2, 0, 9,
2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 2, 3, 8, 2, 8,
10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1 }, { 1, 10, 2, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 1, 3, 8, 9, 1, 8,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 9, 1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { 0, 3, 8, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, { -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } };
/*
Linearly interpolate the position where an isosurface cuts
an edge between two vertices, each with their own scalar value
*/
XYZ VertexInterp(double isolevel, XYZ p1, XYZ p2, double valp1, double valp2) {
double mu;
XYZ p;
float dx = p2.x - p1.x;
float dy = p2.y - p1.y;
float dz = p2.z - p1.z;
float eps = sqrt(dx*dx+dy*dy+dz*dz) * 0.05;
if (fabs(isolevel - valp1) < eps)
return (p1);
if (fabs(isolevel - valp2) < eps)
return (p2);
if (fabs(valp1 - valp2) < 0.0001)
return (p1);
mu = (isolevel - valp1) / (valp2 - valp1);
p.x = p1.x + mu * dx;
p.y = p1.y + mu * dy;
p.z = p1.z + mu * dz;
return (p);
}
/*
Given a grid cell and an isolevel, calculate the triangular
facets required to represent the isosurface through the cell.
Return the number of triangular facets, the array "triangles"
will be loaded up with the vertices at most 5 triangular facets.
0 will be returned if the grid cell is either totally above
of totally below the isolevel.
*/
int Polygonise(GRIDCELL &grid, double isolevel, TRIANGLE *triangles) {
int i, ntriang;
int cubeindex;
XYZ vertlist[12];
/*
Determine the index into the edge table which
tells us which vertices are inside of the surface
*/
cubeindex = 0;
if (grid.val[0] < isolevel)
cubeindex |= 1;
if (grid.val[1] < isolevel)
cubeindex |= 2;
if (grid.val[2] < isolevel)
cubeindex |= 4;
if (grid.val[3] < isolevel)
cubeindex |= 8;
if (grid.val[4] < isolevel)
cubeindex |= 16;
if (grid.val[5] < isolevel)
cubeindex |= 32;
if (grid.val[6] < isolevel)
cubeindex |= 64;
if (grid.val[7] < isolevel)
cubeindex |= 128;
/* Cube is entirely in/out of the surface */
if (edgeTable[cubeindex] == 0)
return (0);
/* Find the vertices where the surface intersects the cube */
if (edgeTable[cubeindex] & 1)
vertlist[0] = VertexInterp(isolevel, grid.p[0], grid.p[1], grid.val[0],
grid.val[1]);
if (edgeTable[cubeindex] & 2)
vertlist[1] = VertexInterp(isolevel, grid.p[1], grid.p[2], grid.val[1],
grid.val[2]);
if (edgeTable[cubeindex] & 4)
vertlist[2] = VertexInterp(isolevel, grid.p[2], grid.p[3], grid.val[2],
grid.val[3]);
if (edgeTable[cubeindex] & 8)
vertlist[3] = VertexInterp(isolevel, grid.p[3], grid.p[0], grid.val[3],
grid.val[0]);
if (edgeTable[cubeindex] & 16)
vertlist[4] = VertexInterp(isolevel, grid.p[4], grid.p[5], grid.val[4],
grid.val[5]);
if (edgeTable[cubeindex] & 32)
vertlist[5] = VertexInterp(isolevel, grid.p[5], grid.p[6], grid.val[5],
grid.val[6]);
if (edgeTable[cubeindex] & 64)
vertlist[6] = VertexInterp(isolevel, grid.p[6], grid.p[7], grid.val[6],
grid.val[7]);
if (edgeTable[cubeindex] & 128)
vertlist[7] = VertexInterp(isolevel, grid.p[7], grid.p[4], grid.val[7],
grid.val[4]);
if (edgeTable[cubeindex] & 256)
vertlist[8] = VertexInterp(isolevel, grid.p[0], grid.p[4], grid.val[0],
grid.val[4]);
if (edgeTable[cubeindex] & 512)
vertlist[9] = VertexInterp(isolevel, grid.p[1], grid.p[5], grid.val[1],
grid.val[5]);
if (edgeTable[cubeindex] & 1024)
vertlist[10] = VertexInterp(isolevel, grid.p[2], grid.p[6], grid.val[2],
grid.val[6]);
if (edgeTable[cubeindex] & 2048)
vertlist[11] = VertexInterp(isolevel, grid.p[3], grid.p[7], grid.val[3],
grid.val[7]);
/* Create the triangle */
ntriang = 0;
for (i = 0; triTable[cubeindex][i] != -1; i += 3) {
triangles[ntriang].p[0] = vertlist[triTable[cubeindex][i]];
triangles[ntriang].p[1] = vertlist[triTable[cubeindex][i + 1]];
triangles[ntriang].p[2] = vertlist[triTable[cubeindex][i + 2]];
ntriang++;
}
return (ntriang);
}

16
src/MarchingCube.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <glm/vec3.hpp>
typedef glm::vec3 XYZ;
struct TRIANGLE {
XYZ p[3];
};
struct GRIDCELL {
XYZ p[8];
double val[8];
} ;
int Polygonise(GRIDCELL &grid, double isolevel, TRIANGLE *triangles);

View File

@ -3,16 +3,25 @@
#include <glm/geometric.hpp>
#include <map>
#include <limits>
#include <stack>
using namespace std;
using namespace glm;
void calculateNormals(const vec3v_t &vtx, uvec3v_t &tri, vec3v_t &normals) {
static const uvec3::value_type InvalidIndex =
numeric_limits<uvec3::value_type>::max();
void calculateVertexNormals(const vec3v_t &positions, uvec3v_t &indices,
vec3v_t &normals) {
normals.clear();
normals.resize(vtx.size(), vec3(0));
for (size_t i = 0; i < tri.size(); i++) {
int a = tri[i].x, b = tri[i].y, c = tri[i].z;
vec3 faceNormal = normalize(cross(vtx[b] - vtx[a], vtx[c] - vtx[a]));
normals.resize(positions.size(), vec3(0));
#pragma omp parallel for
for (size_t i = 0; i < indices.size(); i++) {
int a = indices[i].x, b = indices[i].y, c = indices[i].z;
vec3 faceNormal = normalize(
cross(positions[b] - positions[a],
positions[c] - positions[a]));
normals[a] += faceNormal;
normals[b] += faceNormal;
normals[c] += faceNormal;
@ -22,27 +31,40 @@ void calculateNormals(const vec3v_t &vtx, uvec3v_t &tri, vec3v_t &normals) {
}
void moveToMean(vec3v_t &vtx) {
vec3 mean(0);
for (size_t i = 0; i < vtx.size(); i++) {
mean += vtx[i];
}
mean *= vec3(1.f / vtx.size());
for (size_t i = 0; i < vtx.size(); i++) {
vtx[i] -= mean;
void calculateFaceNormals(const vec3v_t &positions, uvec3v_t &indices,
vec3v_t &normals) {
normals.clear();
normals.resize(indices.size(), vec3(uninitialize));
#pragma omp parallel for
for (size_t i = 0; i < indices.size(); i++) {
int a = indices[i].x, b = indices[i].y, c = indices[i].z;
normals[i] = normalize(
cross(positions[b] - positions[a],
positions[c] - positions[a]));
}
}
void smooth(vec3v_t &vtx, const uvec3v_t &tri) {
vec3v_t cogs(vtx.size(), vec3(0.f));
vector<int> valence(vtx.size(), 0);
void moveToMean(vec3v_t &positions) {
vec3 mean(0);
for (size_t i = 0; i < positions.size(); i++) {
mean += positions[i];
}
mean *= vec3(1.f / positions.size());
for (size_t i = 0; i < positions.size(); i++) {
positions[i] -= mean;
}
}
for (size_t iTri = 0; iTri < tri.size(); iTri++) {
const uvec3 &idx = tri[iTri];
void smooth(vec3v_t &positions, const uvec3v_t &indices) {
vec3v_t cogs(positions.size(), vec3(0.f));
vector<int> valence(positions.size(), 0);
for (size_t iTri = 0; iTri < indices.size(); iTri++) {
const uvec3 &idx = indices[iTri];
for (size_t iE = 0; iE < 3; iE++) {
valence[idx[iE]] += 2;
cogs[idx[iE]] += vtx[idx[(iE + 1) % 3]];
cogs[idx[iE]] += vtx[idx[(iE + 2) % 3]];
cogs[idx[iE]] += positions[idx[(iE + 1) % 3]];
cogs[idx[iE]] += positions[idx[(iE + 2) % 3]];
}
}
/*
@ -61,10 +83,11 @@ void smooth(vec3v_t &vtx, const uvec3v_t &tri) {
mesh.set_point(*v_it, *cog_it);
*/
for (size_t i = 0; i < vtx.size(); i++) {
#pragma omp parallel for
for (size_t i = 0; i < positions.size(); i++) {
// vtx[i] = vtx[i] * vec3(0.8)
// + cogs[i] * vec3(0.2f / valence[i]);
vtx[i] = cogs[i] * vec3(1.f / valence[i]);
positions[i] = cogs[i] * vec3(1.f / valence[i]);
}
}
@ -81,12 +104,12 @@ void saveAttrib(std::ostream &out, const char *prefix, vec2v_t &elements) {
}
}
void saveFaces(std::ostream &out, const uvec3v_t &tris, size_t attribs) {
for (size_t i = 0; i < tris.size(); i++) {
void saveFaces(std::ostream &out, const uvec3v_t &incdices, size_t attribs) {
for (size_t i = 0; i < incdices.size(); i++) {
out << "f";
for (size_t j = 0; j < 3; j++) {
int v = tris[i][j] + 1;
int v = incdices[i][j] + 1;
out << " " << v;
if (attribs > 1)
out << "/" << v;
@ -99,39 +122,43 @@ void saveFaces(std::ostream &out, const uvec3v_t &tris, size_t attribs) {
}
}
void findEdges(const vec3v_t &vtx, uvec3v_t &tri, uvec4v_t &edges) {
void findEdges(const vec3v_t &positions, const uvec3v_t &indices,
uvec4v_t &edges) {
edges.clear();
map<pair<uint32_t, uint32_t>, uint32_t> edgeMap;
for (size_t iTri = 0; iTri < tri.size(); iTri++) {
uvec3 idx = tri[iTri];
for (size_t iTri = 0; iTri < indices.size(); iTri++) {
uvec3 idx = indices[iTri];
for (size_t k = 0; k < 3; k++) {
int a = idx[k];
int b = idx[(k + 1) % 3];
uvec4 edge1(std::min(a, b), std::max(a, b), iTri, 0);
auto it1 = edgeMap.find(std::make_pair(edge1.x, edge1.y));
auto key = std::make_pair(edge1.x, edge1.y);
auto it1 = edgeMap.find(key);
if (it1 != edgeMap.end()) {
edges[it1->second].z = iTri;
edges[it1->second].w = iTri;
} else {
size_t idx = edges.size();
edges.push_back(edge1);
edgeMap[key] = idx;
}
}
}
}
void computeTangentBasis(vec3v_t & vertices, vec2v_t & uvs, vec3v_t & normals,
vec3v_t & tangents, vec3v_t & bitangents) {
void computeTangentBasis(vec3v_t & positions, vec2v_t & texcoords,
vec3v_t & normals, vec3v_t & tangents, vec3v_t & bitangents) {
for (size_t i = 0; i < vertices.size(); i += 3) {
for (size_t i = 0; i < positions.size(); i += 3) {
// Shortcuts for vertices
vec3 & v0 = vertices[i + 0];
vec3 & v1 = vertices[i + 1];
vec3 & v2 = vertices[i + 2];
vec3 & v0 = positions[i + 0];
vec3 & v1 = positions[i + 1];
vec3 & v2 = positions[i + 2];
// Shortcuts for UVs
vec2 & uv0 = uvs[i + 0];
vec2 & uv1 = uvs[i + 1];
vec2 & uv2 = uvs[i + 2];
vec2 & uv0 = texcoords[i + 0];
vec2 & uv1 = texcoords[i + 1];
vec2 & uv2 = texcoords[i + 2];
// Edges of the triangle : postion delta
vec3 deltaPos1 = v1 - v0;
@ -157,3 +184,85 @@ void computeTangentBasis(vec3v_t & vertices, vec2v_t & uvs, vec3v_t & normals,
}
}
void findAdjacent(const uvec4v_t &edges, size_t nFaces, uvec3v_t &adjacents) {
printf("findAdjacent: %lu\n", nFaces);
adjacents.resize(nFaces, uvec3(InvalidIndex));
for (size_t i = 0; i < edges.size(); i++) {
int a = edges[i].z;
int b = edges[i].w;
uvec3 &aa = adjacents[a];
for (size_t j = 0; j < 3; j++) {
if (aa[j] == InvalidIndex) {
aa[j] = b;
break;
}
}
uvec3 &ab = adjacents[b];
for (size_t j = 0; j < 3; j++) {
if (ab[j] == InvalidIndex) {
ab[j] = a;
break;
}
}
}
}
void createPatches(const vec3v_t &positions, const uvec3v_t &indices,
const vec3v_t &faceNormals, const uvec3v_t &adjacents,
vec3v_t &oPositions, uvec3v_t &oIndices, uintv_t &patches,
float threshold) {
assert(adjacents.size() == indices.size());
patches.clear();
oPositions.clear();
oIndices.clear();
vector<bool> processed(indices.size(), false);
for (size_t i = 0; i < indices.size(); i++) {
if (processed[i])
continue;
vector<uint32_t> faces;
map<uint32_t, uint32_t> vertexMap;
vec3 normal = faceNormals[i];
// check all adjacent faces
stack<uint32_t> facesToCheck;
facesToCheck.push(i);
while (facesToCheck.size()) {
uint32_t face = facesToCheck.top();
facesToCheck.pop();
if (face == InvalidIndex || processed[face])
continue;
if (dot(normal, faceNormals[face]) > threshold) {
faces.push_back(face);
//normal = normalize(normal + 0.5f * faceNormals[face]);
processed[face] = true;
facesToCheck.push(adjacents[face].x);
facesToCheck.push(adjacents[face].y);
facesToCheck.push(adjacents[face].z);
}
}
// fill new arrays
for (size_t j = 0; j < faces.size(); j++) {
uvec3 idx = indices[faces[j]];
for (size_t k = 0; k < 3; k++) {
auto it = vertexMap.find(idx[k]);
if (it == vertexMap.end()) {
uint32_t newIdx = oPositions.size();
oPositions.push_back(positions[idx[k]]);
vertexMap[idx[k]] = newIdx;
idx[k] = newIdx;
} else {
idx[k] = it->second;
}
}
oIndices.push_back(idx);
}
printf("\n");
}
}

View File

@ -1,28 +1,35 @@
#pragma once
#include "types.h"
#include <vector>
#include <ostream>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
void calculateVertexNormals(const vec3v_t &positions, uvec3v_t &indices,
vec3v_t &normals);
void calculateFaceNormals(const vec3v_t &positions, uvec3v_t &indices,
vec3v_t &normals);
void findEdges(const vec3v_t &positions, const uvec3v_t &indices,
uvec4v_t &edges);
//void createPatches(const vec3v_t &positions, const uvec3v_t &indices,
// const uvec4v_t &edges, vec3v_t &oPositions, uvec3v_t &oIndices,
// uvec4v_t &oEdges, uintv_t &patches, float threshold);
typedef std::vector<glm::vec3> vec3v_t;
typedef std::vector<glm::vec2> vec2v_t;
typedef std::vector<glm::uvec3> uvec3v_t;
typedef std::vector<glm::uvec4> uvec4v_t;
void moveToMean(vec3v_t &positions);
void calculateNormals(const vec3v_t &vtx, uvec3v_t &tri, vec3v_t &normals);
void findEdges(const vec3v_t &vtx, uvec3v_t &tri, uvec4v_t &edges);
void moveToMean(vec3v_t &vtx);
void smooth(vec3v_t &vtx, const uvec3v_t &tri);
void smooth(vec3v_t &positions, const uvec3v_t &indices);
void saveAttrib(std::ostream &out, const char *prefix, vec3v_t &elements);
void saveAttrib(std::ostream &out, const char *prefix, vec2v_t &elements);
void saveFaces(std::ostream &out, const uvec3v_t &tris, size_t attribs);
void saveFaces(std::ostream &out, const uvec3v_t &indicess, size_t attributes);
void computeTangentBasis(vec3v_t & vertices, vec2v_t & uvs, vec3v_t & normals,
vec3v_t & tangents, vec3v_t & bitangents);
void findAdjacent(const uvec4v_t &edges, size_t nFaces, uvec3v_t &adjacents);
void computeTangentBasis(vec3v_t & vertices, vec2v_t & texcoords,
vec3v_t & normals, vec3v_t & tangents, vec3v_t & bitangents);
void createPatches(const vec3v_t &positions, const uvec3v_t &indices,
const vec3v_t &faceNormals, const uvec3v_t &adjacents,
vec3v_t &oPositions, uvec3v_t &oIndices, uintv_t &patches,
float threshold);

View File

@ -5,31 +5,33 @@
#include <glm/gtc/epsilon.hpp>
#include <MarchingCube.h>
#include "MarchingCube.h"
static const int isocells = 32;
using namespace glm;
#define ISOCELL 0
static const int isocells = 50;
Polygonizer::Polygonizer(Density &density, float isolevel) :
density(density), isolevel(isolevel) {
updateIsocell();
density(density), isolevel(isolevel), isocellIsolevel(0), isocellVersion(
0) {
}
void Polygonizer::setIsoLevel(float isolevel) {
bool needIsocellUpdate = false;
if (this->isolevel != isolevel) {
this->isolevel = isolevel;
needIsocellUpdate = true;
}
needIsocellUpdate |= (isocellVersion != density.getVersion());
if (needIsocellUpdate)
updateIsocell();
this->isolevel = isolevel;
}
#if ISOCELL
void Polygonizer::updateIsocell() {
if (density.getVersion() == isocellVersion && isocellIsolevel == isolevel)
return;
isocell.clear();
isocell.reserve(isocells * isocells * isocells);
isocell.resize(isocells * isocells * isocells);
float step = 1. / isocells;
const float lowerIso = isolevel * 0.7;
const float upperIso = isolevel * 1.3;
const float step = 1. / isocells;
#pragma omp parallel for
for (size_t ix = 0; ix < isocells; ix++) {
float xmin = ix * step;
float xmax = xmin + step;
@ -41,10 +43,10 @@ void Polygonizer::updateIsocell() {
float Xyz = density(vec3(xmax, ymin, 0));
float xYz = density(vec3(xmin, ymax, 0));
float XYz = density(vec3(xmax, ymax, 0));
bool zAllUnder = (xyz < isolevel) && (Xyz < isolevel)
&& (xYz < isolevel) && (XYz < isolevel);
bool zAllOver = (xyz > isolevel) && (Xyz > isolevel)
&& (xYz > isolevel) && (XYz > isolevel);
bool zAllUnder = (xyz < lowerIso) && (Xyz < lowerIso)
&& (xYz < lowerIso) && (XYz < lowerIso);
bool zAllOver = (xyz > upperIso) && (Xyz > upperIso)
&& (xYz > upperIso) && (XYz > upperIso);
for (size_t iz = 0; iz < isocells; iz++) {
float zmin = iz * step;
@ -54,13 +56,13 @@ void Polygonizer::updateIsocell() {
float XyZ = density(vec3(xmax, ymin, zmax));
float xYZ = density(vec3(xmin, ymax, zmax));
float XYZ = density(vec3(xmax, ymax, zmax));
bool ZAllUnder = (xyZ < isolevel) && (XyZ < isolevel)
&& (xYZ < isolevel) && (XYZ < isolevel);
bool ZAllOver = (xyZ > isolevel) && (XyZ > isolevel)
&& (xYZ > isolevel) && (XYZ > isolevel);
bool ZAllUnder = (xyZ < lowerIso) && (XyZ < lowerIso)
&& (xYZ < lowerIso) && (XYZ < lowerIso);
bool ZAllOver = (xyZ > upperIso) && (XyZ > upperIso)
&& (xYZ > upperIso) && (XYZ > upperIso);
isocell[ix * isocells * isocells + iy * isocells + iz] =
(zAllUnder && ZAllUnder) || (zAllOver && ZAllOver);
!((zAllUnder && ZAllUnder) || (zAllOver && ZAllOver));
xyz = xyZ;
Xyz = XyZ;
@ -71,19 +73,25 @@ void Polygonizer::updateIsocell() {
}
}
}
size_t n = 0;
for(size_t i = 0; i < isocell.size(); i++)
if(isocell[i]) n++;
printf("%lu / %lu", n, isocell.size());
isocellVersion = density.getVersion();
isocellIsolevel = isolevel;
}
void Polygonizer::polygonize(const glm::vec3 lower, const glm::vec3 upper,
void Polygonizer::polygonize(const vec3 &lower, const vec3 &upper,
float resolution) {
size_t nSteps = 1.f / resolution - 1;
size_t nT = 0;
for (size_t ix = 0; ix < nSteps; ix++) {
vec3 l = round(lower * vec3(1.f / resolution));
vec3 u = round(upper * vec3(1.f / resolution));
for (size_t ix = l.x; ix < u.x; ix++) {
double x = (double(ix) + 0.5) * resolution;
for (size_t iy = 0; iy < nSteps; iy++) {
for (size_t iy = l.y; iy < u.y; iy++) {
double y = (double(iy) + 0.5) * resolution;
for (size_t iz = 0; iz < nSteps; iz++) {
for (size_t iz = l.z; iz < u.z; iz++) {
double z = (double(iz) + 0.5) * resolution;
GRIDCELL gridCell;
@ -103,7 +111,6 @@ void Polygonizer::polygonize(const glm::vec3 lower, const glm::vec3 upper,
TRIANGLE tris[6];
int nTris = Polygonise(gridCell, isolevel, tris);
nT += nTris;
for (int iTri = 0; iTri < nTris; iTri++) {
vec3 *ps = tris[iTri].p;
@ -111,13 +118,13 @@ void Polygonizer::polygonize(const glm::vec3 lower, const glm::vec3 upper,
if (all(epsilonEqual(ps[0], ps[1], 1e-8f))
|| all(epsilonEqual(ps[0], ps[2], 1e-8f))
|| all(epsilonEqual(ps[2], ps[1], 1e-8f)))
continue;
continue;
glm::uvec3 idc;
uvec3 idc;
for (size_t k = 0; k < 3; k++) {
glm::vec3 &p = tris[iTri].p[k];
std::map<glm::vec3, int>::iterator vit =
vertexLookup.find(p);
vec3 &p = tris[iTri].p[k];
std::map<vec3, int>::iterator vit = vertexLookup.find(
p);
if (vit != vertexLookup.end()) {
idc[k] = vit->second;
} else {
@ -138,36 +145,116 @@ void Polygonizer::polygonize(float resolution) {
vertices.clear();
indices.clear();
// coarse scan
float coarseResolution = resolution * 10;
const float isocellSize = 1.f / isocells;
if (resolution < isocellSize) {
updateIsocell();
size_t nSteps = 1.f / resolution - 1;
size_t nT = 0;
for (size_t ix = 0; ix < nSteps; ix++) {
double x = (double(ix) + 0.5) * resolution;
for (size_t iy = 0; iy < nSteps; iy++) {
double y = (double(iy) + 0.5) * resolution;
for (size_t iz = 0; iz < nSteps; iz++) {
double z = (double(iz) + 0.5) * resolution;
vec3 lower, upper;
for (size_t ix = 0; ix < isocells - 1; ix++) {
lower.x = double(ix) * isocellSize;
upper.x = lower.x + isocellSize;
for (size_t iy = 0; iy < isocells - 1; iy++) {
lower.y = (double(iy) + 0.5) * isocellSize;
upper.y = lower.y + isocellSize;
for (size_t iz = 0; iz < isocells - 1; iz++) {
if (!isocell[ix * isocells * isocells + iy * isocells + iz])
continue;
lower.z = (double(iz) + 0.5) * isocellSize;
upper.z = lower.z + isocellSize;
GRIDCELL gridCell;
gridCell.p[0] = vec3(x, y, z);
gridCell.p[1] = vec3(x + resolution, y, z);
gridCell.p[2] = vec3(x + resolution, y + resolution, z);
gridCell.p[3] = vec3(x, y + resolution, z);
gridCell.p[4] = vec3(x, y, z + resolution);
gridCell.p[5] = vec3(x + resolution, y, z + resolution);
gridCell.p[6] = vec3(x + resolution, y + resolution,
z + resolution);
gridCell.p[7] = vec3(x, y + resolution, z + resolution);
for (size_t iCell = 0; iCell < 8; iCell++) {
gridCell.val[iCell] = density(gridCell.p[iCell]);
polygonize(lower, upper, resolution);
}
}
}
} else {
polygonize(vec3(0.f), vec3(1.0f), resolution);
}
}
#else
void Polygonizer::calculateLayer(std::vector<float> &layer, float resolution,
size_t nSamples, float z) {
#pragma omp parallel for
for (size_t iy = 0; iy < nSamples; iy++) {
float y = iy * resolution;
size_t offset = iy * nSamples;
for (size_t ix = 0; ix < nSamples; ix++) {
float x = ix * resolution;
layer[offset + ix] = density(glm::vec3(x, y, z));
}
}
}
void Polygonizer::polygonize(float resolution, ProgressMonitor &progress) {
vertexLookup.clear();
vertices.clear();
indices.clear();
vertices.reserve(pow(1. / resolution, 2) * 8);
indices.reserve(pow(1. / resolution, 2) * 8);
size_t nSteps = 1.f / resolution;
size_t nSamples = nSteps + 1;
// precalculate 2 layers
std::vector<float> layers[2];
layers[0].resize(nSamples * nSamples);
layers[1].resize(nSamples * nSamples);
calculateLayer(layers[0], resolution, nSamples, 0.0);
progress.begin("Polygonize", nSteps);
for (size_t iz = 0; iz < nSteps; iz++) {
std::vector<float> &zLayer = layers[iz % 2];
std::vector<float> &ZLayer = layers[(iz + 1) % 2];
float z = iz * resolution;
float Z = z + resolution;
calculateLayer(ZLayer, resolution, nSamples, Z);
if (!progress.advance())
break;
for (size_t iy = 0; iy < nSteps; iy++) {
float y = iy * resolution;
float Y = y + resolution;
size_t yOffset = iy * nSamples;
size_t YOffset = yOffset + nSamples;
GRIDCELL gridCell;
gridCell.p[0] = vec3(0, y, z);
gridCell.p[1] = vec3(0, y, z);
gridCell.p[2] = vec3(0, Y, z);
gridCell.p[3] = vec3(0, Y, z);
gridCell.p[4] = vec3(0, y, Z);
gridCell.p[5] = vec3(0, y, Z);
gridCell.p[6] = vec3(0, Y, Z);
gridCell.p[7] = vec3(0, Y, Z);
for (size_t ix = 0; ix < nSteps; ix++) {
float x = ix * resolution;
float X = x + resolution;
gridCell.p[0].x = x;
gridCell.p[1].x = X;
gridCell.p[2].x = X;
gridCell.p[3].x = x;
gridCell.p[4].x = x;
gridCell.p[5].x = X;
gridCell.p[6].x = X;
gridCell.p[7].x = x;
gridCell.val[0] = zLayer[yOffset + ix];
gridCell.val[1] = zLayer[yOffset + ix + 1];
gridCell.val[2] = zLayer[YOffset + ix + 1];
gridCell.val[3] = zLayer[YOffset + ix];
gridCell.val[4] = ZLayer[yOffset + ix];
gridCell.val[5] = ZLayer[yOffset + ix + 1];
gridCell.val[6] = ZLayer[YOffset + ix + 1];
gridCell.val[7] = ZLayer[YOffset + ix];
TRIANGLE tris[6];
int nTris = Polygonise(gridCell, isolevel, tris);
nT += nTris;
for (int iTri = 0; iTri < nTris; iTri++) {
vec3 *ps = tris[iTri].p;
@ -177,11 +264,11 @@ void Polygonizer::polygonize(float resolution) {
|| all(epsilonEqual(ps[2], ps[1], 1e-8f)))
continue;
glm::uvec3 idc;
uvec3 idc;
for (size_t k = 0; k < 3; k++) {
glm::vec3 &p = tris[iTri].p[k];
std::map<glm::vec3, int>::iterator vit =
vertexLookup.find(p);
vec3 &p = tris[iTri].p[k];
std::map<vec3, int>::iterator vit = vertexLookup.find(
p);
if (vit != vertexLookup.end()) {
idc[k] = vit->second;
} else {
@ -197,3 +284,75 @@ void Polygonizer::polygonize(float resolution) {
}
}
//void Polygonizer::polygonize(float resolution) {
// vertexLookup.clear();
// vertices.clear();
// indices.clear();
//
// size_t nSteps = 1.f / resolution;
// size_t nSamples = nSteps + 1;
//
// // precalculate 2 layers
// std::vector<float> layers[2];
// layers[0].resize(nSamples*nSamples);
// layers[1].resize(nSamples*nSamples);
//
// calculateLayer(layers[0], resolution, nSamples, 0.0);
//
// size_t nT = 0;
// for (size_t ix = 0; ix < nSteps; ix++) {
// double x = (double(ix) + 0.5) * resolution;
// for (size_t iy = 0; iy < nSteps; iy++) {
// double y = (double(iy) + 0.5) * resolution;
// for (size_t iz = 0; iz < nSteps; iz++) {
// double z = (double(iz) + 0.5) * resolution;
//
// GRIDCELL gridCell;
// gridCell.p[0] = vec3(x, y, z);
// gridCell.p[1] = vec3(x + resolution, y, z);
// gridCell.p[2] = vec3(x + resolution, y + resolution, z);
// gridCell.p[3] = vec3(x, y + resolution, z);
// gridCell.p[4] = vec3(x, y, z + resolution);
// gridCell.p[5] = vec3(x + resolution, y, z + resolution);
// gridCell.p[6] = vec3(x + resolution, y + resolution,
// z + resolution);
// gridCell.p[7] = vec3(x, y + resolution, z + resolution);
//
// for (size_t iCell = 0; iCell < 8; iCell++) {
// gridCell.val[iCell] = density(gridCell.p[iCell]);
// }
//
// TRIANGLE tris[6];
// int nTris = Polygonise(gridCell, isolevel, tris);
// nT += nTris;
// for (int iTri = 0; iTri < nTris; iTri++) {
// vec3 *ps = tris[iTri].p;
//
// // skip degenerate vertices
// if (all(epsilonEqual(ps[0], ps[1], 1e-8f))
// || all(epsilonEqual(ps[0], ps[2], 1e-8f))
// || all(epsilonEqual(ps[2], ps[1], 1e-8f)))
// continue;
//
// uvec3 idc;
// for (size_t k = 0; k < 3; k++) {
// vec3 &p = tris[iTri].p[k];
// std::map<vec3, int>::iterator vit = vertexLookup.find(
// p);
// if (vit != vertexLookup.end()) {
// idc[k] = vit->second;
// } else {
// idc[k] = vertices.size();
// vertices.push_back(p);
// vertexLookup[p] = idc[k];
// }
// }
// indices.push_back(idc);
// }
// }
// }
// }
//
//}
#endif

View File

@ -3,9 +3,9 @@
#include <vector>
#include <map>
#include <glm/vec3.hpp>
#include "types.h"
#include "Density.h"
#include "ProgressMonitor.h"
struct CompareVec3 {
bool operator()(const glm::vec3 &lhs, const glm::vec3 &rhs) {
@ -36,20 +36,26 @@ struct CompareVec3 {
class Polygonizer {
Density &density;
float isolevel;
public:
std::vector<glm::vec3> vertices;
std::vector<glm::uvec3> indices;
std::map<glm::vec3, int, CompareVec3> vertexLookup;
std::vector<bool> isocell;
size_t isocellVersion;
float isocellIsolevel;
void polygonize(const glm::vec3 &lower, const glm::vec3 &upper,
float isolevel);
void calculateLayer(std::vector<float> &layer, float resolution, size_t nSamples, float z);
public:
vec3v_t vertices;
uvec3v_t indices;
std::map<glm::vec3, int, CompareVec3> vertexLookup;
Polygonizer(Density &density, float isolevel);
void setIsoLevel(float isolevel);
void updateIsocell();
void polygonize(float resolution);
void polygonize(const glm::vec3 lower, const glm::vec3 upper,
float isolevel);
void polygonize(float resolution, ProgressMonitor &progress);
};

77
src/ProgressMonitor.h Normal file
View File

@ -0,0 +1,77 @@
#pragma once
#include <string>
class ProgressMonitor {
public:
ProgressMonitor() :
finished(false), running(false), canceled(false), steps(0), currentStep(
0) {
}
bool begin(std::string task, size_t steps) {
if (canceled)
return false;
this->task = task;
this->steps = steps;
this->running = true;
finished = false;
currentStep = 0;
return true;
}
bool advance(size_t count = 1) {
currentStep += count;
return !canceled;
}
size_t getSteps() {
return steps;
}
size_t getCurrentStep() {
return currentStep;
}
float getProgress() {
return float(currentStep) / float(steps);
}
void finish() {
task = "Finished";
currentStep = 0;
steps = 0;
running = false;
finished = true;
canceled = false;
}
void cancel() {
canceled = true;
}
std::string &getTask() {
return task;
}
bool isFinished() {
return finished;
}
bool isRunning() {
return running;
}
bool isCanceled() {
return canceled;
}
protected:
bool finished;
bool running;
bool canceled;
std::string task;
size_t steps;
size_t currentStep;
};

105
src/Shader.cpp Normal file
View File

@ -0,0 +1,105 @@
#include "Shader.h"
#include <glad/glad.h>
#include <fstream>
#include <iostream>
#include <vector>
using namespace std;
GLuint loadProgram(const string &name) {
// Create the shaders
GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
// Read the Vertex Shader code from the file
string VertexShaderCode;
string vertex_file_path = "shader/" + name + ".vertex.glsl";
ifstream VertexShaderStream(vertex_file_path, ios::in);
if (VertexShaderStream.is_open()) {
string Line = "";
while (getline(VertexShaderStream, Line))
VertexShaderCode += "\n" + Line;
VertexShaderStream.close();
} else {
cout << "Failed to open " << vertex_file_path << endl;
return 0;
}
// Read the Fragment Shader code from the file
string FragmentShaderCode;
string fragment_file_path = "shader/" + name + ".fragment.glsl";
ifstream FragmentShaderStream(fragment_file_path, ios::in);
if (FragmentShaderStream.is_open()) {
string Line = "";
while (getline(FragmentShaderStream, Line))
FragmentShaderCode += "\n" + Line;
FragmentShaderStream.close();
} else {
cout << "Failed to open " << vertex_file_path << endl;
return 0;
}
GLint Result = GL_FALSE;
int InfoLogLength;
// Compile Vertex Shader
cout << "Compiling vertex shader : " << name << endl;
char const * VertexSourcePointer = VertexShaderCode.c_str();
glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL);
glCompileShader(VertexShaderID);
// Check Vertex Shader
glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL,
&VertexShaderErrorMessage[0]);
printf("%s\n", &VertexShaderErrorMessage[0]);
}
// Compile Fragment Shader
cout << "Compiling fragment shader : " << name << endl;
char const * FragmentSourcePointer = FragmentShaderCode.c_str();
glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL);
glCompileShader(FragmentShaderID);
// Check Fragment Shader
glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL,
&FragmentShaderErrorMessage[0]);
printf("%s\n", &FragmentShaderErrorMessage[0]);
}
// Link the program
cout << "Linking program : " << name << endl;
GLuint ProgramID = glCreateProgram();
glAttachShader(ProgramID, VertexShaderID);
glAttachShader(ProgramID, FragmentShaderID);
glLinkProgram(ProgramID);
// Check the program
glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
vector<char> ProgramErrorMessage(InfoLogLength + 1);
glGetProgramInfoLog(ProgramID, InfoLogLength, NULL,
&ProgramErrorMessage[0]);
printf("%s\n", &ProgramErrorMessage[0]);
}
glDetachShader(ProgramID, VertexShaderID);
glDetachShader(ProgramID, FragmentShaderID);
glDeleteShader(VertexShaderID);
glDeleteShader(FragmentShaderID);
return ProgramID;
}

5
src/Shader.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <string>
unsigned int loadProgram(const std::string &name);

78
src/SkyBox.cpp Normal file
View File

@ -0,0 +1,78 @@
#include "SkyBox.h"
#include "Shader.h"
#include <glad/glad.h>
#include <stb_image.h>
using namespace std;
SkyBox::SkyBox() {
glGenTextures(1, &textureId);
}
SkyBox::~SkyBox() {
glDeleteTextures(1, &textureId);
}
bool SkyBox::Load(const std::string basename) {
glBindTexture(GL_TEXTURE_CUBE_MAP, textureId);
Load(GL_TEXTURE_CUBE_MAP_POSITIVE_X, basename + "_right1.png");
Load(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, basename + "_left2.png");
Load(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, basename + "_top3.png");
Load(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, basename + "_bottom4.png");
Load(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, basename + "_front5.png");
Load(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, basename + "_back6.png");
programId = loadProgram("skybox");
return true;
}
bool SkyBox::Load(GLuint target, const std::string filename) {
int x, y, comp;
unsigned char *data = stbi_load(filename.c_str(), &x, &y, &comp, 4);
glTexImage2D(target, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R,
GL_CLAMP_TO_EDGE);
stbi_image_free(data);
return true;
}
void SkyBox::Render() {
GLint OldCullFaceMode;
glGetIntegerv(GL_CULL_FACE_MODE, &OldCullFaceMode);
GLint OldDepthFuncMode;
glGetIntegerv(GL_DEPTH_FUNC, &OldDepthFuncMode);
glCullFace(GL_FRONT);
glDepthFunc(GL_LEQUAL);
/*
Pipeline p;
p.Scale(20.0f, 20.0f, 20.0f);
p.Rotate(0.0f, 0.0f, 0.0f);
p.WorldPos(m_pCamera->GetPos().x, m_pCamera->GetPos().y,
m_pCamera->GetPos().z);
p.SetCamera(m_pCamera->GetPos(), m_pCamera->GetTarget(),
m_pCamera->GetUp());
p.SetPerspectiveProj(m_persProjInfo);
m_pSkyboxTechnique->SetWVP(p.GetWVPTrans());
m_pCubemapTex->Bind(GL_TEXTURE0);
m_pMesh->Render();
*/
glCullFace(OldCullFaceMode);
glDepthFunc(OldDepthFuncMode);
}
void SkyBox::Bind(GLenum unit) {
glActiveTexture(unit);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureId);
}

24
src/SkyBox.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <glad/glad.h>
#include <string>
class SkyBox {
public:
SkyBox();
~SkyBox();
bool Load(const std::string basename);
bool Load(GLuint target, const std::string filename);
void Bind(GLenum TextureUnit);
void Render();
private:
std::string fileNames[6];
GLuint textureId, programId;
};

View File

@ -9,8 +9,8 @@
TextureMapper::TextureMapper(Density &density, size_t textureSize) :
density(density), textureSize(textureSize), albedo(
textureSize * textureSize), normal(textureSize * textureSize), roughness(
textureSize * textureSize), darkestColor(0.3, 0.25, 0.2), brightestColor(
0.9, 0.85, 0.8) {
textureSize * textureSize), darkestColor(0.3, 0.25, 0.2, 1.0), brightestColor(
0.9, 0.85, 0.8, 1.0) {
}
void TextureMapper::setTextureSize(size_t size) {
@ -35,9 +35,19 @@ void TextureMapper::map(const vec3v_t &inVertices, const vec3v_t &inNormals,
texcoords.clear();
texcoords.reserve(inIndices.size() * 3);
// 2 px margin
size_t marginPixels = 2;
float margin = marginPixels * texf;
std::fill(albedo.begin(), albedo.end(), 255.f * brightestColor);
std::fill(normal.begin(), normal.end(), ucvec4_t(255, 255, 255, 255));
std::fill(roughness.begin(), roughness.end(), 255);
int rects = ceil(sqrt(inIndices.size())), rx = 0, ry = 0;
float rectSize = floor(float(textureSize) / rects) / textureSize;
for (size_t i = 0; i != inIndices.size(); i++) {
float rectSizePixel = floor(((float)textureSize - (rects + 1) * marginPixels) / rects);
float rectSize = rectSizePixel / textureSize;
printf("Rects: %d, Size: %f", rects, rectSize);
for (size_t i = 0; i < inIndices.size(); i++) {
glm::vec3 p[3], n[3];
glm::uvec3 idx = inIndices[i];
indices.push_back(
@ -62,17 +72,17 @@ void TextureMapper::map(const vec3v_t &inVertices, const vec3v_t &inNormals,
t[2] -= lower;
glm::vec3 extent = upper - lower;
float s = std::max(std::max(extent.x, extent.y), extent.z);
t[0] *= 0.8 * rectSize / s;
t[1] *= 0.8 * rectSize / s;
t[2] *= 0.8 * rectSize / s;
glm::vec3 off(rx * rectSize, 0, ry * rectSize);
t[0] *= 0.9 * rectSize / s;
t[1] *= rectSize / s;
t[2] *= rectSize / s;
glm::vec3 off(margin + rx * (rectSize + margin), 0, margin + ry * (rectSize + margin));
t[0] += off;
t[1] += off;
t[2] += off;
texcoords.push_back(glm::vec2(t[0].x, t[0].z));
texcoords.push_back(glm::vec2(t[1].x, t[1].z));
texcoords.push_back(glm::vec2(t[2].x, t[2].z));
#if 0
//if (rx == 0 && ry == 0) {
t[0].y = 0;
t[1].y = 0;
@ -111,16 +121,22 @@ void TextureMapper::map(const vec3v_t &inVertices, const vec3v_t &inNormals,
glm::mat3 faceBase = glm::mat3(db, glm::cross(db, dc), dc);
glm::mat3 ifaceBase = glm::inverse(faceBase);
glm::vec3 tmin = max(
floor(
min(min(t[0], t[1]), t[2])
* glm::vec3((float) textureSize))
- glm::vec3(1.0f), glm::vec3(0.1));
glm::vec3 tmax = min(
ceil(
max(max(t[0], t[1]), t[2])
* glm::vec3((float) textureSize))
+ glm::vec3(1.0f), glm::vec3(textureSize-1));
glm::vec3 tmin = min(min(t[0], t[1]), t[2]);
tmin = tmin * glm::vec3((float) textureSize);
tmin = floor(tmin) - glm::vec3(2.0f);
//tmin = tmin - glm::vec3(1.0f);
tmin = max(tmin, glm::vec3(0.1));
// glm::vec3 tmax = min(
// ceil(
// max(max(t[0], t[1]), t[2])
// * glm::vec3((float) textureSize))
// + glm::vec3(1.0f), glm::vec3(textureSize - 1));
glm::vec3 tmax = max(max(t[0], t[1]), t[2]);
tmax = tmax * glm::vec3((float) textureSize);
tmax = ceil(tmax) + glm::vec3(2.0f);
tmax = min(tmax, glm::vec3(textureSize));
// TODO: borders!
for (int ix = tmin.x; ix < tmax.x; ix++) {
@ -166,9 +182,9 @@ void TextureMapper::map(const vec3v_t &inVertices, const vec3v_t &inNormals,
// diff[ix + iy * ntex][2] = 0; //(0.5 + sp.z) * 255;
// float rd = 1.f; //0.7 + 0.3 * length(r) * rects;
// albedo[ix + iy * textureSize][0] = rd * (0.5 + sp.x) * 255;
// albedo[ix + iy * textureSize][1] = rd * (0.5 + sp.y) * 255;
// albedo[ix + iy * textureSize][2] = rd * (0.5 + sp.z) * 255;
// albedo[ix + (textureSize - iy) * textureSize][0] = rd * (sp.x) * 255;
// albedo[ix + (textureSize - iy) * textureSize][1] = rd * (sp.y) * 255;
// albedo[ix + (textureSize - iy) * textureSize][2] = rd * (sp.z) * 255;
// albedo[ix + iy * textureSize][0] = length(res) * rects * 255;
// albedo[ix + iy * textureSize][1] = length(res) * rects * 255;
@ -190,7 +206,7 @@ void TextureMapper::map(const vec3v_t &inVertices, const vec3v_t &inNormals,
rx = 0;
ry++;
}
#endif
}
//
// for (int ix = 0; ix < ntex; ix++) {

View File

@ -1,19 +1,12 @@
#pragma once
#include "Density.h"
#include <vector>
#include <glm/vec3.hpp>
#include "types.h"
class TextureMapper {
size_t textureSize;
public:
typedef std::vector< glm::tvec3<uint8_t> > texture3_t;
typedef std::vector<uint8_t> texture1_t;
typedef std::vector<glm::vec3> vec3v_t;
typedef std::vector<glm::vec2> vec2v_t;
typedef std::vector<glm::uvec3> uvec3v_t;
Density &density;
@ -27,7 +20,7 @@ public:
vec2v_t texcoords;
uvec3v_t indices;
glm::vec3 darkestColor, brightestColor;
glm::vec4 darkestColor, brightestColor;
TextureMapper(Density &density, size_t textureSize);

View File

@ -1,7 +1,7 @@
#include "Application.h"
int main(void) {
srand(time(0));
Application::instance().run();
}

15
src/types.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include "AlignedAllocator.h"
#include <glm/vec4.hpp>
#include <glm/vec3.hpp>
#include <vector>
typedef glm::tvec4<uint8_t> ucvec4_t;
typedef std::vector<ucvec4_t, AlignedAllocator<ucvec4_t> > texture3_t;
typedef std::vector<uint8_t, AlignedAllocator<uint8_t>> texture1_t;
typedef std::vector<glm::vec3, AlignedAllocator<glm::vec3> > vec3v_t;
typedef std::vector<glm::vec2, AlignedAllocator<glm::vec2> > vec2v_t;
typedef std::vector<glm::uvec3, AlignedAllocator<glm::uvec3> > uvec3v_t;
typedef std::vector<glm::uvec4, AlignedAllocator<glm::uvec4> > uvec4v_t;
typedef std::vector<uint32_t> uintv_t;