generated from AfonsoCMSousa/CPP-OpenGLTemplate
feat: 3D spaces and Camera
This commit is contained in:
+139
@@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
#include <glad/glad.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
// 3 axis lines: X=red, Y=green, Z=blue
|
||||
// Each line: 2 vertices, each vertex has pos(3) + color(3)
|
||||
static const float AXIS_VERTICES[] = {
|
||||
// X axis - red
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.2f,
|
||||
0.2f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.2f,
|
||||
0.2f,
|
||||
// Y axis - green
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.2f,
|
||||
1.0f,
|
||||
0.2f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.2f,
|
||||
1.0f,
|
||||
0.2f,
|
||||
// Z axis - blue
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
0.2f,
|
||||
0.4f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.2f,
|
||||
0.4f,
|
||||
1.0f,
|
||||
};
|
||||
|
||||
struct AxisRenderer {
|
||||
unsigned int VAO, VBO;
|
||||
unsigned int shader;
|
||||
};
|
||||
|
||||
static const char *AXIS_VERT_SRC = R"(
|
||||
#version 330 core
|
||||
layout(location = 0) in vec3 aPos;
|
||||
layout(location = 1) in vec3 aColor;
|
||||
out vec3 vColor;
|
||||
uniform mat4 uMVP;
|
||||
void main() {
|
||||
vColor = aColor;
|
||||
gl_Position = uMVP * vec4(aPos, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
static const char *AXIS_FRAG_SRC = R"(
|
||||
#version 330 core
|
||||
in vec3 vColor;
|
||||
out vec4 FragColor;
|
||||
void main() {
|
||||
FragColor = vec4(vColor, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
inline AxisRenderer axis_init() {
|
||||
AxisRenderer r;
|
||||
|
||||
// Compile inline shaders
|
||||
int success;
|
||||
char log[512];
|
||||
|
||||
unsigned int vert = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vert, 1, &AXIS_VERT_SRC, NULL);
|
||||
glCompileShader(vert);
|
||||
glGetShaderiv(vert, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
glGetShaderInfoLog(vert, 512, NULL, log);
|
||||
fprintf(stderr, "Axis vert: %s\n", log);
|
||||
}
|
||||
|
||||
unsigned int frag = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(frag, 1, &AXIS_FRAG_SRC, NULL);
|
||||
glCompileShader(frag);
|
||||
glGetShaderiv(frag, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
glGetShaderInfoLog(frag, 512, NULL, log);
|
||||
fprintf(stderr, "Axis frag: %s\n", log);
|
||||
}
|
||||
|
||||
r.shader = glCreateProgram();
|
||||
glAttachShader(r.shader, vert);
|
||||
glAttachShader(r.shader, frag);
|
||||
glLinkProgram(r.shader);
|
||||
glDeleteShader(vert);
|
||||
glDeleteShader(frag);
|
||||
|
||||
glGenVertexArrays(1, &r.VAO);
|
||||
glGenBuffers(1, &r.VBO);
|
||||
|
||||
glBindVertexArray(r.VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, r.VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(AXIS_VERTICES), AXIS_VERTICES, GL_STATIC_DRAW);
|
||||
|
||||
// pos
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
// color
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3 * sizeof(float)));
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
glBindVertexArray(0);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline void axis_draw(const AxisRenderer &r, const glm::mat4 &mvp) {
|
||||
glUseProgram(r.shader);
|
||||
glUniformMatrix4fv(glGetUniformLocation(r.shader, "uMVP"), 1, GL_FALSE, glm::value_ptr(mvp));
|
||||
glBindVertexArray(r.VAO);
|
||||
glLineWidth(2.0f);
|
||||
glDrawArrays(GL_LINES, 0, 6);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
inline void axis_destroy(AxisRenderer &r) {
|
||||
glDeleteVertexArrays(1, &r.VAO);
|
||||
glDeleteBuffers(1, &r.VBO);
|
||||
glDeleteProgram(r.shader);
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
#pragma once
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
struct Camera {
|
||||
glm::vec3 position;
|
||||
glm::vec3 front;
|
||||
glm::vec3 up;
|
||||
glm::vec3 right;
|
||||
glm::vec3 world_up;
|
||||
|
||||
float yaw; // horizontal angle, degrees
|
||||
float pitch; // vertical angle, degrees
|
||||
float fov;
|
||||
float speed;
|
||||
float sensitivity;
|
||||
|
||||
// Mouse state
|
||||
float last_x, last_y;
|
||||
bool first_mouse;
|
||||
bool cursor_captured;
|
||||
};
|
||||
|
||||
inline Camera camera_init(glm::vec3 position, float scr_width, float scr_height) {
|
||||
Camera c;
|
||||
c.position = position;
|
||||
c.world_up = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
c.yaw = -90.0f; // face -Z by default
|
||||
c.pitch = -20.0f;
|
||||
c.fov = 60.0f;
|
||||
c.speed = 5.0f;
|
||||
c.sensitivity = 0.1f;
|
||||
c.last_x = scr_width * 0.5f;
|
||||
c.last_y = scr_height * 0.5f;
|
||||
c.first_mouse = true;
|
||||
c.cursor_captured = false;
|
||||
|
||||
// Compute initial vectors from yaw/pitch
|
||||
glm::vec3 front;
|
||||
front.x = cos(glm::radians(c.yaw)) * cos(glm::radians(c.pitch));
|
||||
front.y = sin(glm::radians(c.pitch));
|
||||
front.z = sin(glm::radians(c.yaw)) * cos(glm::radians(c.pitch));
|
||||
c.front = glm::normalize(front);
|
||||
c.right = glm::normalize(glm::cross(c.front, c.world_up));
|
||||
c.up = glm::normalize(glm::cross(c.right, c.front));
|
||||
return c;
|
||||
}
|
||||
|
||||
inline glm::mat4 camera_view(const Camera &c) {
|
||||
return glm::lookAt(c.position, c.position + c.front, c.up);
|
||||
}
|
||||
|
||||
inline glm::mat4 camera_projection(const Camera &c, float aspect) {
|
||||
return glm::perspective(glm::radians(c.fov), aspect, 0.1f, 1000.0f);
|
||||
}
|
||||
|
||||
// Call every frame with GLFW window
|
||||
inline void camera_keyboard(Camera &c, GLFWwindow *window, float dt) {
|
||||
if (!c.cursor_captured)
|
||||
return;
|
||||
float vel = c.speed * dt;
|
||||
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
|
||||
c.position += c.front * vel;
|
||||
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
|
||||
c.position -= c.front * vel;
|
||||
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
|
||||
c.position -= c.right * vel;
|
||||
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
|
||||
c.position += c.right * vel;
|
||||
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
|
||||
c.position += c.world_up * vel;
|
||||
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
|
||||
c.position -= c.world_up * vel;
|
||||
}
|
||||
|
||||
// Call from your GLFW cursor position callback
|
||||
inline void camera_mouse(Camera &c, double xpos, double ypos) {
|
||||
if (!c.cursor_captured)
|
||||
return;
|
||||
|
||||
if (c.first_mouse) {
|
||||
c.last_x = (float)xpos;
|
||||
c.last_y = (float)ypos;
|
||||
c.first_mouse = false;
|
||||
}
|
||||
|
||||
float dx = ((float)xpos - c.last_x) * c.sensitivity;
|
||||
float dy = (c.last_y - (float)ypos) * c.sensitivity; // inverted Y
|
||||
c.last_x = (float)xpos;
|
||||
c.last_y = (float)ypos;
|
||||
|
||||
c.yaw += dx;
|
||||
c.pitch += dy;
|
||||
if (c.pitch > 89.0f)
|
||||
c.pitch = 89.0f;
|
||||
if (c.pitch < -89.0f)
|
||||
c.pitch = -89.0f;
|
||||
|
||||
glm::vec3 front;
|
||||
front.x = cos(glm::radians(c.yaw)) * cos(glm::radians(c.pitch));
|
||||
front.y = sin(glm::radians(c.pitch));
|
||||
front.z = sin(glm::radians(c.yaw)) * cos(glm::radians(c.pitch));
|
||||
c.front = glm::normalize(front);
|
||||
c.right = glm::normalize(glm::cross(c.front, c.world_up));
|
||||
c.up = glm::normalize(glm::cross(c.right, c.front));
|
||||
}
|
||||
|
||||
// Call from scroll callback
|
||||
inline void camera_scroll(Camera &c, double yoffset) {
|
||||
c.fov -= (float)yoffset;
|
||||
if (c.fov < 10.0f)
|
||||
c.fov = 10.0f;
|
||||
if (c.fov > 90.0f)
|
||||
c.fov = 90.0f;
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
#include <glad/glad.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <vector>
|
||||
|
||||
// XZ floor grid, centered at origin
|
||||
// SIZE = half-extent (25 means grid goes -25 to +25)
|
||||
// STEP = spacing between lines
|
||||
static constexpr int GRID_SIZE = 25;
|
||||
static constexpr float GRID_STEP = 1.0f;
|
||||
|
||||
struct GridRenderer {
|
||||
unsigned int VAO, VBO;
|
||||
unsigned int shader;
|
||||
int vertex_count;
|
||||
};
|
||||
|
||||
static const char *GRID_VERT_SRC = R"(
|
||||
#version 330 core
|
||||
layout(location = 0) in vec3 aPos;
|
||||
uniform mat4 uMVP;
|
||||
void main() {
|
||||
gl_Position = uMVP * vec4(aPos, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
static const char *GRID_FRAG_SRC = R"(
|
||||
#version 330 core
|
||||
out vec4 FragColor;
|
||||
void main() {
|
||||
FragColor = vec4(0.35, 0.35, 0.35, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
inline GridRenderer grid_init() {
|
||||
GridRenderer r;
|
||||
|
||||
// Build vertices on the CPU — two endpoints per line, X-parallel and Z-parallel
|
||||
std::vector<float> verts;
|
||||
verts.reserve(4 * 3 * (GRID_SIZE * 2 + 1) * 2); // rough upper bound
|
||||
|
||||
float lo = -GRID_SIZE * GRID_STEP;
|
||||
float hi = GRID_SIZE * GRID_STEP;
|
||||
|
||||
for (int i = -GRID_SIZE; i <= GRID_SIZE; i++) {
|
||||
float t = i * GRID_STEP;
|
||||
|
||||
// Line parallel to X axis (varies X, fixed Z=t)
|
||||
verts.insert(verts.end(), { lo, 0.0f, t,
|
||||
hi, 0.0f, t });
|
||||
|
||||
// Line parallel to Z axis (fixed X=t, varies Z)
|
||||
verts.insert(verts.end(), { t, 0.0f, lo,
|
||||
t, 0.0f, hi });
|
||||
}
|
||||
|
||||
r.vertex_count = (int)(verts.size() / 3);
|
||||
|
||||
// Compile shaders
|
||||
int success;
|
||||
char log[512];
|
||||
|
||||
unsigned int vert = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(vert, 1, &GRID_VERT_SRC, NULL);
|
||||
glCompileShader(vert);
|
||||
glGetShaderiv(vert, GL_COMPILE_STATUS, &success);
|
||||
if (!success) { glGetShaderInfoLog(vert, 512, NULL, log); fprintf(stderr, "Grid vert: %s\n", log); }
|
||||
|
||||
unsigned int frag = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(frag, 1, &GRID_FRAG_SRC, NULL);
|
||||
glCompileShader(frag);
|
||||
glGetShaderiv(frag, GL_COMPILE_STATUS, &success);
|
||||
if (!success) { glGetShaderInfoLog(frag, 512, NULL, log); fprintf(stderr, "Grid frag: %s\n", log); }
|
||||
|
||||
r.shader = glCreateProgram();
|
||||
glAttachShader(r.shader, vert);
|
||||
glAttachShader(r.shader, frag);
|
||||
glLinkProgram(r.shader);
|
||||
glGetProgramiv(r.shader, GL_LINK_STATUS, &success);
|
||||
if (!success) { glGetProgramInfoLog(r.shader, 512, NULL, log); fprintf(stderr, "Grid link: %s\n", log); }
|
||||
glDeleteShader(vert);
|
||||
glDeleteShader(frag);
|
||||
|
||||
// Upload geometry
|
||||
glGenVertexArrays(1, &r.VAO);
|
||||
glGenBuffers(1, &r.VBO);
|
||||
|
||||
glBindVertexArray(r.VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, r.VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, verts.size() * sizeof(float), verts.data(), GL_STATIC_DRAW);
|
||||
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
glBindVertexArray(0);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline void grid_draw(const GridRenderer &r, const glm::mat4 &mvp) {
|
||||
glUseProgram(r.shader);
|
||||
glUniformMatrix4fv(glGetUniformLocation(r.shader, "uMVP"), 1, GL_FALSE, glm::value_ptr(mvp));
|
||||
glBindVertexArray(r.VAO);
|
||||
glLineWidth(1.0f);
|
||||
glDrawArrays(GL_LINES, 0, r.vertex_count);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
inline void grid_destroy(GridRenderer &r) {
|
||||
glDeleteVertexArrays(1, &r.VAO);
|
||||
glDeleteBuffers(1, &r.VBO);
|
||||
glDeleteProgram(r.shader);
|
||||
}
|
||||
+2
-4
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define G_CONSTANT 9.807f
|
||||
#define G_CONSTANT 0.207f
|
||||
|
||||
typedef struct {
|
||||
float x, y, z;
|
||||
@@ -49,14 +49,12 @@ int particle_update(Particle *particles, unsigned long long size, float time) {
|
||||
continue;
|
||||
}
|
||||
|
||||
p.velocity.y += (G_CONSTANT * time);
|
||||
p.velocity.y -= (G_CONSTANT * time);
|
||||
|
||||
p.position.x += p.velocity.x * time;
|
||||
p.position.y += p.velocity.y * time;
|
||||
p.position.z += p.velocity.z * time;
|
||||
|
||||
vec_add(p.position, (p.velocity));
|
||||
|
||||
if (p.life > 0) p.life -= time;
|
||||
|
||||
particles[i] = p;
|
||||
|
||||
Reference in New Issue
Block a user