commit d533139d1fd24e6d118a124780afcd0e40b5d181 Author: allem Date: Fri Jan 11 23:24:46 2019 -0500 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e608a77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,151 @@ +# Created by .ignore support plugin (hsz.mobi) +### C template +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf +### CMake template +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/dictionaries +.idea/**/shelf + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# CMake +cmake-build-debug/ +cmake-build-release/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests +### C++ template +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..74ae14a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,7 @@ +[submodule "vendor/glfw"] + path = vendor/glfw + url = https://github.com/glfw/glfw.git +[submodule "vendor/glad"] + path = vendor/glad + url = https://github.com/Dav1dde/glad.git + branch = c diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a9b3af8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.10) +project(main) + +set(CMAKE_CXX_STANDARD 17) + +add_library(glad vendor/glad/src/glad.c) +target_include_directories(glad PUBLIC vendor/glad/include) + +option(GLFW_BUILD_DOCS OFF) +option(GLFW_BUILD_EXAMPLES OFF) +option(GLFW_BUILD_TESTS OFF) +add_subdirectory(vendor/glfw) + +add_subdirectory(main) diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt new file mode 100644 index 0000000..ddda9a7 --- /dev/null +++ b/main/CMakeLists.txt @@ -0,0 +1,29 @@ +project(main) + +add_executable(${PROJECT_NAME} + src/main.cpp) + +target_link_libraries(${PROJECT_NAME} + glad + glfw) + +target_include_directories(${PROJECT_NAME} + PRIVATE include) + +set(SHADERS + shaders/main.frag + shaders/main.vert) +add_custom_target(shaders DEPENDS ${SHADERS}) + +add_custom_command( + TARGET shaders PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}/shaders/ + COMMENT "clearing shaders" +) +add_custom_command( + TARGET shaders POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/shaders/ ${CMAKE_CURRENT_BINARY_DIR}/shaders/ + COMMENT "copying shaders" +) + +add_dependencies(${PROJECT_NAME} shaders) \ No newline at end of file diff --git a/main/shaders/main.frag b/main/shaders/main.frag new file mode 100644 index 0000000..234034d --- /dev/null +++ b/main/shaders/main.frag @@ -0,0 +1,7 @@ +#version 440 + +out vec4 color; + +void main() { + color = vec4(1); +} \ No newline at end of file diff --git a/main/shaders/main.geom b/main/shaders/main.geom new file mode 100644 index 0000000..78bda9b --- /dev/null +++ b/main/shaders/main.geom @@ -0,0 +1,31 @@ +#version 440 + +#define CIRCLE_RES 256 +#define PI 3.14159 + +layout(points) in; +layout(line_strip, max_vertices=CIRCLE_RES) out; + +in float xi_[]; +in float eta_[]; + +layout(binding=1) uniform Matrices { + mat4 proj; +}; + +void main(){ + for(int k = 0; k <= CIRCLE_RES; k++) { + vec2 xi = vec2(xi_[0], 4 * PI * k / CIRCLE_RES); + float eta = eta_[0]; + + float x = cos((xi.y + xi.x) / 2) * sin(eta); + float y = sin((xi.y + xi.x) / 2) * sin(eta); + float z = cos((xi.y - xi.x) / 2) * cos(eta); + float w = sin((xi.y - xi.x) / 2) * cos(eta); + + vec4 pos = vec4(x / (1 - w), y / (1 - w), z / (1 - w), 1); + + gl_Position = proj * pos; + EmitVertex(); + } +} \ No newline at end of file diff --git a/main/shaders/main.vert b/main/shaders/main.vert new file mode 100644 index 0000000..ed3da93 --- /dev/null +++ b/main/shaders/main.vert @@ -0,0 +1,12 @@ +#version 440 + +layout(location=0) in float xi; +layout(location=1) in float eta; + +out float xi_; +out float eta_; + +void main(){ + xi_ = xi; + eta_ = eta; +} \ No newline at end of file diff --git a/main/src/main.cpp b/main/src/main.cpp new file mode 100644 index 0000000..6d2b899 --- /dev/null +++ b/main/src/main.cpp @@ -0,0 +1,262 @@ +#include +#include + +#include +#include +#include +#include + +#define PI 3.14159f + +namespace util { + template + void bufferData(GLenum target, std::vector data, GLenum usage) { + glBufferData(target, data.size() * sizeof(T), &data.front(), usage); + } + + template + void bufferData(GLenum target, T &data, GLenum usage) { + glBufferData(target, sizeof(T), &data, usage); + } + + std::string readFile(const std::string &path) { + std::ifstream file(path); + if (!file) return std::string(); + + file.ignore(std::numeric_limits::max()); + auto size = file.gcount(); + + if (size > 0x10000) return std::string(); + + file.clear(); + file.seekg(0, std::ios_base::beg); + + std::stringstream sstr; + sstr << file.rdbuf(); + file.close(); + + return sstr.str(); + } + + void shaderFiles(GLuint shader, std::vector &paths) { + std::vector strs; + std::vector c_strs; + + for (const auto &path : paths) strs.push_back(readFile(path)); + for (const auto &str:strs) c_strs.push_back(str.c_str()); + + glShaderSource(shader, (GLsizei) c_strs.size(), &c_strs.front(), nullptr); + } + + std::string shaderInfoLog(GLuint shader) { + GLint log_len; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len); + char log[log_len]; + glGetShaderInfoLog(shader, log_len, nullptr, log); + return std::string(log); + } + + std::string programInfoLog(GLuint program) { + GLint log_len; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len); + char log[log_len]; + glGetProgramInfoLog(program, log_len, nullptr, log); + return std::string(log); + } + + GLuint buildShader(GLenum kind, const std::string &name, std::vector paths) { + GLuint shader = glCreateShader(kind); + shaderFiles(shader, paths); + + glCompileShader(shader); + + GLint comp; + glGetShaderiv(shader, GL_COMPILE_STATUS, &comp); + if (!comp) { + std::string log = shaderInfoLog(shader); + fprintf(stderr, "SHADER ERROR (%s):\n%s", name.c_str(), log.c_str()); + glDeleteShader(shader); + return 0; + } + + return shader; + } + + GLuint buildProgram(bool separable, const std::string &name, std::vector shaders) { + GLuint program = glCreateProgram(); + + if (separable) + glProgramParameteri(program, GL_PROGRAM_SEPARABLE, GL_TRUE); + + for (GLuint shader : shaders) + glAttachShader(program, shader); + + glLinkProgram(program); + + GLint link; + glGetProgramiv(program, GL_LINK_STATUS, &link); + if (!link) { + std::string log = programInfoLog(program); + fprintf(stderr, "PROGRAM ERROR (%s):\n%s", name.c_str(), log.c_str()); + glDeleteProgram(program); + return 0; + } + + return program; + } +} + +struct HopfCircle { + float xi; + float eta; +}; + +struct State { + GLuint vao{}; + GLuint vbo{}, ubo{}; + GLuint ubo_bp = 1; + + GLuint prog{}; + + std::vector circles{}; + + explicit State(GLFWwindow *window) { + const int N = 32; + for (int k = 0; k < N; ++k) { + circles.push_back({2 * PI * k / N, 0.025}); + circles.push_back({2 * PI * k / N, PI / 2 - 0.025}); + + circles.push_back({2 * PI * k / N, 0.3f}); + circles.push_back({2 * PI * k / N, 0.4f}); + circles.push_back({2 * PI * k / N, 0.5f}); + + circles.push_back({2 * PI * k / N, 1.1f}); + circles.push_back({2 * PI * k / N, 1.2f}); + circles.push_back({2 * PI * k / N, 1.3f}); + } + + printf("vendor: %s\nrenderer: %s\n", glGetString(GL_VENDOR), glGetString(GL_RENDERER)); + + glGenBuffers(1, &vbo); + glGenBuffers(1, &ubo); + glGenVertexArrays(1, &vao); + + glBindBuffer(GL_ARRAY_BUFFER, vbo); + util::bufferData(GL_ARRAY_BUFFER, circles, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glBindBufferBase(GL_UNIFORM_BUFFER, ubo_bp, ubo); + + GLuint vs = util::buildShader(GL_VERTEX_SHADER, "vs", {"shaders/main.vert"}); + GLuint gs = util::buildShader(GL_GEOMETRY_SHADER, "gs", {"shaders/main.geom"}); + GLuint fs = util::buildShader(GL_FRAGMENT_SHADER, "fs", {"shaders/main.frag"}); + prog = util::buildProgram(false, "prog", {vs, gs, fs}); + + glBindVertexArray(vao); + + glBindBuffer(GL_ARRAY_BUFFER, vbo); + auto xi = glGetAttribLocation(prog, "xi"); + if (xi >= 0) { + glEnableVertexAttribArray((unsigned) xi); + glVertexAttribPointer((unsigned) xi, 1, GL_FLOAT, GL_FALSE, + sizeof(HopfCircle), + (void *) offsetof(HopfCircle, xi)); + } + + auto eta = glGetAttribLocation(prog, "eta"); + if (eta >= 0) { + glEnableVertexAttribArray((unsigned) eta); + glVertexAttribPointer((unsigned) eta, 1, GL_FLOAT, GL_FALSE, + sizeof(HopfCircle), + (void *) offsetof(HopfCircle, eta)); + } + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glBindVertexArray(0); + } + + void update(GLFWwindow *window, float dt, int frame) { + int w, h; + glfwGetFramebufferSize(window, &w, &h); + auto ar = (float) w / h; + + glBindBuffer(GL_UNIFORM_BUFFER, ubo); + util::bufferData(GL_UNIFORM_BUFFER, { + 1.f / 4 / ar, 0, 0, 0, + 0, 0, 1.f / 10, 0, + 0, 1.f / 4, 0, 0, + 0, 0, 0, 1 + }, GL_STREAM_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + } + + void render(GLFWwindow *window, float dt, int frame) { + int w, h; + glfwGetFramebufferSize(window, &w, &h); + glViewport(0, 0, w, h); + + glClear(GL_COLOR_BUFFER_BIT); + + glUseProgram(prog); + glBindVertexArray(vao); + glPointSize(5); + glLineWidth(3); + glDrawArrays(GL_POINTS, 0, (unsigned) circles.size()); + glBindVertexArray(0); + glUseProgram(0); + + glFinish(); + glfwSwapBuffers(window); + } + + void deinit(GLFWwindow *window) { + } +}; + +void run() { + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + auto window = glfwCreateWindow(1280, 720, "Hopf Fibration", nullptr, nullptr); + if (!window) { + glfwTerminate(); + exit(EXIT_FAILURE); + } + + glfwMakeContextCurrent(window); + gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); + glfwSwapInterval(0); + + auto state = State(window); + + double time = glfwGetTime(); + int frame = 0; + while (!glfwWindowShouldClose(window)) { + double time_ = glfwGetTime(); + auto dt = (float) (time_ - time); + + state.update(window, dt, frame); + state.render(window, dt, frame); + + glfwPollEvents(); + + time = time_; + frame += 1; + } + + state.deinit(window); + + glfwDestroyWindow(window); +} + +int main() { + if (!glfwInit()) { + return EXIT_FAILURE; + } + + run(); + + glfwTerminate(); + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/vendor/glad b/vendor/glad new file mode 160000 index 0000000..5bf3eda --- /dev/null +++ b/vendor/glad @@ -0,0 +1 @@ +Subproject commit 5bf3eda6da606324999775b88a90ed572202be93 diff --git a/vendor/glfw b/vendor/glfw new file mode 160000 index 0000000..72c3908 --- /dev/null +++ b/vendor/glfw @@ -0,0 +1 @@ +Subproject commit 72c3908e1474d0cd72bed9fecb6ff3da022f7200