386 lines
11 KiB
C++
386 lines
11 KiB
C++
#include "Density.h"
|
|
#include "Polygoniser.h"
|
|
|
|
#include <glad/glad.h>
|
|
#include <GLFW/glfw3.h>
|
|
#include <glm/mat4x4.hpp>
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
#include <imgui.h>
|
|
#include <imgui_impl_glfw_gl3.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
static bool glck(const char* call) {
|
|
int err = glGetError();
|
|
if (err == 0) {
|
|
return true;
|
|
} else {
|
|
switch (err) {
|
|
case GL_INVALID_VALUE:
|
|
printf("GL_INVALID_VALUE: %s\n", call);
|
|
break;
|
|
case GL_INVALID_ENUM:
|
|
printf("GL_INVALID_ENUM: %s\n", call);
|
|
break;
|
|
case GL_INVALID_OPERATION:
|
|
printf("GL_INVALID_OPERATION: %s\n", call);
|
|
break;
|
|
default:
|
|
printf("UNKNOWN Error: %s\n", call);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#define GLCK(a) {a; assert(glck(#a));}
|
|
|
|
// ! https://learnopengl.com/#!PBR/Lighting
|
|
|
|
static const char* vertex_shader_text = "#version 130\n"
|
|
"uniform mat4 MVP;\n"
|
|
"in vec3 vPos;\n"
|
|
"in vec3 vNorm;\n"
|
|
"out vec3 normal;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_Position = MVP * vec4(vPos, 1.0);\n"
|
|
" normal = normalize(vNorm);\n"
|
|
"}\n";
|
|
|
|
static const char* fragment_shader_text = "#version 130\n"
|
|
"in vec3 normal;\n"
|
|
"out vec4 color;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" color = normal.y * vec4(1.0, 0.95, 0.9, 1.0);\n"
|
|
"}\n";
|
|
static void error_callback(int error, const char* description) {
|
|
fprintf(stderr, "Error: %s\n", description);
|
|
}
|
|
static void key_callback(GLFWwindow* window, int key, int scancode, int action,
|
|
int mods) {
|
|
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
|
|
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
|
}
|
|
|
|
void checkShader(GLuint vertexShader, const std::string &name) {
|
|
GLint status;
|
|
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);
|
|
|
|
if (status == GL_FALSE) {
|
|
|
|
std::cout << "Shader '" << name << "' compiled with an error(s):"
|
|
<< std::endl;
|
|
char buffer[512];
|
|
int l;
|
|
glGetShaderInfoLog(vertexShader, 512, &l, buffer);
|
|
buffer[l] = 0;
|
|
std::cout << buffer << std::endl;
|
|
}
|
|
}
|
|
|
|
void checkProgam(GLuint vertexShader, const std::string &name) {
|
|
GLint status;
|
|
glGetProgramiv(vertexShader, GL_LINK_STATUS, &status);
|
|
|
|
if (status == GL_FALSE) {
|
|
|
|
std::cout << "Program '" << name << "' failed with an error(s):"
|
|
<< std::endl;
|
|
char buffer[512];
|
|
int l;
|
|
glGetProgramInfoLog(vertexShader, 512, &l, buffer);
|
|
buffer[l] = 0;
|
|
std::cout << buffer << std::endl;
|
|
}
|
|
}
|
|
|
|
void calculateNormals(const std::vector<glm::vec3> &vtx,
|
|
std::vector<glm::uvec3> &tri, std::vector<glm::vec3> &normals) {
|
|
normals.clear();
|
|
normals.resize(vtx.size(), glm::vec3(0));
|
|
for (size_t i = 0; i < tri.size(); i++) {
|
|
int a = tri[i].x, b = tri[i].y, c = tri[i].z;
|
|
glm::vec3 faceNormal = normalize(
|
|
glm::cross(vtx[b] - vtx[a], vtx[c] - vtx[a]));
|
|
normals[a] += faceNormal;
|
|
normals[b] += faceNormal;
|
|
normals[c] += faceNormal;
|
|
}
|
|
for (size_t i = 0; i < normals.size(); i++)
|
|
normals[i] = glm::normalize(normals[i]);
|
|
|
|
}
|
|
|
|
void moveToMean(std::vector<glm::vec3> &vtx) {
|
|
glm::vec3 mean(0);
|
|
for (size_t i = 0; i < vtx.size(); i++) {
|
|
mean += vtx[i];
|
|
}
|
|
mean *= glm::vec3(1.f / vtx.size());
|
|
for (size_t i = 0; i < vtx.size(); i++) {
|
|
vtx[i] -= mean;
|
|
}
|
|
}
|
|
|
|
void smooth(std::vector<glm::vec3> &vtx, const std::vector<glm::uvec3> &tri) {
|
|
std::vector<glm::vec3> cogs(vtx.size(), glm::vec3(0.f));
|
|
std::vector<int> valence(vtx.size(), 0);
|
|
|
|
for (size_t iTri = 0; iTri < tri.size(); iTri++) {
|
|
const glm::uvec3 &idx = tri[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]];
|
|
}
|
|
}
|
|
/*
|
|
for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it) {
|
|
cog[0] = cog[1] = cog[2] = valence = 0.0;
|
|
|
|
for (vv_it = mesh.vv_iter(*v_it); vv_it.is_valid(); ++vv_it) {
|
|
cog += mesh.point(*vv_it);
|
|
++valence;
|
|
}
|
|
cogs.push_back(cog / valence);
|
|
}
|
|
for (v_it = mesh.vertices_begin(), cog_it = cogs.begin(); v_it != v_end;
|
|
++v_it, ++cog_it)
|
|
if (!mesh.is_boundary(*v_it))
|
|
mesh.set_point(*v_it, *cog_it);
|
|
|
|
*/
|
|
for (size_t i = 0; i < vtx.size(); i++) {
|
|
// vtx[i] = vtx[i] * glm::vec3(0.8)
|
|
// + cogs[i] * glm::vec3(0.2f / valence[i]);
|
|
vtx[i] = cogs[i] * glm::vec3(1.f / valence[i]);
|
|
}
|
|
}
|
|
|
|
void saveAttrib(std::ostream &out, const char *prefix,
|
|
std::vector<glm::vec3> &elements) {
|
|
for (size_t i = 0; i < elements.size(); i++) {
|
|
out << prefix << elements[i].x << " " << elements[i].y << " " << elements[i].z
|
|
<< "\n";
|
|
}
|
|
}
|
|
|
|
void saveAttrib(std::ostream &out, const char *prefix,
|
|
std::vector<glm::vec2> &elements) {
|
|
for (size_t i = 0; i < elements.size(); i++) {
|
|
out << prefix << elements[i].x << " " << elements[i].y << "\n";
|
|
}
|
|
}
|
|
|
|
void saveFaces(std::ostream &out, const std::vector<glm::uvec3> &tris, size_t attribs) {
|
|
for (size_t i = 0; i < tris.size(); i++) {
|
|
out << "f";
|
|
|
|
for (size_t j = 0; j < 3; j++) {
|
|
int v = tris[i][j] + 1;
|
|
out << " " << v;
|
|
if (attribs > 1)
|
|
out << "/" << v;
|
|
if (attribs > 2)
|
|
out << "/" << v;
|
|
out << " ";
|
|
}
|
|
|
|
out << "\n";
|
|
}
|
|
}
|
|
|
|
void calculateEdges(const std::vector<glm::vec3> &vtx,
|
|
std::vector<glm::uvec3> &tri, std::vector<glm::vec4> &edges) {
|
|
edges.clear();
|
|
}
|
|
|
|
int main(void) {
|
|
|
|
std::srand(123);
|
|
|
|
Density density;
|
|
density.addRandomImpacts(1000, 0.2, 0.01, 0.005, 0.2, 4096);
|
|
//density.saveCrossSection("density.png", 512);
|
|
|
|
Polygonizer polygonizer(density);
|
|
polygonizer.polygonize(0.2, 1. / 20.);
|
|
|
|
moveToMean(polygonizer.vertices);
|
|
{
|
|
std::ofstream out("stage1.obj");
|
|
saveAttrib(out, "v ", polygonizer.vertices);
|
|
saveFaces(out, polygonizer.triangles, 1);
|
|
}
|
|
smooth(polygonizer.vertices, polygonizer.triangles);
|
|
{
|
|
std::ofstream out("stage2.obj");
|
|
saveAttrib(out, "v ", polygonizer.vertices);
|
|
saveFaces(out, polygonizer.triangles, 1);
|
|
}
|
|
std::vector<glm::vec3> normals;
|
|
calculateNormals(polygonizer.vertices, polygonizer.triangles, normals);
|
|
{
|
|
std::ofstream out("stage3.obj");
|
|
saveAttrib(out, "v ", polygonizer.vertices);
|
|
saveAttrib(out, "vn ", normals);
|
|
saveFaces(out, polygonizer.triangles, 2);
|
|
}
|
|
|
|
std::vector<glm::uvec4> edges;
|
|
std::cout << "Vertices: " << polygonizer.vertices.size() << std::endl;
|
|
std::cout << "Triangles: " << polygonizer.triangles.size() << std::endl;
|
|
|
|
GLFWwindow* window;
|
|
GLuint vertex_array, vertex_buffer, index_buffer, normal_buffer,
|
|
vertex_shader, fragment_shader, program;
|
|
GLint mvp_location, vpos_location, vnorm_location;
|
|
|
|
glfwSetErrorCallback(error_callback);
|
|
|
|
if (!glfwInit())
|
|
exit(EXIT_FAILURE);
|
|
|
|
// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
|
//glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_COMPAT_PROFILE);
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
|
|
|
|
window = glfwCreateWindow(640, 480, "Simple example", NULL, NULL);
|
|
if (!window) {
|
|
glfwTerminate();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
glfwSetKeyCallback(window, key_callback);
|
|
|
|
glfwMakeContextCurrent(window);
|
|
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
|
|
glfwSwapInterval(1);
|
|
|
|
std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;
|
|
std::cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION)
|
|
<< std::endl;
|
|
std::cout << "Vendor: " << glGetString(GL_VENDOR) << std::endl;
|
|
std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl;
|
|
|
|
// NOTE: OpenGL error checks have been omitted for brevity
|
|
|
|
// glGenBuffers(1, &vertex_buffer);
|
|
// glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
|
|
// glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
|
|
|
GLCK(glGenVertexArrays(1, &vertex_array))
|
|
GLCK(glBindVertexArray(vertex_array))
|
|
|
|
GLCK(glGenBuffers(1, &vertex_buffer))
|
|
GLCK(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer))
|
|
GLCK(
|
|
glBufferData(GL_ARRAY_BUFFER, polygonizer.vertices.size() * sizeof(glm::vec3), polygonizer.vertices.data(), GL_STATIC_DRAW))
|
|
|
|
GLCK(glGenBuffers(1, &index_buffer))
|
|
GLCK(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer))
|
|
GLCK(
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, polygonizer.triangles.size() * sizeof(glm::uvec3), polygonizer.triangles.data(), GL_STATIC_DRAW))
|
|
|
|
GLCK(glGenBuffers(1, &normal_buffer))
|
|
GLCK(glBindBuffer(GL_ARRAY_BUFFER, normal_buffer))
|
|
GLCK(
|
|
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW))
|
|
|
|
GLCK(vertex_shader = glCreateShader(GL_VERTEX_SHADER))
|
|
GLCK(glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL))
|
|
GLCK(glCompileShader(vertex_shader))
|
|
checkShader(vertex_shader, "vertex");
|
|
|
|
GLCK(fragment_shader = glCreateShader(GL_FRAGMENT_SHADER))
|
|
GLCK(glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL))
|
|
GLCK(glCompileShader(fragment_shader))
|
|
checkShader(fragment_shader, "fragment");
|
|
|
|
GLCK(program = glCreateProgram())
|
|
GLCK(glAttachShader(program, vertex_shader))
|
|
GLCK(glAttachShader(program, fragment_shader))
|
|
GLCK(glLinkProgram(program))
|
|
checkProgam(program, "program");
|
|
|
|
GLCK(mvp_location = glGetUniformLocation(program, "MVP"))
|
|
std::cout << mvp_location << std::endl;
|
|
|
|
GLCK(vpos_location = glGetAttribLocation(program, "vPos"))
|
|
std::cout << vpos_location << std::endl;
|
|
|
|
GLCK(vnorm_location = glGetAttribLocation(program, "vNorm"))
|
|
std::cout << vnorm_location << std::endl;
|
|
|
|
GLCK(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer))
|
|
glEnableVertexAttribArray(vpos_location);
|
|
GLCK(
|
|
glVertexAttribPointer(vpos_location, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0))
|
|
|
|
if (vnorm_location >= 0) {
|
|
GLCK(glBindBuffer(GL_ARRAY_BUFFER, normal_buffer))
|
|
GLCK(glEnableVertexAttribArray(vnorm_location))
|
|
GLCK(
|
|
glVertexAttribPointer(vnorm_location, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0))
|
|
}
|
|
|
|
ImGui_ImplGlfwGL3_Init(window, true);
|
|
|
|
while (!glfwWindowShouldClose(window)) {
|
|
glfwPollEvents();
|
|
ImGui_ImplGlfwGL3_NewFrame();
|
|
{
|
|
static float f = 0.0f;
|
|
static float resolution = 0.1f;
|
|
ImGui::Text("Hello, world!");
|
|
if (ImGui::Button("Wireframe"))
|
|
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE);
|
|
if (ImGui::Button("Fill"))
|
|
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL);
|
|
ImGui::InputFloat("Resolution", &resolution);
|
|
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)",
|
|
1000.0f / ImGui::GetIO().Framerate,
|
|
ImGui::GetIO().Framerate);
|
|
}
|
|
int width, height;
|
|
glm::mat4 m(1.0f), p, mvp(2);
|
|
|
|
glfwGetFramebufferSize(window, &width, &height);
|
|
float ratio = width / (float) height;
|
|
|
|
glViewport(0, 0, width, height);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
m = glm::rotate(m, (float) glfwGetTime(), glm::vec3(0.f, 0.f, 1.f));
|
|
//m = glm::translate(m, glm::vec3(-1.f));
|
|
//glm::translate(mvp, glm::vec3((float) glfwGetTime()));
|
|
p = glm::ortho(-1.f, 1.f, -1.f, 1.f);
|
|
mvp = p * m;
|
|
|
|
GLCK(glUseProgram(program))
|
|
GLCK(
|
|
glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) &mvp))
|
|
|
|
// Draw the triangles !
|
|
GLCK(glBindVertexArray(vertex_array))
|
|
glDrawElements( GL_TRIANGLES, polygonizer.triangles.size() * 3,
|
|
GL_UNSIGNED_INT, (void*) 0);
|
|
//GLCK(glDrawArrays( GL_TRIANGLES, 0, polygonizer.triangles.size() * 3))
|
|
ImGui::Render();
|
|
glfwSwapBuffers(window);
|
|
|
|
}
|
|
|
|
glfwDestroyWindow(window);
|
|
|
|
ImGui_ImplGlfwGL3_Shutdown();
|
|
|
|
glfwTerminate();
|
|
}
|