extract orbital camera into separate file
This commit is contained in:
@ -11,6 +11,7 @@ include_directories(include)
|
|||||||
|
|
||||||
add_executable(masssprings
|
add_executable(masssprings
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
|
src/camera.cpp
|
||||||
src/renderer.cpp
|
src/renderer.cpp
|
||||||
src/physics.cpp
|
src/physics.cpp
|
||||||
src/puzzle.cpp
|
src/puzzle.cpp
|
||||||
|
|||||||
41
include/camera.hpp
Normal file
41
include/camera.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#ifndef __CAMERA_HPP_
|
||||||
|
#define __CAMERA_HPP_
|
||||||
|
|
||||||
|
#include <raylib.h>
|
||||||
|
#include <raymath.h>
|
||||||
|
|
||||||
|
#include "config.hpp"
|
||||||
|
|
||||||
|
class OrbitCamera3D {
|
||||||
|
friend class Renderer;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Camera camera;
|
||||||
|
Vector3 target;
|
||||||
|
float distance;
|
||||||
|
float angle_x;
|
||||||
|
float angle_y;
|
||||||
|
Vector2 last_mouse;
|
||||||
|
bool dragging;
|
||||||
|
bool panning;
|
||||||
|
bool target_lock;
|
||||||
|
|
||||||
|
public:
|
||||||
|
OrbitCamera3D()
|
||||||
|
: camera({0}), target(Vector3Zero()), distance(CAMERA_DISTANCE),
|
||||||
|
angle_x(0.0), angle_y(0.0), last_mouse(Vector2Zero()), dragging(false),
|
||||||
|
panning(false), target_lock(true) {
|
||||||
|
camera.position = Vector3(0, 0, -1.0 * distance);
|
||||||
|
camera.target = target;
|
||||||
|
camera.up = Vector3(0, 1.0, 0);
|
||||||
|
camera.fovy = CAMERA_FOV;
|
||||||
|
camera.projection = CAMERA_PERSPECTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
~OrbitCamera3D() {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
auto Update(const Vector3 ¤t_target) -> void;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -86,7 +86,6 @@ public:
|
|||||||
|
|
||||||
class MassSpringSystem {
|
class MassSpringSystem {
|
||||||
private:
|
private:
|
||||||
// TODO: Use references
|
|
||||||
std::vector<Mass *> mass_vec;
|
std::vector<Mass *> mass_vec;
|
||||||
std::vector<int> indices;
|
std::vector<int> indices;
|
||||||
std::vector<int64_t> cell_ids;
|
std::vector<int64_t> cell_ids;
|
||||||
|
|||||||
@ -282,6 +282,8 @@ public:
|
|||||||
std::vector<std::pair<State, State>>>;
|
std::vector<std::pair<State, State>>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Provide hash functions so we can use State and <State, State> as hash-set
|
||||||
|
// keys for masses and springs.
|
||||||
template <> struct std::hash<State> {
|
template <> struct std::hash<State> {
|
||||||
std::size_t operator()(const State &s) const noexcept { return s.Hash(); }
|
std::size_t operator()(const State &s) const noexcept { return s.Hash(); }
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,57 +1,24 @@
|
|||||||
#ifndef __RENDERER_HPP_
|
#ifndef __RENDERER_HPP_
|
||||||
#define __RENDERER_HPP_
|
#define __RENDERER_HPP_
|
||||||
|
|
||||||
#include <immintrin.h>
|
|
||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
#include <raymath.h>
|
#include <raymath.h>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#include "camera.hpp"
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "puzzle.hpp"
|
|
||||||
#include "physics.hpp"
|
#include "physics.hpp"
|
||||||
|
#include "puzzle.hpp"
|
||||||
class OrbitCamera3D {
|
|
||||||
friend class Renderer;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Camera camera;
|
|
||||||
Vector3 target;
|
|
||||||
float distance;
|
|
||||||
float angle_x;
|
|
||||||
float angle_y;
|
|
||||||
Vector2 last_mouse;
|
|
||||||
bool dragging;
|
|
||||||
bool panning;
|
|
||||||
bool target_lock;
|
|
||||||
|
|
||||||
public:
|
|
||||||
OrbitCamera3D(Vector3 target, float distance)
|
|
||||||
: camera({0}), target(target), distance(distance), angle_x(0.0),
|
|
||||||
angle_y(0.0), last_mouse(Vector2Zero()), dragging(false),
|
|
||||||
panning(false), target_lock(true) {
|
|
||||||
camera.position = Vector3(0, 0, -1.0 * distance);
|
|
||||||
camera.target = target;
|
|
||||||
camera.up = Vector3(0, 1.0, 0);
|
|
||||||
camera.fovy = CAMERA_FOV;
|
|
||||||
camera.projection = CAMERA_PERSPECTIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
~OrbitCamera3D() {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
auto Update(const Mass ¤t_mass) -> void;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Renderer {
|
class Renderer {
|
||||||
private:
|
private:
|
||||||
OrbitCamera3D camera;
|
const OrbitCamera3D &camera;
|
||||||
RenderTexture render_target;
|
RenderTexture render_target;
|
||||||
RenderTexture klotski_target;
|
RenderTexture klotski_target;
|
||||||
RenderTexture menu_target;
|
RenderTexture menu_target;
|
||||||
|
|
||||||
Material vertex_mat;
|
|
||||||
|
|
||||||
// Instancing
|
// Instancing
|
||||||
|
Material vertex_mat;
|
||||||
int transforms_size;
|
int transforms_size;
|
||||||
Matrix *transforms;
|
Matrix *transforms;
|
||||||
Mesh cube_instance;
|
Mesh cube_instance;
|
||||||
@ -62,18 +29,14 @@ public:
|
|||||||
bool connect_solutions;
|
bool connect_solutions;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Renderer()
|
Renderer(const OrbitCamera3D &camera)
|
||||||
: camera(OrbitCamera3D(Vector3(0, 0, 0), CAMERA_DISTANCE)),
|
: camera(camera), mark_solutions(false), connect_solutions(false),
|
||||||
mark_solutions(false), connect_solutions(false), transforms_size(0),
|
transforms_size(0), transforms(nullptr) {
|
||||||
transforms(nullptr) {
|
|
||||||
render_target = LoadRenderTexture(GetScreenWidth() / 2.0,
|
render_target = LoadRenderTexture(GetScreenWidth() / 2.0,
|
||||||
GetScreenHeight() - MENU_HEIGHT);
|
GetScreenHeight() - MENU_HEIGHT);
|
||||||
klotski_target = LoadRenderTexture(GetScreenWidth() / 2.0,
|
klotski_target = LoadRenderTexture(GetScreenWidth() / 2.0,
|
||||||
GetScreenHeight() - MENU_HEIGHT);
|
GetScreenHeight() - MENU_HEIGHT);
|
||||||
menu_target = LoadRenderTexture(GetScreenWidth(), MENU_HEIGHT);
|
menu_target = LoadRenderTexture(GetScreenWidth(), MENU_HEIGHT);
|
||||||
|
|
||||||
vertex_mat = LoadMaterialDefault();
|
|
||||||
vertex_mat.maps[MATERIAL_MAP_DIFFUSE].color = VERTEX_COLOR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer(const Renderer ©) = delete;
|
Renderer(const Renderer ©) = delete;
|
||||||
@ -86,10 +49,9 @@ public:
|
|||||||
UnloadRenderTexture(klotski_target);
|
UnloadRenderTexture(klotski_target);
|
||||||
UnloadRenderTexture(menu_target);
|
UnloadRenderTexture(menu_target);
|
||||||
|
|
||||||
UnloadMaterial(vertex_mat);
|
|
||||||
|
|
||||||
// Instancing
|
// Instancing
|
||||||
if (transforms != nullptr) {
|
if (transforms != nullptr) {
|
||||||
|
UnloadMaterial(vertex_mat);
|
||||||
MemFree(transforms);
|
MemFree(transforms);
|
||||||
UnloadMesh(cube_instance);
|
UnloadMesh(cube_instance);
|
||||||
|
|
||||||
@ -106,9 +68,6 @@ private:
|
|||||||
-> void;
|
-> void;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
auto UpdateCamera(const MassSpringSystem &mass_springs,
|
|
||||||
const State ¤t_state) -> void;
|
|
||||||
|
|
||||||
auto UpdateTextureSizes() -> void;
|
auto UpdateTextureSizes() -> void;
|
||||||
|
|
||||||
auto DrawMassSprings(const MassSpringSystem &mass_springs,
|
auto DrawMassSprings(const MassSpringSystem &mass_springs,
|
||||||
|
|||||||
80
src/camera.cpp
Normal file
80
src/camera.cpp
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#include "camera.hpp"
|
||||||
|
|
||||||
|
auto OrbitCamera3D::Update(const Vector3 ¤t_target) -> void {
|
||||||
|
Vector2 mouse = GetMousePosition();
|
||||||
|
if (mouse.x >= GetScreenWidth() / 2.0 && mouse.y >= MENU_HEIGHT) {
|
||||||
|
if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
|
||||||
|
dragging = true;
|
||||||
|
last_mouse = mouse;
|
||||||
|
} else if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
|
||||||
|
panning = true;
|
||||||
|
target_lock = false;
|
||||||
|
last_mouse = mouse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsMouseButtonReleased(MOUSE_RIGHT_BUTTON)) {
|
||||||
|
dragging = false;
|
||||||
|
}
|
||||||
|
if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) {
|
||||||
|
panning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsKeyPressed(KEY_L)) {
|
||||||
|
target_lock = !target_lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dragging) {
|
||||||
|
Vector2 dx = Vector2Subtract(mouse, last_mouse);
|
||||||
|
last_mouse = mouse;
|
||||||
|
|
||||||
|
angle_x -= dx.x * ROT_SPEED / 200.0;
|
||||||
|
angle_y += dx.y * ROT_SPEED / 200.0;
|
||||||
|
|
||||||
|
angle_y = Clamp(angle_y, -1.5, 1.5); // Prevent flipping
|
||||||
|
}
|
||||||
|
|
||||||
|
if (panning) {
|
||||||
|
Vector2 dx = Vector2Subtract(mouse, last_mouse);
|
||||||
|
last_mouse = mouse;
|
||||||
|
|
||||||
|
// float speed = PAN_SPEED;
|
||||||
|
float speed;
|
||||||
|
if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
||||||
|
speed = distance * PAN_SPEED / 1000.0 * PAN_MULTIPLIER;
|
||||||
|
} else {
|
||||||
|
speed = distance * PAN_SPEED / 1000.0;
|
||||||
|
}
|
||||||
|
Vector3 forward =
|
||||||
|
Vector3Normalize(Vector3Subtract(camera.target, camera.position));
|
||||||
|
Vector3 right = Vector3Normalize(Vector3CrossProduct(forward, camera.up));
|
||||||
|
Vector3 up = Vector3Normalize(Vector3CrossProduct(right, forward));
|
||||||
|
|
||||||
|
Vector3 offset = Vector3Add(Vector3Scale(right, -dx.x * speed),
|
||||||
|
Vector3Scale(up, dx.y * speed));
|
||||||
|
|
||||||
|
target = Vector3Add(target, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_lock) {
|
||||||
|
target = current_target;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouse.x >= GetScreenWidth() / 2.0 && mouse.y >= MENU_HEIGHT) {
|
||||||
|
float wheel = GetMouseWheelMove();
|
||||||
|
if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
||||||
|
distance -= wheel * ZOOM_SPEED * ZOOM_MULTIPLIER;
|
||||||
|
} else {
|
||||||
|
distance -= wheel * ZOOM_SPEED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
distance = Clamp(distance, MIN_CAMERA_DISTANCE, MAX_CAMERA_DISTANCE);
|
||||||
|
|
||||||
|
// Spherical coordinates
|
||||||
|
float x = cos(angle_y) * sin(angle_x) * distance;
|
||||||
|
float y = sin(angle_y) * distance;
|
||||||
|
float z = cos(angle_y) * cos(angle_x) * distance;
|
||||||
|
|
||||||
|
camera.position = Vector3Add(target, Vector3(x, y, z));
|
||||||
|
camera.target = target;
|
||||||
|
}
|
||||||
11
src/main.cpp
11
src/main.cpp
@ -46,10 +46,11 @@ auto main(int argc, char *argv[]) -> int {
|
|||||||
InitWindow(INITIAL_WIDTH * 2, INITIAL_HEIGHT + MENU_HEIGHT, "MassSprings");
|
InitWindow(INITIAL_WIDTH * 2, INITIAL_HEIGHT + MENU_HEIGHT, "MassSprings");
|
||||||
|
|
||||||
// Game setup
|
// Game setup
|
||||||
Renderer renderer;
|
OrbitCamera3D camera;
|
||||||
|
Renderer renderer(camera);
|
||||||
MassSpringSystem mass_springs;
|
MassSpringSystem mass_springs;
|
||||||
StateManager state = StateManager(mass_springs);
|
StateManager state(mass_springs);
|
||||||
InputHandler input = InputHandler(state, renderer);
|
InputHandler input(state, renderer);
|
||||||
|
|
||||||
// Game loop
|
// Game loop
|
||||||
#ifdef PRINT_TIMINGS
|
#ifdef PRINT_TIMINGS
|
||||||
@ -68,7 +69,8 @@ auto main(int argc, char *argv[]) -> int {
|
|||||||
// Input update
|
// Input update
|
||||||
state.previous_state = state.current_state;
|
state.previous_state = state.current_state;
|
||||||
input.HandleInput();
|
input.HandleInput();
|
||||||
state.UpdateGraph();
|
state.UpdateGraph(); // Add state added after user input
|
||||||
|
camera.Update(mass_springs.GetMass(state.current_state).position);
|
||||||
|
|
||||||
// Physics update
|
// Physics update
|
||||||
#ifdef PRINT_TIMINGS
|
#ifdef PRINT_TIMINGS
|
||||||
@ -98,7 +100,6 @@ auto main(int argc, char *argv[]) -> int {
|
|||||||
std::chrono::high_resolution_clock::now();
|
std::chrono::high_resolution_clock::now();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
renderer.UpdateCamera(mass_springs, state.current_state);
|
|
||||||
renderer.UpdateTextureSizes();
|
renderer.UpdateTextureSizes();
|
||||||
renderer.DrawMassSprings(mass_springs, state.current_state,
|
renderer.DrawMassSprings(mass_springs, state.current_state,
|
||||||
state.winning_states);
|
state.winning_states);
|
||||||
|
|||||||
@ -15,91 +15,6 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto OrbitCamera3D::Update(const Mass ¤t_mass) -> void {
|
|
||||||
Vector2 mouse = GetMousePosition();
|
|
||||||
if (mouse.x >= GetScreenWidth() / 2.0 && mouse.y >= MENU_HEIGHT) {
|
|
||||||
if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) {
|
|
||||||
dragging = true;
|
|
||||||
last_mouse = mouse;
|
|
||||||
} else if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
|
|
||||||
panning = true;
|
|
||||||
target_lock = false;
|
|
||||||
last_mouse = mouse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsMouseButtonReleased(MOUSE_RIGHT_BUTTON)) {
|
|
||||||
dragging = false;
|
|
||||||
}
|
|
||||||
if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) {
|
|
||||||
panning = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsKeyPressed(KEY_L)) {
|
|
||||||
target_lock = !target_lock;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dragging) {
|
|
||||||
Vector2 dx = Vector2Subtract(mouse, last_mouse);
|
|
||||||
last_mouse = mouse;
|
|
||||||
|
|
||||||
angle_x -= dx.x * ROT_SPEED / 200.0;
|
|
||||||
angle_y += dx.y * ROT_SPEED / 200.0;
|
|
||||||
|
|
||||||
angle_y = Clamp(angle_y, -1.5, 1.5); // Prevent flipping
|
|
||||||
}
|
|
||||||
|
|
||||||
if (panning) {
|
|
||||||
Vector2 dx = Vector2Subtract(mouse, last_mouse);
|
|
||||||
last_mouse = mouse;
|
|
||||||
|
|
||||||
// float speed = PAN_SPEED;
|
|
||||||
float speed;
|
|
||||||
if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
|
||||||
speed = distance * PAN_SPEED / 1000.0 * PAN_MULTIPLIER;
|
|
||||||
} else {
|
|
||||||
speed = distance * PAN_SPEED / 1000.0;
|
|
||||||
}
|
|
||||||
Vector3 forward =
|
|
||||||
Vector3Normalize(Vector3Subtract(camera.target, camera.position));
|
|
||||||
Vector3 right = Vector3Normalize(Vector3CrossProduct(forward, camera.up));
|
|
||||||
Vector3 up = Vector3Normalize(Vector3CrossProduct(right, forward));
|
|
||||||
|
|
||||||
Vector3 offset = Vector3Add(Vector3Scale(right, -dx.x * speed),
|
|
||||||
Vector3Scale(up, dx.y * speed));
|
|
||||||
|
|
||||||
target = Vector3Add(target, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target_lock) {
|
|
||||||
target = current_mass.position;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mouse.x >= GetScreenWidth() / 2.0 && mouse.y >= MENU_HEIGHT) {
|
|
||||||
float wheel = GetMouseWheelMove();
|
|
||||||
if (IsKeyDown(KEY_LEFT_SHIFT)) {
|
|
||||||
distance -= wheel * ZOOM_SPEED * ZOOM_MULTIPLIER;
|
|
||||||
} else {
|
|
||||||
distance -= wheel * ZOOM_SPEED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
distance = Clamp(distance, MIN_CAMERA_DISTANCE, MAX_CAMERA_DISTANCE);
|
|
||||||
|
|
||||||
// Spherical coordinates
|
|
||||||
float x = cos(angle_y) * sin(angle_x) * distance;
|
|
||||||
float y = sin(angle_y) * distance;
|
|
||||||
float z = cos(angle_y) * cos(angle_x) * distance;
|
|
||||||
|
|
||||||
camera.position = Vector3Add(target, Vector3(x, y, z));
|
|
||||||
camera.target = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Renderer::UpdateCamera(const MassSpringSystem &mass_springs,
|
|
||||||
const State ¤t) -> void {
|
|
||||||
const Mass &c = mass_springs.masses.at(current);
|
|
||||||
camera.Update(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Renderer::UpdateTextureSizes() -> void {
|
auto Renderer::UpdateTextureSizes() -> void {
|
||||||
if (!IsWindowResized()) {
|
if (!IsWindowResized()) {
|
||||||
return;
|
return;
|
||||||
@ -128,6 +43,8 @@ auto Renderer::AllocateGraphInstancing(const MassSpringSystem &mass_springs)
|
|||||||
instancing_shader.locs[SHADER_LOC_VECTOR_VIEW] =
|
instancing_shader.locs[SHADER_LOC_VECTOR_VIEW] =
|
||||||
GetShaderLocation(instancing_shader, "viewPos");
|
GetShaderLocation(instancing_shader, "viewPos");
|
||||||
|
|
||||||
|
vertex_mat = LoadMaterialDefault();
|
||||||
|
vertex_mat.maps[MATERIAL_MAP_DIFFUSE].color = VERTEX_COLOR;
|
||||||
vertex_mat.shader = instancing_shader;
|
vertex_mat.shader = instancing_shader;
|
||||||
|
|
||||||
transforms = (Matrix *)MemAlloc(mass_springs.masses.size() * sizeof(Matrix));
|
transforms = (Matrix *)MemAlloc(mass_springs.masses.size() * sizeof(Matrix));
|
||||||
|
|||||||
Reference in New Issue
Block a user