A serious refactor. Moved the entire window management process to another thread. Made a plotting interface with DLL exports. Refactored camera and changed transformation approach based on Jordan's suggestions
This commit is contained in:
17
src/body.cpp
17
src/body.cpp
@@ -100,16 +100,13 @@ bool load_body(Body* out_body, const char* obj_filepath) {
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
*out_body = { .pose = glm::mat4(1),
|
||||
.scale = 1.0f,
|
||||
.ebo = ebo,
|
||||
.vao = vao,
|
||||
.vbo = vbo,
|
||||
.shader = 0,
|
||||
.verts = verts,
|
||||
.faces = faces,
|
||||
.color = glm::vec4(0.5, 0.5, 0.5, 1)
|
||||
};
|
||||
out_body->pose = glm::mat4(1);
|
||||
out_body->ebo = ebo;
|
||||
out_body->vao = vao;
|
||||
out_body->vbo = vbo;
|
||||
out_body->shader = 0;
|
||||
out_body->verts = verts;
|
||||
out_body->faces = faces;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
48
src/camera.cpp
Normal file
48
src/camera.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#include "camera.hpp"
|
||||
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/geometric.hpp>
|
||||
#include <glm/trigonometric.hpp>
|
||||
|
||||
const float zoom_speed_scale = 30.0f;
|
||||
|
||||
Viewport make_viewport(float win_w, float win_h, float fov_degrees = 45.0f) {
|
||||
return { .fov_degrees = fov_degrees, .width = win_w, .height = win_h };
|
||||
}
|
||||
|
||||
glm::mat4 camera_to_projection(Viewport &v) {
|
||||
return glm::infinitePerspective(glm::radians(v.fov_degrees), v.width / v.height, 0.1f);
|
||||
}
|
||||
|
||||
Camera make_camera(glm::vec3 focus = glm::vec3(0, 0, 0), float distance = 1.0f) {
|
||||
return {
|
||||
.focus = focus,
|
||||
.theta = 0,
|
||||
.phi = 0,
|
||||
.distance = distance
|
||||
};
|
||||
}
|
||||
void pan_camera(Camera& c, glm::vec2 dxdy) {
|
||||
dxdy.y *= -1;
|
||||
c.focus += camera_to_world(c) * glm::vec4(dxdy, 0, 0) * c.distance / 1000.0f;
|
||||
}
|
||||
|
||||
void rotate_camera(Camera& c, glm::vec2 dxdy) {
|
||||
c.theta += dxdy.x / 100.0f;
|
||||
c.phi += dxdy.y / 100.0f;
|
||||
}
|
||||
|
||||
void zoom_camera(Camera& c, float dz) {
|
||||
c.distance = std::max(0.0f, c.distance - (dz * zoom_speed_scale));
|
||||
}
|
||||
|
||||
glm::mat4 world_to_camera(Camera& c) {
|
||||
glm::mat4 world_to_focus = glm::translate(glm::mat4(1), c.focus);
|
||||
glm::mat4 rotation_theta = glm::rotate(glm::mat4(1), c.theta, {0, 1, 0});
|
||||
glm::mat4 rotation_phi = glm::rotate(glm::mat4(1), c.phi, {1, 0, 0});
|
||||
glm::mat4 rotated_focus_to_camera = glm::translate(glm::mat4(1), { 0, 0, -c.distance });
|
||||
return rotated_focus_to_camera * rotation_phi * rotation_theta * world_to_focus;
|
||||
}
|
||||
|
||||
glm::mat4 camera_to_world(Camera& c) { return glm::inverse(world_to_camera(c)); }
|
||||
@@ -14,11 +14,7 @@
|
||||
#define NUM_SPHERES_PER_AXE 25
|
||||
#define SPACE_PER_SPHERE 10.0f
|
||||
|
||||
glm::vec4 red_color = glm::vec4(1, 0, 0, 1);
|
||||
glm::vec4 green_color = glm::vec4(0, 1, 0, 1);
|
||||
glm::vec4 blue_color = glm::vec4(0, 0, 1, 1);
|
||||
|
||||
bool parse_poses(Array<Body>* bodies_out, const char* filepath) {
|
||||
bool parse_poses(Array<glm::mat2x3>* locs_out, const char* filepath) {
|
||||
FILE* fp;
|
||||
if (fopen_s(&fp, filepath, "rb")) {
|
||||
printf("Error parsing %s\n", filepath);
|
||||
@@ -28,8 +24,8 @@ bool parse_poses(Array<Body>* bodies_out, const char* filepath) {
|
||||
char delim = ',';
|
||||
char line[LINE_BUF_SIZE];
|
||||
// because clang refuses to cooperate with my append implementation and generate the function code...
|
||||
*bodies_out
|
||||
= { (Body*)malloc(sizeof(Body) * 3 * NUM_SPHERES_PER_AXE * 14), 3 * NUM_SPHERES_PER_AXE * 14 };
|
||||
*locs_out = { (glm::mat2x3*)malloc(sizeof(glm::mat2x3) * 3 * NUM_SPHERES_PER_AXE * 14),
|
||||
3 * NUM_SPHERES_PER_AXE * 14 };
|
||||
|
||||
// read in header
|
||||
fgets(line, LINE_BUF_SIZE, fp);
|
||||
@@ -37,7 +33,6 @@ bool parse_poses(Array<Body>* bodies_out, const char* filepath) {
|
||||
fgets(line, LINE_BUF_SIZE, fp);
|
||||
|
||||
for (int camera_i = 0; !feof(fp); camera_i++) {
|
||||
|
||||
Array<char*> words = split_str(line, delim);
|
||||
float x = atof(words[0]);
|
||||
float y = atof(words[1]);
|
||||
@@ -47,23 +42,18 @@ bool parse_poses(Array<Body>* bodies_out, const char* filepath) {
|
||||
float j = atof(words[5]);
|
||||
float k = atof(words[6]);
|
||||
|
||||
glm::mat4 pose = glm::translate(quat_to_mat4(glm::quat(w, i, j, k)), glm::vec3(x, y, z));
|
||||
|
||||
glm::mat4 pose = quat_to_mat4(glm::quat(w, i, j, k));
|
||||
pose[3] = glm::vec4(x, y, z, 1);
|
||||
// Generate axis spheres
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < NUM_SPHERES_PER_AXE; j++) {
|
||||
Body b;
|
||||
create_new_sphere(&b);
|
||||
for (int m = 0; m < 3; m++) {
|
||||
for (int n = 0; n < NUM_SPHERES_PER_AXE; n++) {
|
||||
glm::mat2x3 loc_color = glm::mat2x3(0.0);
|
||||
loc_color[0][m] = n * SPACE_PER_SPHERE;
|
||||
loc_color[0] = pose * glm::vec4(loc_color[0], 1);
|
||||
|
||||
// How far along the axis is this ball
|
||||
glm::vec3 trans = glm::vec3(0, 0, 0);
|
||||
trans[i] = (float)j * SPACE_PER_SPHERE;
|
||||
|
||||
// Now move the translated pose via the camera's pose
|
||||
b.pose = pose * glm::translate(b.pose, trans);
|
||||
b.color = glm::vec4(i == 0 ? 1 : 0, i == 1 ? 1 : 0, i == 2 ? 1 : 0, 1);
|
||||
b.scale = 3;
|
||||
bodies_out->data[camera_i*3*NUM_SPHERES_PER_AXE + i*NUM_SPHERES_PER_AXE + j] = b;
|
||||
loc_color[1] = glm::vec3(0);
|
||||
loc_color[1][m] = 1.0f;
|
||||
locs_out->data[camera_i*3*NUM_SPHERES_PER_AXE + m*NUM_SPHERES_PER_AXE + n] = loc_color;
|
||||
}
|
||||
}
|
||||
fgets(line, LINE_BUF_SIZE, fp);
|
||||
|
||||
288
src/live_plotter.cpp
Normal file
288
src/live_plotter.cpp
Normal file
@@ -0,0 +1,288 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <glm/ext/vector_float2.hpp>
|
||||
#include <glm/ext/vector_float4.hpp>
|
||||
#include <profileapi.h>
|
||||
#include <synchapi.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/ext/vector_float3.hpp>
|
||||
#include <glm/matrix.hpp>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
#include <winnt.h>
|
||||
|
||||
#include "util.hpp"
|
||||
#include "shaders.hpp"
|
||||
#include "body.hpp"
|
||||
#include "camera.hpp"
|
||||
#include "live_plotter.hpp"
|
||||
|
||||
#define LERP_MOVE_PERIOD_S 0.05
|
||||
#define STOP_WAIT_TIME_MS 500
|
||||
|
||||
struct Point {
|
||||
bool initialized;
|
||||
glm::vec3 startloc;
|
||||
glm::vec3 targetloc;
|
||||
Body b;
|
||||
double lifetime_s;
|
||||
double start_s;
|
||||
};
|
||||
|
||||
// Globals
|
||||
static GLFWwindow* win;
|
||||
static double prev_cursor_x, prev_cursor_y;
|
||||
static bool mouse_pressed, scroll_pressed, stop_flag, running;
|
||||
static Camera camera;
|
||||
static Viewport viewport;
|
||||
static uint shader;
|
||||
static CRITICAL_SECTION cs;
|
||||
static HANDLE win_thread_h;
|
||||
static DWORD win_thread_id;
|
||||
static LARGE_INTEGER fr;
|
||||
static pointid next_id = 0;
|
||||
static std::map<uint, Point*> id_to_point; // Use a pool allocator possibly later
|
||||
static std::map<Point*, uint> point_to_id;
|
||||
|
||||
// Constants
|
||||
const char* vertex_filepath = "src/shaders/vertex.glsl";
|
||||
const char* fragment_filepath = "src/shaders/fragment.glsl";
|
||||
|
||||
// Private foward decls
|
||||
void _resize_cb(GLFWwindow* win, int w, int h);
|
||||
void _cursor_pos_cb(GLFWwindow* win, double xpos, double ypos);
|
||||
void _mouse_button_cb(GLFWwindow* win, int button, int action, int mods);
|
||||
void _scroll_cb(GLFWwindow* win, double xoffset, double yoffset);
|
||||
DWORD WINAPI _win_thread(LPVOID);
|
||||
bool _glfw_setup();
|
||||
void _refresh_win();
|
||||
double _time();
|
||||
|
||||
DllExport bool __cdecl start(int win_w, int win_h) {
|
||||
if (!InitializeCriticalSectionAndSpinCount(&cs, 0x00000400))
|
||||
return false;
|
||||
|
||||
if (running) {
|
||||
printf("Already running! Call stop before calling stop again\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!QueryPerformanceFrequency(&fr)) {
|
||||
printf("Failed to get the performance counter frequency.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::vec2* winsize = (glm::vec2*)malloc(sizeof(glm::vec2));
|
||||
*winsize = glm::vec2(win_w, win_h);
|
||||
stop_flag = false;
|
||||
win_thread_h = CreateThread(NULL, 0, _win_thread, winsize, 0, &win_thread_id);
|
||||
|
||||
running = win_thread_h != NULL;
|
||||
if (!running)
|
||||
printf("Error while creating the live plotter window thread.\n");
|
||||
return running;
|
||||
}
|
||||
|
||||
DllExport bool __cdecl stop() {
|
||||
stop_flag = true;
|
||||
DWORD res = WaitForSingleObject(win_thread_h, STOP_WAIT_TIME_MS);
|
||||
bool success = res == WAIT_OBJECT_0;
|
||||
running = !success; // Consider the app still running if we didn't shut down properly...?
|
||||
|
||||
// TODO: Please wrap away win api synch stuff. thank you
|
||||
if (!running) DeleteCriticalSection(&cs);
|
||||
return success;
|
||||
}
|
||||
|
||||
DllExport pointid __cdecl create_point(float x, float y, float z) {
|
||||
EnterCriticalSection(&cs);
|
||||
|
||||
Point* p = (Point*)malloc(sizeof(Point));
|
||||
*p = {
|
||||
.initialized = false,
|
||||
.startloc = glm::vec3(x, y, z),
|
||||
.targetloc = glm::vec3(x, y, z),
|
||||
.lifetime_s = INFINITY,
|
||||
.start_s = _time()
|
||||
};
|
||||
p->b.scale = 1.0f;
|
||||
p->b.color = glm::vec4(randf() + 0.1, randf() + 0.1, randf() + 0.1, 1);
|
||||
|
||||
pointid id = next_id++;
|
||||
id_to_point[id] = p;
|
||||
point_to_id[p] = id;
|
||||
LeaveCriticalSection(&cs);
|
||||
return id;
|
||||
}
|
||||
|
||||
DllExport void __cdecl set_color(pointid id, float r, float g, float b) {
|
||||
EnterCriticalSection(&cs);
|
||||
Point* p = id_to_point[id];
|
||||
p->b.color = { r, g, b, p->b.color[3] };
|
||||
LeaveCriticalSection(&cs);
|
||||
}
|
||||
|
||||
DllExport void __cdecl set_scale(pointid id, float scale) {
|
||||
EnterCriticalSection(&cs);
|
||||
Point* p = id_to_point[id];
|
||||
p->b.scale = scale;
|
||||
LeaveCriticalSection(&cs);
|
||||
}
|
||||
|
||||
DllExport void __cdecl update_point(pointid id, float x, float y, float z) {
|
||||
EnterCriticalSection(&cs);
|
||||
Point* p = id_to_point[id];
|
||||
p->targetloc = { x, y, z };
|
||||
p->startloc = p->b.pose[3];
|
||||
LeaveCriticalSection(&cs);
|
||||
}
|
||||
|
||||
DllExport void __cdecl set_lifetime(pointid id, float new_lifetime_s) {
|
||||
EnterCriticalSection(&cs);
|
||||
Point* p = id_to_point[id];
|
||||
p->start_s = _time();
|
||||
p->lifetime_s = new_lifetime_s;
|
||||
LeaveCriticalSection(&cs);
|
||||
}
|
||||
|
||||
DllExport void __cdecl clear_point(pointid id) {
|
||||
EnterCriticalSection(&cs);
|
||||
Point* p = id_to_point[id];
|
||||
id_to_point.erase(id);
|
||||
point_to_id.erase(p);
|
||||
free(p);
|
||||
LeaveCriticalSection(&cs);
|
||||
}
|
||||
|
||||
void _resize_cb(GLFWwindow* win, int w, int h) {
|
||||
viewport.width = w;
|
||||
viewport.height = h;
|
||||
glViewport(0, 0, w, h);
|
||||
}
|
||||
|
||||
void _cursor_pos_cb(GLFWwindow* win, double xpos, double ypos) {
|
||||
glm::vec2 dxdy = glm::vec2((xpos - prev_cursor_x), (ypos - prev_cursor_y));
|
||||
prev_cursor_x = xpos;
|
||||
prev_cursor_y = ypos;
|
||||
if (mouse_pressed)
|
||||
rotate_camera(camera, dxdy);
|
||||
if (scroll_pressed)
|
||||
pan_camera(camera, dxdy);
|
||||
}
|
||||
|
||||
void _mouse_button_cb(GLFWwindow* win, int button, int action, int mods) {
|
||||
if (button == GLFW_MOUSE_BUTTON_RIGHT)
|
||||
mouse_pressed = action == GLFW_PRESS;
|
||||
if (button == GLFW_MOUSE_BUTTON_MIDDLE)
|
||||
scroll_pressed = action == GLFW_PRESS;
|
||||
// glfwGetCursorPos(window, &prev_cursor_x, &prev_cursor_y); Don't think this is necessary
|
||||
}
|
||||
|
||||
void _scroll_cb(GLFWwindow* win, double xoffset, double yoffset) { zoom_camera(camera, yoffset); }
|
||||
|
||||
DWORD _win_thread(LPVOID args) {
|
||||
glm::vec2* winsize = (glm::vec2*)args;
|
||||
camera = make_camera({ 0, 0, 0 }, 3000);
|
||||
camera.theta = glm::radians(90.0f);
|
||||
camera.phi = glm::radians(30.0f);
|
||||
viewport = make_viewport(winsize->x, winsize->y, 45.0f);
|
||||
if (!_glfw_setup()) {
|
||||
printf("Failed to initialize glfw window\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
|
||||
printf("Failed to initialize GLAD\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!load_shader(&shader, vertex_filepath, fragment_filepath)) {
|
||||
printf("Failed to compile shaders\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// This swapping bit is probably unnecessary now that I clear in the loop.
|
||||
// I was getting a flashing issue during the tutorial...
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT); // Write to back buffer
|
||||
glfwSwapBuffers(win); // front buffer is now back
|
||||
glClear(GL_COLOR_BUFFER_BIT); // Write to back buffer again (former front buf)
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
while (!(glfwWindowShouldClose(win) || stop_flag))
|
||||
_refresh_win();
|
||||
glfwTerminate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool _glfw_setup() {
|
||||
glfwInit();
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
win = glfwCreateWindow(viewport.width, viewport.height, "LivePlotter", NULL, NULL);
|
||||
if (win == NULL) {
|
||||
printf("Failed to create GLFW window\n");
|
||||
glfwTerminate();
|
||||
return false;
|
||||
}
|
||||
glfwMakeContextCurrent(win);
|
||||
glfwSetFramebufferSizeCallback(win, _resize_cb);
|
||||
glfwSetCursorPosCallback(win, _cursor_pos_cb);
|
||||
glfwSetMouseButtonCallback(win, _mouse_button_cb);
|
||||
glfwSetScrollCallback(win, _scroll_cb);
|
||||
|
||||
_cursor_pos_cb(win, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void _refresh_win() {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
set_uniform(shader, "camera_t", world_to_camera(camera));
|
||||
set_uniform(shader, "projection_t", camera_to_projection(viewport));
|
||||
|
||||
if (TryEnterCriticalSection(&cs)) {
|
||||
for (const auto& [id, p] : id_to_point) {
|
||||
// Initialize if not done so yet
|
||||
if (!p->initialized) {
|
||||
create_new_sphere(&p->b, p->b.scale);
|
||||
p->b.shader = shader;
|
||||
p->b.pose = glm::translate(glm::mat4(1), p->startloc);
|
||||
p->initialized = true;
|
||||
}
|
||||
|
||||
// Perform fade
|
||||
double elapsed_time_s = _time() - p->start_s;
|
||||
float t = elapsed_time_s / p->lifetime_s;
|
||||
p->b.color[3] = lerp(1.0, 0.0, t);
|
||||
|
||||
// Lerp position
|
||||
t = elapsed_time_s / LERP_MOVE_PERIOD_S;
|
||||
p->b.pose[3] = glm::vec4(lerp(p->startloc, p->targetloc, t), 1);
|
||||
draw_body(p->b);
|
||||
}
|
||||
LeaveCriticalSection(&cs);
|
||||
}
|
||||
glfwSwapBuffers(win);
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
double _time() {
|
||||
LARGE_INTEGER timeticks;
|
||||
if (!QueryPerformanceCounter(&timeticks)) {
|
||||
printf("Failed to query performance counter;\n");
|
||||
return false;
|
||||
}
|
||||
return (double)timeticks.QuadPart / (double)fr.QuadPart;
|
||||
}
|
||||
|
||||
283
src/main.cpp
283
src/main.cpp
@@ -1,249 +1,60 @@
|
||||
#include <cstring>
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glm/ext/matrix_clip_space.hpp>
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/ext/vector_float3.hpp>
|
||||
#include <glm/matrix.hpp>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "util.hpp"
|
||||
#include "shaders.hpp"
|
||||
#include "body.hpp"
|
||||
#include "camera_poses.hpp"
|
||||
#include "live_plotter.hpp"
|
||||
|
||||
static GLFWwindow* window;
|
||||
static float width, height;
|
||||
static glm::mat4 projection_t;
|
||||
//void* process_cin(void* args) {
|
||||
// std::string line;
|
||||
// while (true) {
|
||||
// std::getline(std::cin, line);
|
||||
// Array<char*> words = split_str(line.c_str());
|
||||
// if (!words.len == 4)
|
||||
// return NULL;
|
||||
// printf("Received: %s, %s, %s, %s\n", words[0], words[1], words[2], words[3]); // echo for debugging
|
||||
// float x = atof(words[1]);
|
||||
// float y = atof(words[2]);
|
||||
// float z = atof(words[3]);
|
||||
// glm::vec3 new_loc = glm::vec3(x, y, z);
|
||||
// bool found_match = false;
|
||||
// for (int i = 0; i < camera_bodies.size(); i++) {
|
||||
// if (strcmp(words[0], camera_bodies[i].name) == 0 && camera_bodies[i].b) {
|
||||
// Body& b = *camera_bodies[i].b;
|
||||
// glm::vec4& transl = b.pose[3];
|
||||
// transl = (0.8f * transl) + (0.2f * glm::vec4(new_loc, 1)); // lp filter
|
||||
// int color_i = i + 1;
|
||||
// b.color = glm::vec4(color_i & 0x4, color_i & 0x2, color_i & 0x1, 1); // reset alpha to 1
|
||||
// camera_bodies[i].hp = max_hp;
|
||||
// found_match = true;
|
||||
// } else if (camera_bodies[i].b) {
|
||||
// float& cur_hp = camera_bodies[i].hp;
|
||||
// if (cur_hp > 0)
|
||||
// cur_hp -= 1;
|
||||
// camera_bodies[i].b->color = glm::vec4(i & 0x4, i & 0x2, i & 0x1, cur_hp / max_hp);
|
||||
// }
|
||||
// }
|
||||
// if (!found_match) {
|
||||
// auto read = BarcodeRead { words[0], (Body*)NULL, max_hp };
|
||||
// camera_bodies.push_back(read);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
void framebuffer_size_callback(GLFWwindow* window, int w, int h) {
|
||||
width = w;
|
||||
height = h;
|
||||
glViewport(0, 0, width, height);
|
||||
projection_t = glm::infinitePerspective(glm::radians(45.0f), (float)width / (float)height, 0.1f);
|
||||
}
|
||||
|
||||
void process_input() {
|
||||
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
|
||||
glfwSetWindowShouldClose(window, true);
|
||||
}
|
||||
|
||||
static bool stop = false;
|
||||
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
const float max_hp
|
||||
= 10; // Number of scans (without a particular barcode) for which the sphere will still be visible
|
||||
|
||||
struct BarcodeRead {
|
||||
char* name;
|
||||
Body* b;
|
||||
float hp;
|
||||
};
|
||||
static std::vector<BarcodeRead> camera_bodies; // I would use my array here, but was getting a linking error
|
||||
|
||||
void* process_cin(void* args) {
|
||||
std::string line;
|
||||
while (true) {
|
||||
std::getline(std::cin, line);
|
||||
Array<char*> words = split_str(line.c_str());
|
||||
if (!words.len == 4) return NULL;
|
||||
printf("Received: %s, %s, %s, %s\n", words[0], words[1], words[2], words[3]); // echo for debugging
|
||||
float x = atof(words[1]);
|
||||
float y = atof(words[2]);
|
||||
float z = atof(words[3]);
|
||||
glm::vec3 new_loc = glm::vec3(x, y, z);
|
||||
bool found_match = false;
|
||||
pthread_mutex_lock(&lock);
|
||||
for (int i = 0; i < camera_bodies.size(); i++) {
|
||||
if (strcmp(words[0], camera_bodies[i].name) == 0 && camera_bodies[i].b) {
|
||||
Body& b = *camera_bodies[i].b;
|
||||
glm::vec4& transl = b.pose[3];
|
||||
transl = (0.8f * transl) + (0.2f * glm::vec4(new_loc, 1)); // lp filter
|
||||
int color_i = i + 1;
|
||||
b.color = glm::vec4(color_i & 0x4, color_i & 0x2, color_i & 0x1, 1); // reset alpha to 1
|
||||
camera_bodies[i].hp = max_hp;
|
||||
found_match = true;
|
||||
} else if (camera_bodies[i].b) {
|
||||
float& cur_hp = camera_bodies[i].hp;
|
||||
if (cur_hp > 0)
|
||||
cur_hp -= 1;
|
||||
camera_bodies[i].b->color = glm::vec4(i & 0x4, i & 0x2, i & 0x1, cur_hp / max_hp);
|
||||
}
|
||||
}
|
||||
if (!found_match) {
|
||||
auto read = BarcodeRead { words[0], (Body*)NULL, max_hp };
|
||||
camera_bodies.push_back(read);
|
||||
}
|
||||
pthread_mutex_unlock(&lock);
|
||||
}
|
||||
}
|
||||
|
||||
static bool mouse_pressed = false;
|
||||
static bool scroll_pressed = false;
|
||||
static double prev_cursor_x, prev_cursor_y;
|
||||
|
||||
static double theta = 0.0; // angle of camera trans vect wrt x-z plane
|
||||
static double phi = glm::radians(270.0); // angle of camera trans vect wrt x-axis
|
||||
|
||||
static glm::vec3 focal_point = glm::vec3(0, 0, 500);
|
||||
static glm::vec3 camera_loc = glm::vec3(0, 4000, 0);
|
||||
static glm::vec3 up = glm::vec3(0, 1, 0);
|
||||
static glm::mat4 world_to_camera = glm::lookAt(camera_loc, focal_point, up);
|
||||
|
||||
static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) {
|
||||
float dx = (xpos - prev_cursor_x);
|
||||
float dy = (ypos - prev_cursor_y);
|
||||
|
||||
glm::mat4 camera_to_world = glm::inverse(world_to_camera);
|
||||
// These could be acquired via some cross products. Don't know if that's more efficient.
|
||||
glm::vec4 strafe_x = camera_to_world[0];
|
||||
glm::vec4 strafe_y = camera_to_world[1];
|
||||
prev_cursor_x = xpos;
|
||||
prev_cursor_y = ypos;
|
||||
|
||||
double len = glm::length(camera_loc - focal_point);
|
||||
|
||||
if (mouse_pressed) {
|
||||
phi += glm::radians(dx * (360 / width)); // * glm::radians(360.0);
|
||||
theta += glm::radians(dy * (360 / height)); // * glm::radians(360.0);
|
||||
camera_loc.x = focal_point.x + (len * glm::cos(theta) * glm::cos(-phi));
|
||||
camera_loc.y = focal_point.y + (len * glm::sin(theta));
|
||||
camera_loc.z = focal_point.z + (-len * glm::cos(theta) * glm::sin(-phi));
|
||||
}
|
||||
|
||||
if (scroll_pressed) {
|
||||
glm::vec4 move_vec = glm::max((float)len, 20.0f) * (- strafe_x * (dx / 500) + strafe_y * (dy / 500));
|
||||
focal_point += move_vec;
|
||||
camera_loc += move_vec;
|
||||
}
|
||||
|
||||
world_to_camera = glm::lookAt(camera_loc, focal_point, up);
|
||||
}
|
||||
|
||||
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) {
|
||||
if (button == GLFW_MOUSE_BUTTON_RIGHT) {
|
||||
mouse_pressed = action == GLFW_PRESS;
|
||||
}
|
||||
|
||||
if (button == GLFW_MOUSE_BUTTON_MIDDLE) {
|
||||
scroll_pressed = action == GLFW_PRESS;
|
||||
}
|
||||
|
||||
glfwGetCursorPos(window, &prev_cursor_x, &prev_cursor_y);
|
||||
}
|
||||
|
||||
void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) {
|
||||
glm::vec3 k = camera_loc - focal_point;
|
||||
camera_loc -= k * (float)yoffset / 10.0f;
|
||||
world_to_camera = glm::lookAt(camera_loc, focal_point, up);
|
||||
}
|
||||
|
||||
bool glfw_setup() {
|
||||
glfwInit();
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
// glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
||||
window = glfwCreateWindow(800, 800, "LivePlotter", NULL, NULL);
|
||||
if (window == NULL) {
|
||||
printf("Failed to create GLFW window\n");
|
||||
glfwTerminate();
|
||||
return false;
|
||||
}
|
||||
glfwMakeContextCurrent(window);
|
||||
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
||||
glfwSetCursorPosCallback(window, cursor_position_callback);
|
||||
glfwSetMouseButtonCallback(window, mouse_button_callback);
|
||||
glfwSetScrollCallback(window, scroll_callback);
|
||||
|
||||
cursor_position_callback(window, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
if (!glfw_setup())
|
||||
return -1;
|
||||
|
||||
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
|
||||
printf("Failed to initialize GLAD\n");
|
||||
return -1;
|
||||
}
|
||||
glViewport(0, 0, 800, 800);
|
||||
width = 800;
|
||||
height = 800;
|
||||
|
||||
const char* vertex_filepath = "src/shaders/vertex.glsl";
|
||||
const char* fragment_filepath = "src/shaders/fragment.glsl";
|
||||
uint shader;
|
||||
if (!load_shader(&shader, vertex_filepath, fragment_filepath))
|
||||
return -1;
|
||||
|
||||
//glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT); // Write to back buffer
|
||||
|
||||
glfwSwapBuffers(window); // front buffer is now back
|
||||
glClear(GL_COLOR_BUFFER_BIT); // Write to back buffer again (former front buf)
|
||||
|
||||
// glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
// set_uniform(shader, "color", glm::vec4 { sin(time), sin(time + glm::radians(45.0f)), sin(time +
|
||||
// glm::radians(90.0f)), 1.0 } / 2.0f); time = glfwGetTime();
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
projection_t = glm::infinitePerspective(glm::radians(45.0f), (float)width / (float)height, 0.1f);
|
||||
pthread_t thread_id;
|
||||
pthread_create(&thread_id, NULL, process_cin, NULL);
|
||||
|
||||
Array<Body> camera_pose_axes = { NULL, 0 };
|
||||
Array<glm::mat2x3> camera_pose_axes = { NULL, 0 };
|
||||
if (!parse_poses(&camera_pose_axes, "poses.csv")) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
start(800, 800);
|
||||
|
||||
for (int i = 0; i < camera_pose_axes.len; i++) {
|
||||
camera_pose_axes[i].shader = shader;
|
||||
glm::vec3 p = camera_pose_axes[i][0];
|
||||
glm::vec3 color = camera_pose_axes[i][1];
|
||||
pointid id = create_point(p.x, p.y, p.z);
|
||||
set_color(id, color.x, color.y, color.z);
|
||||
set_scale(id, 10);
|
||||
}
|
||||
|
||||
/*Body b;
|
||||
create_new_sphere(&b);
|
||||
b.pose = glm::mat4(1);
|
||||
b.color = glm::vec4(1, 1, 1, 1);
|
||||
b.shader = shader;*/
|
||||
|
||||
while (!glfwWindowShouldClose(window)) {
|
||||
process_input();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
set_uniform(shader, "camera_t", world_to_camera);
|
||||
set_uniform(shader, "projection_t", projection_t);
|
||||
|
||||
//draw_body(b);
|
||||
|
||||
for (int i = 0; i < camera_pose_axes.len; i++) {
|
||||
draw_body(camera_pose_axes[i]);
|
||||
}
|
||||
|
||||
if (pthread_mutex_trylock(&lock) == 0) {
|
||||
for (int i = 0; i < camera_bodies.size(); i++) {
|
||||
if (!camera_bodies[i].b) {
|
||||
Body* b = (Body*)malloc(sizeof(Body));
|
||||
create_new_sphere(b);
|
||||
b->color = glm::vec4((i+1) & 0x4, (i+1) & 0x2, (i+1) & 0x1, max_hp);
|
||||
b->scale = 25;
|
||||
b->shader = shader;
|
||||
camera_bodies[i].b = b;
|
||||
}
|
||||
draw_body(*camera_bodies[i].b);
|
||||
}
|
||||
pthread_mutex_unlock(&lock);
|
||||
}
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
glfwPollEvents();
|
||||
}
|
||||
glfwTerminate();
|
||||
return 0;
|
||||
while (true)
|
||||
;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,6 @@ Array<char*> _split_str_inner(const char* s, char delim, bool just_check_ws) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// https://songho.ca/opengl/gl_quaternion.html
|
||||
glm::mat4 quat_to_mat4(glm::quat q) {
|
||||
glm::vec4 col0 = glm::vec4(
|
||||
@@ -109,3 +108,7 @@ glm::mat4 quat_to_mat4(glm::quat q) {
|
||||
|
||||
return glm::mat4(col0, col1, col2, col3);
|
||||
}
|
||||
|
||||
float randf() {
|
||||
return (float)rand() / (float)RAND_MAX;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user