4 Commits

Author SHA1 Message Date
5bba0801f4 Add readme details. 2020-03-04 12:39:40 -05:00
b89b124693 Create README.md 2020-03-04 12:30:36 -05:00
a2f6416903 Merge remote-tracking branch 'origin/master' 2019-02-07 23:38:31 -05:00
2298a4fef9 realtime rotations 2019-02-07 23:38:05 -05:00
20 changed files with 569 additions and 443 deletions

4
.gitignore vendored
View File

@@ -147,4 +147,6 @@ fabric.properties
# Executables
*.exe
*.out
*.app
*.app
.idea/

3
.gitmodules vendored
View File

@@ -5,6 +5,3 @@
path = vendor/glad
url = https://github.com/Dav1dde/glad.git
branch = c
[submodule "vendor/glm"]
path = vendor/glm
url = https://github.com/g-truc/glm.git

4
.idea/encodings.xml generated
View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
</project>

View File

@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

12
.idea/misc.xml generated
View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<component name="CidrRootsConfiguration">
<sourceRoots>
<file path="$PROJECT_DIR$/main" />
</sourceRoots>
<libraryRoots>
<file path="$PROJECT_DIR$/vendor" />
</libraryRoots>
</component>
</project>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/hopf-fibration.iml" filepath="$PROJECT_DIR$/.idea/hopf-fibration.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.10)
project(hopf-fibration)
project(hopf)
set(CMAKE_CXX_STANDARD 17)
@@ -11,7 +11,4 @@ option(GLFW_BUILD_EXAMPLES OFF)
option(GLFW_BUILD_TESTS OFF)
add_subdirectory(vendor/glfw)
option(GLM_TEST_ENABLE OFF)
add_subdirectory(vendor/glm)
add_subdirectory(main)
add_subdirectory(main)

21
README.md Normal file
View File

@@ -0,0 +1,21 @@
# hopf-fibration
Generate images of the hopf fibration.
![zoomed](images/zoomed.png)
## Usage
Hold keys `Q`, `W`, `E`, `A`, `S`, `D` to select from the six planes of rotation, and use the scroll wheel to rotate the fibration through the selected plane. The resulting Hopf links are stereographically projected into 3D space, and the resulting circles are rendered orthographically on screen.
Hold left-control `LCTL` and scroll to zoom in on the fibration. This affects only the orthographic rendering, not the fibration itself.
![default](images/default.png)
![rotated](images/rotated.png)
---
## More information
[Wikipedia: Hopf Fibration](https://en.wikipedia.org/wiki/Hopf_fibration)

BIN
images/default.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
images/rotated.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
images/zoomed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

View File

@@ -1,18 +1,17 @@
project(main)
add_executable(${PROJECT_NAME}
src/main.cpp include/util.h)
src/main.cpp)
target_link_libraries(${PROJECT_NAME}
glad
glm
glfw)
target_include_directories(${PROJECT_NAME}
PRIVATE
include)
PRIVATE include)
set(SHADERS
shaders/main.frag
shaders/main.vert)
add_custom_target(shaders DEPENDS ${SHADERS})

165
main/include/glga.hpp Normal file
View File

@@ -0,0 +1,165 @@
#include <math.h>
namespace ga {
struct Vec;
struct Bivec;
struct Mat;
struct Vec {
float x, y, z, w;
Vec(float x, float y, float z, float w) :
x(x), y(y), z(z), w(w) {}
};
struct Bivec {
float xy, yz, zw, wx, xz, yw;
Bivec(float xy, float yz, float zw, float wx, float xz, float yw) :
xy(xy), yz(yz), zw(zw), wx(wx), xz(xz), yw(yw) {}
};
struct Mat {
Vec x, y, z, w;
Mat(Vec x, Vec y, Vec z, Vec w) : x(x), y(y), z(z), w(w) {}
};
namespace unit {
Vec x() { return Vec(1, 0, 0, 0); };
Vec y() { return Vec(0, 1, 0, 0); };
Vec z() { return Vec(0, 0, 1, 0); };
Vec w() { return Vec(0, 0, 0, 1); };
Bivec xy() { return Bivec(1, 0, 0, 0, 0, 0); }
Bivec yz() { return Bivec(0, 1, 0, 0, 0, 0); }
Bivec zw() { return Bivec(0, 0, 1, 0, 0, 0); }
Bivec wx() { return Bivec(0, 0, 0, 1, 0, 0); }
Bivec xz() { return Bivec(0, 0, 0, 0, 1, 0); }
Bivec yw() { return Bivec(0, 0, 0, 0, 0, 1); }
Mat identity() { return Mat(x(), y(), z(), w()); }
}
float length2(Vec v) {
return v.x * v.x + v.y * v.y + v.z * v.z + v.w * v.w;
}
float length2(Bivec v) {
return v.xy * v.xy + v.yz * v.yz + v.zw * v.zw
+ v.wx * v.wx + v.xz * v.xz + v.yw * v.yw;
}
float length(Vec v) { return sqrt(length2(v)); }
float length(Bivec v) { return sqrt(length2(v)); }
Vec add(Vec u, Vec v) {
return Vec(u.x + v.x,
u.y + v.y,
u.z + v.z,
u.w + v.w);
}
Bivec add(Bivec u, Bivec v) {
Bivec(u.xy + v.xy,
u.yz + v.yz,
u.zw + v.zw,
u.wx + v.wx,
u.xz + v.xz,
u.yw + v.yw);
}
Vec mul(float c, Vec v) {
return Vec(c * v.x,
c * v.y,
c * v.z,
c * v.w);
}
Bivec mul(float c, Bivec v) {
Bivec(c * v.xy,
c * v.yz,
c * v.zw,
c * v.wx,
c * v.xz,
c * v.yw);
}
Vec mul(Mat m, Vec v) {
return add(add(mul(v.x, m.x), mul(v.y, m.y)), add(mul(v.z, m.z), mul(v.w, m.w)));
}
Mat mul(Mat m, Mat n) {
return Mat(
mul(m, n.x),
mul(m, n.y),
mul(m, n.z),
mul(m, n.w)
);
}
Mat mul(float c, Mat m) {
return Mat(
mul(c, m.x),
mul(c, m.y),
mul(c, m.z),
mul(c, m.w)
);
}
Vec normalize(Vec v) {
return mul(1 / length(v), v);
}
Bivec normalize(Bivec v) {
return mul(1 / length(v), v);
}
Vec tform(float c, Vec v) {
}
Vec tform(Vec u, Vec v) {
}
Vec tform(Bivec u, Vec v) {
}
Mat matrix(float c) {
auto m = unit::identity();
m.x = tform(c, m.x);
m.y = tform(c, m.y);
m.z = tform(c, m.z);
m.w = tform(c, m.w);
return m;
}
Mat matrix(Vec v) {
auto m = unit::identity();
m.x = tform(v, m.x);
m.y = tform(v, m.y);
m.z = tform(v, m.z);
m.w = tform(v, m.w);
return m;
}
Mat matrix(Bivec v) {
auto m = unit::identity();
m.x = tform(v, m.x);
m.y = tform(v, m.y);
m.z = tform(v, m.z);
m.w = tform(v, m.w);
return m;
}
}

View File

@@ -1,113 +0,0 @@
//
// Created by allem on 2/7/2019.
//
#ifndef HOPF_FIBRATION_UTIL_H
#define HOPF_FIBRATION_UTIL_H
#include <glad/glad.h>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
namespace util {
template<typename T>
void bufferData(GLenum target, std::vector<T> data, GLenum usage) {
glBufferData(target, data.size() * sizeof(T), &data.front(), usage);
}
template<typename T>
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<std::streamsize>::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<std::string> &paths) {
std::vector<std::string> strs;
std::vector<const char *> 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<std::string> 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<GLuint> 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;
}
}
#endif //HOPF_FIBRATION_UTIL_H

View File

@@ -1,12 +1,20 @@
#version 440
layout(binding=1) uniform Unifs {
mat4 uProj;
vec4 uColor;
};
#define PI 3.14159
uniform float bright;
in vec4 pos;
in vec4 pos4;
in vec4 pos3;
out vec4 color;
void main() {
color = uColor;
float light = -pos3.y / 10 + .5;
vec3 col = vec3(bright);
//color = vec4(col * light, 1);
color = vec4(col, 1);
}

47
main/shaders/main.geom Normal file
View File

@@ -0,0 +1,47 @@
#version 440
#define CIRCLE_RES 128
#define PI 3.14159
layout(points) in;
layout(line_strip, max_vertices=CIRCLE_RES) out;
layout(binding=1) uniform Matrices {
mat4 proj;
mat4 model;
};
in float xi_[];
in float eta_[];
out vec4 pos;
out vec4 pos4;
out vec4 pos3;
void main(){
for(int k = 0; k <= CIRCLE_RES; k++) {
vec2 xi = vec2(xi_[0], 4 * PI * k / (CIRCLE_RES - 1));
float eta = eta_[0];
// todo parameterize the projected circle so there aren't jagged edges.
// should be smooth at <=32 segments, not just 128+
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);
pos = vec4(x, y, z, w);
pos4 = model * pos;
pos3 = vec4(pos4.xyz / (1 - pos4.w), 1);
gl_Position = proj * pos3;
if (length(gl_Position) > 4) {
EndPrimitive();
continue;
}
EmitVertex();
}
EndPrimitive();
}

View File

@@ -1,12 +1,12 @@
#version 440
layout(binding=1) uniform Unifs {
mat4 uProj;
vec4 uColor;
};
layout(location=0) in float xi;
layout(location=1) in float eta;
in vec4 iPos;
out float xi_;
out float eta_;
void main(){
gl_Position = uProj * vec4(iPos.xyz, 1);
xi_ = xi;
eta_ = eta;
}

View File

@@ -1,319 +1,356 @@
//
// Created by allem on 2/7/2019.
//
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#define GLM_FORCE_SWIZZLE
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include <glm/gtx/string_cast.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <cstdlib>
#include <math.h>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <cmath>
#include "util.h"
#include "glga.hpp"
#define RES_MAJOR 512
#define RES_MINOR 8
#define PI 3.14159f
namespace util {
template<typename T>
void bufferData(GLenum target, std::vector<T> data, GLenum usage) {
glBufferData(target, data.size() * sizeof(T), &data.front(), usage);
}
#define Z_RADIUS 10.f
template<typename T>
void bufferData(GLenum target, T &data, GLenum usage) {
glBufferData(target, sizeof(T), &data, usage);
}
#define PI (float) (M_PI)
std::string readFile(const std::string &path) {
std::ifstream file(path);
if (!file) return std::string();
struct Unifs {
glm::mat4 proj = glm::identity<glm::mat4>();
glm::vec4 color = glm::vec4(1);
file.ignore(std::numeric_limits<std::streamsize>::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<std::string> &paths) {
std::vector<std::string> strs;
std::vector<const char *> 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<std::string> 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<GLuint> 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; // longitude
float eta; // latitude
HopfCircle(float xi, float eta) : xi(xi), eta(eta) {}
HopfCircle() : HopfCircle(0, 0) {}
};
struct State {
GLuint vao_wide{};
GLuint vbo_wide{};
GLuint ibo_wide{};
GLuint vao_thin{};
GLuint vbo_thin{};
GLuint ibo_thin{};
GLuint ubo{};
GLuint vao{};
GLuint vbo{}, ubo{};
GLuint unif_bright{};
GLuint ubo_bp = 1;
GLuint prog{};
const GLuint UNIF_BINDING_POINT = 1;
std::vector<glm::vec4> verts_wide{};
std::vector<unsigned> inds_wide{};
std::vector<HopfCircle> circles{};
ga::Mat rot = ga::unit::identity();
float view = 4.f;
std::vector<glm::vec4> verts_thin{};
std::vector<unsigned> inds_thin{};
Unifs unifs;
glm::vec4 hopf(float xi, float nu, float eta) {
return glm::vec4( // todo find parameterization given quaternion
cos((nu + xi) / 2) * sin(eta),
sin((nu + xi) / 2) * sin(eta),
cos((nu - xi) / 2) * cos(eta),
sin((nu - xi) / 2) * cos(eta)
);
}
glm::vec3 stereo(float xi, float nu, float eta) {
auto h = hopf(xi, nu, eta);
float xw = 0.8;
float yw = -0.1;
float zw = 2.5;
float xy = 0.0;
float yz = 0.5;
float zx = 0.0;
auto r = glm::mat4(
glm::vec4(cos(xw), 0, 0, sin(xw)),
glm::vec4(0, 1, 0, 0),
glm::vec4(0, 0, 1, 0),
glm::vec4(-sin(xw), 0, 0, cos(xw))
) * glm::mat4(
glm::vec4(1, 0, 0, 0),
glm::vec4(0, cos(yw), 0, sin(yw)),
glm::vec4(0, 0, 1, 0),
glm::vec4(0, -sin(yw), 0, cos(yw))
) * glm::mat4(
glm::vec4(1, 0, 0, 0),
glm::vec4(0, 1, 0, 0),
glm::vec4(0, 0, cos(zw), sin(zw)),
glm::vec4(0, 0, -sin(zw), cos(zw))
) * glm::mat4(
glm::vec4(cos(xy), sin(xy), 0, 0),
glm::vec4(-sin(xy), cos(xy), 0, 0),
glm::vec4(0, 0, 1, 0),
glm::vec4(0, 0, 0, 1)
) * glm::mat4(
glm::vec4(1, 0, 0, 0),
glm::vec4(0, cos(yz), sin(yz), 0),
glm::vec4(0, -sin(yz), cos(yz), 0),
glm::vec4(0, 0, 0, 1)
) * glm::mat4(
glm::vec4(cos(zx), 0, -sin(zx), 0),
glm::vec4(0, 1, 0, 0),
glm::vec4(sin(zx), 0, cos(zx), 0),
glm::vec4(0, 0, 0, 1)
);
auto rot = r;
h = rot * h;
auto s = h.xyz() / (1 - h.w);
s /= 2;
return s;
}
void
add_ring(std::vector<glm::vec4> &dest_verts, std::vector<unsigned> &dest_inds, float xi, float eta, float rad) {
std::vector<glm::vec3> circle;
std::vector<glm::vec3> torus;
std::vector<unsigned> ind;
for (unsigned i = 0; i < RES_MAJOR; ++i) {
auto nu = 4 * PI * i / RES_MAJOR;
auto v = stereo(xi, nu, eta);
circle.push_back(v);
}
auto center = glm::vec3(0);
for (auto v : circle) center += v;
center /= (float) RES_MAJOR;
auto A = stereo(xi, 0 * PI, eta);
auto B = stereo(xi, 1 * PI, eta);
auto normal = glm::normalize(cross(A - center, B - center));
for (unsigned i = 0; i < circle.size(); ++i) {
auto v = circle[i];
auto b1 = normal;
auto b2 = glm::normalize(v - center);
for (int j = 0; j < RES_MINOR; ++j) {
auto theta = 2 * PI * j / RES_MINOR;
auto p = v + (cos(theta) * b1 + sin(theta) * b2) * rad;
ind.push_back(i * RES_MINOR + j);
ind.push_back((i + 1) * RES_MINOR + j);
ind.push_back(i * RES_MINOR + (j + 1) % RES_MINOR);
ind.push_back((i + 1) * RES_MINOR + j);
ind.push_back((i + 1) * RES_MINOR + (j + 1) % RES_MINOR);
ind.push_back(i * RES_MINOR + (j + 1) % RES_MINOR);
torus.push_back(p);
}
}
auto offset = (unsigned) dest_verts.size();
for (auto v : torus)
dest_verts.emplace_back(v, 1);
for (auto i : ind)
dest_inds.push_back(offset + i % (RES_MAJOR * RES_MINOR));
}
void updateUnifs() {
glBindBuffer(GL_UNIFORM_BUFFER, ubo);
util::bufferData(GL_UNIFORM_BUFFER, unifs, GL_STREAM_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
float t = 0;
float dt = 0;
void regen() {
printf("generating\n");
circles.clear();
verts_wide.clear();
verts_thin.clear();
inds_wide.clear();
inds_thin.clear();
const int N = 32;
const int M = 4;
const float PAD = 0.0125;
const float XI_R = 28;
const float ETA_R = 5;
const float ETA_BUF = 0;
for (int i = 0; i < XI_R; ++i) {
float xi = 2 * PI * i / XI_R;
for (int j = 1; j <= ETA_R - 1; ++j) {
float eta = ETA_BUF + (PI / 2 - 2 * ETA_BUF) * j / ETA_R;
add_ring(verts_wide, inds_wide, xi, eta, .015);
add_ring(verts_thin, inds_thin, xi, eta, .004);
for (int x = 0; x <= N; ++x) {
for (int e = 1; e < M; ++e) {
float xi = 2 * PI * x / N;
float eta = (PI / 2 - 2 * PAD) * e / M + PAD;
circles.emplace_back(xi, eta);
}
}
add_ring(verts_wide, inds_wide, .001f, .0f, .015);
add_ring(verts_thin, inds_thin, .001f, .0f, .008);
add_ring(verts_wide, inds_wide, .001f, PI / 2 - .0f, .015);
add_ring(verts_thin, inds_thin, .001f, PI / 2 - .0f, .008);
glBindBuffer(GL_ARRAY_BUFFER, vbo_thin);
util::bufferData(GL_ARRAY_BUFFER, verts_thin, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
util::bufferData(GL_ARRAY_BUFFER, circles, GL_STREAM_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_thin);
util::bufferData(GL_ELEMENT_ARRAY_BUFFER, inds_thin, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_wide);
util::bufferData(GL_ARRAY_BUFFER, verts_wide, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_wide);
util::bufferData(GL_ELEMENT_ARRAY_BUFFER, inds_wide, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void init(GLFWwindow *window) {
GLuint vs = util::buildShader(GL_VERTEX_SHADER, "vs", {"shaders/main.vert"});
GLuint fs = util::buildShader(GL_FRAGMENT_SHADER, "fs", {"shaders/main.frag"});
prog = util::buildProgram(false, "prog", {vs, fs});
explicit State(GLFWwindow *window) {
printf("vendor: %s\nrenderer: %s\n", glGetString(GL_VENDOR), glGetString(GL_RENDERER));
glGenBuffers(1, &vbo_wide);
glGenBuffers(1, &ibo_wide);
glGenBuffers(1, &vbo_thin);
glGenBuffers(1, &ibo_thin);
float lw[2];
glGetFloatv(GL_LINE_WIDTH_RANGE, lw);
printf("line width range: %.2f to %.2f\n", lw[0], lw[1]);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ubo);
glGenVertexArrays(1, &vao);
regen();
GLint pos = glGetAttribLocation(prog, "iPos");
glBindBufferBase(GL_UNIFORM_BUFFER, ubo_bp, ubo);
glGenBuffers(1, &ubo);
glBindBufferBase(GL_UNIFORM_BUFFER, UNIF_BINDING_POINT, ubo);
updateUnifs();
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});
glGenVertexArrays(1, &vao_wide);
glBindVertexArray(vao_wide);
if (pos >= 0) {
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_wide);
glVertexAttribPointer((GLuint) pos, 4, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), nullptr);
glBindBuffer(GL_ARRAY_BUFFER, 0);
unif_bright = (GLuint) glGetUniformLocation(prog, "bright");
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));
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_wide);
glBindVertexArray(0);
glGenVertexArrays(1, &vao_thin);
glBindVertexArray(vao_thin);
if (pos >= 0) {
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo_thin);
glVertexAttribPointer((GLuint) pos, 4, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), nullptr);
glBindBuffer(GL_ARRAY_BUFFER, 0);
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_ELEMENT_ARRAY_BUFFER, ibo_thin);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void render(GLFWwindow *window, float dt, int frame) {
int w, h;
glfwGetFramebufferSize(window, &w, &h);
glViewport(0, 0, w, h);
glClearColor(1, 1, 1, 1);
unifs.color = glm::vec4(0, 0, 0, 1);
glClear(GL_DEPTH_BUFFER_BIT);
glBindVertexArray(vao_wide);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
updateUnifs();
glUseProgram(prog);
glDrawElements(GL_TRIANGLES, (GLsizei) inds_wide.size(), GL_UNSIGNED_INT, 0);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vao_thin);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
updateUnifs();
glUseProgram(prog);
glDrawElements(GL_TRIANGLES, (GLsizei) inds_thin.size(), GL_UNSIGNED_INT, 0);
glfwSwapBuffers(window);
}
void update(GLFWwindow *window, float dt, int frame) {
int w, h;
glfwGetFramebufferSize(window, &w, &h);
auto ar = (float) w / h;
float ar = (float) w / (float) h;
unifs.proj = glm::ortho(-ar, ar, -1.f, 1.f, -Z_RADIUS, Z_RADIUS);
t += dt;
float c = std::cos(t / 8);
float s = std::sin(t / 8);
float c_ = std::cos(3.f / 8);
float s_ = std::sin(3.f / 8);
glBindBuffer(GL_UNIFORM_BUFFER, ubo);
util::bufferData<ga::Mat>(GL_UNIFORM_BUFFER, {
ga::Mat(
ga::Vec(1.f / view / ar, 0, 0, 0),
ga::Vec(0, 0, 1.f / 10, 0),
ga::Vec(0, 1.f / view, 0, 0),
ga::Vec(0, 0, 0, 1.f)),
rot
}, 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 | GL_DEPTH_BUFFER_BIT);
glDepthFunc(GL_LEQUAL);
glUseProgram(prog);
glBindVertexArray(vao);
glEnable(GL_DEPTH_TEST);
glLineWidth(10);
glUniform1f(unif_bright, 0);
glDrawArrays(GL_POINTS, 0, (unsigned) circles.size());
glLineWidth(1);
glUniform1f(unif_bright, 1);
glDrawArrays(GL_POINTS, 0, (unsigned) circles.size());
glBindVertexArray(0);
glUseProgram(0);
glFinish();
glfwSwapBuffers(window);
}
void on_scroll(GLFWwindow *window, double xoffset, double yoffset) {
printf("scroll %.2f %.2f\n", xoffset, yoffset);
int xw = glfwGetKey(window, GLFW_KEY_Q);
int yw = glfwGetKey(window, GLFW_KEY_W);
int zw = glfwGetKey(window, GLFW_KEY_E);
int xy = glfwGetKey(window, GLFW_KEY_A);
int yz = glfwGetKey(window, GLFW_KEY_S);
int zx = glfwGetKey(window, GLFW_KEY_D);
int zoom = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL);
float t = (float) yoffset * PI / 48;
float c = std::cos(t);
float s = std::sin(t);
if (xw) {
rot = ga::mul(rot, ga::Mat(
ga::Vec(c, 0, 0, s),
ga::Vec(0, 1, 0, 0),
ga::Vec(0, 0, 1, 0),
ga::Vec(-s, 0, 0, c)
));
}
if (yw) {
rot = ga::mul(rot, ga::Mat(
ga::Vec(1, 0, 0, 0),
ga::Vec(0, c, 0, s),
ga::Vec(0, 0, 1, 0),
ga::Vec(0, -s, 0, c)
));
}
if (zw) {
rot = ga::mul(rot, ga::Mat(
ga::Vec(1, 0, 0, 0),
ga::Vec(0, 1, 0, 0),
ga::Vec(0, 0, c, s),
ga::Vec(0, 0, -s, c)
));
}
if (xy) {
rot = ga::mul(rot, ga::Mat(
ga::Vec(c, s, 0, 0),
ga::Vec(-s, c, 0, 0),
ga::Vec(0, 0, 1, 0),
ga::Vec(0, 0, 0, 1)
));
}
if (yz) {
rot = ga::mul(rot, ga::Mat(
ga::Vec(1, 0, 0, 0),
ga::Vec(0, c, s, 0),
ga::Vec(0, -s, c, 0),
ga::Vec(0, 0, 0, 1)
));
}
if (zx) {
rot = ga::mul(rot, ga::Mat(
ga::Vec(c, 0, -s, 0),
ga::Vec(0, 1, 0, 0),
ga::Vec(s, 0, c, 0),
ga::Vec(0, 0, 0, 1)
));
}
if (zoom) {
view *= 1 - t / 5;
}
std::ofstream matfile;
matfile.open("matrix.txt");
matfile << "vec((\n";
matfile << "vec((" << rot.x.x << ", " << rot.x.y << ", " << rot.x.z << ", " << rot.x.w << ")),\n";
matfile << "vec((" << rot.y.x << ", " << rot.y.y << ", " << rot.y.z << ", " << rot.y.w << ")),\n";
matfile << "vec((" << rot.z.x << ", " << rot.z.y << ", " << rot.z.z << ", " << rot.z.w << ")),\n";
matfile << "vec((" << rot.w.x << ", " << rot.w.y << ", " << rot.w.z << ", " << rot.w.w << ")),\n";
matfile << ")),";
matfile.close();
}
void deinit(GLFWwindow *window) {
}
};
void run(State *state, const std::string &title) {
void scroll_callback(GLFWwindow *window, double xoffset, double yoffset) {
auto *state = (State *) glfwGetWindowUserPointer(window);
state->on_scroll(window, xoffset, yoffset);
}
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(3840, 1249, title.c_str(), nullptr, nullptr);
auto window = glfwCreateWindow(1280, 720, "Hopf Fibration", nullptr, nullptr);
if (!window) {
glfwTerminate();
exit(EXIT_FAILURE);
@@ -323,8 +360,10 @@ void run(State *state, const std::string &title) {
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);
glfwSwapInterval(0);
glfwSetWindowUserPointer(window, state);
state->init(window);
auto state = State(window);
glfwSetWindowUserPointer(window, &state);
glfwSetScrollCallback(window, scroll_callback);
double time = glfwGetTime();
int frame = 0;
@@ -332,8 +371,8 @@ void run(State *state, const std::string &title) {
double time_ = glfwGetTime();
auto dt = (float) (time_ - time);
state->update(window, dt, frame);
state->render(window, dt, frame);
state.update(window, dt, frame);
state.render(window, dt, frame);
glfwPollEvents();
@@ -341,7 +380,7 @@ void run(State *state, const std::string &title) {
frame += 1;
}
state->deinit(window);
state.deinit(window);
glfwDestroyWindow(window);
}
@@ -351,11 +390,8 @@ int main() {
return EXIT_FAILURE;
}
auto *state = new State();
run(state, "Hopf Fibration");
delete state;
run();
glfwTerminate();
return EXIT_SUCCESS;
}
}

1
vendor/glm vendored

Submodule vendor/glm deleted from 7590260cf8