implement option to lock camera to graph's center of mass
This commit is contained in:
@ -41,12 +41,21 @@ auto OrbitCamera3D::Pan(Vector2 last_mouse, Vector2 mouse) -> void {
|
||||
target = Vector3Add(target, offset);
|
||||
}
|
||||
|
||||
auto OrbitCamera3D::Update(const Vector3 ¤t_target, bool lock) -> void {
|
||||
auto OrbitCamera3D::Update(const Vector3 ¤t_target,
|
||||
const Vector3 &mass_center, bool lock,
|
||||
bool mass_center_lock) -> void {
|
||||
if (lock) {
|
||||
target = Vector3MoveTowards(
|
||||
target, current_target,
|
||||
CAMERA_SMOOTH_SPEED * GetFrameTime() *
|
||||
Vector3Length(Vector3Subtract(target, current_target)));
|
||||
if (mass_center_lock) {
|
||||
target = Vector3MoveTowards(
|
||||
target, mass_center,
|
||||
CAMERA_SMOOTH_SPEED * GetFrameTime() *
|
||||
Vector3Length(Vector3Subtract(target, mass_center)));
|
||||
} else {
|
||||
target = Vector3MoveTowards(
|
||||
target, current_target,
|
||||
CAMERA_SMOOTH_SPEED * GetFrameTime() *
|
||||
Vector3Length(Vector3Subtract(target, current_target)));
|
||||
}
|
||||
}
|
||||
|
||||
distance = Clamp(distance, MIN_CAMERA_DISTANCE, MAX_CAMERA_DISTANCE);
|
||||
@ -60,7 +69,7 @@ auto OrbitCamera3D::Update(const Vector3 ¤t_target, bool lock) -> void {
|
||||
float y = sin(angle_y) * actual_distance;
|
||||
float z = cos(angle_y) * cos(angle_x) * actual_distance;
|
||||
|
||||
fov = Clamp(fov, 25.0, 155.0);
|
||||
fov = Clamp(fov, MIN_FOV, MAX_FOV);
|
||||
|
||||
camera.position = Vector3Add(target, Vector3(x, y, z));
|
||||
camera.target = target;
|
||||
|
||||
32
src/gui.cpp
32
src/gui.cpp
@ -482,39 +482,47 @@ auto Gui::DrawGraphInfo(Color color) const -> void {
|
||||
}
|
||||
|
||||
auto Gui::DrawGraphControls(Color color) const -> void {
|
||||
if (DrawMenuButton(1, 2, 1, 1, "Populate Graph (G)", color)) {
|
||||
if (DrawMenuButton(0, 2, 1, 1, "Populate Graph (G)", color)) {
|
||||
input.FillGraph();
|
||||
}
|
||||
|
||||
int mark_path = input.mark_path;
|
||||
DrawMenuToggleSlider(2, 2, 1, 1, "Path Hidden (U)", "Path Shown (U)",
|
||||
&mark_path, color);
|
||||
if (mark_path != input.mark_path) {
|
||||
input.ToggleMarkPath();
|
||||
}
|
||||
// int mark_path = input.mark_path;
|
||||
// DrawMenuToggleSlider(2, 2, 1, 1, "Path Hidden (U)", "Path Shown (U)",
|
||||
// &mark_path, color);
|
||||
// if (mark_path != input.mark_path) {
|
||||
// input.ToggleMarkPath();
|
||||
// }
|
||||
|
||||
if (DrawMenuButton(1, 3, 1, 1, "Clear Graph (C)", color)) {
|
||||
if (DrawMenuButton(1, 2, 1, 1, "Clear Graph (C)", color)) {
|
||||
input.ClearGraph();
|
||||
}
|
||||
|
||||
int mark_solutions = input.mark_solutions;
|
||||
DrawMenuToggleSlider(2, 3, 1, 1, "Solutions Hidden (I)",
|
||||
"Solutions Shown (I)", &mark_solutions, color);
|
||||
DrawMenuToggleSlider(2, 2, 1, 1, "Solution Hidden (I)", "Solution Shown (I)",
|
||||
&mark_solutions, color);
|
||||
if (mark_solutions != input.mark_solutions) {
|
||||
input.ToggleMarkSolutions();
|
||||
}
|
||||
input.mark_path = input.mark_solutions;
|
||||
}
|
||||
|
||||
auto Gui::DrawCameraControls(Color color) const -> void {
|
||||
int lock_camera = input.camera_lock;
|
||||
DrawMenuToggleSlider(0, 2, 1, 1, "Free Camera (L)", "Locked Camera (L)",
|
||||
DrawMenuToggleSlider(0, 3, 1, 1, "Free Camera (L)", "Locked Camera (L)",
|
||||
&lock_camera, color);
|
||||
if (lock_camera != input.camera_lock) {
|
||||
input.ToggleCameraLock();
|
||||
}
|
||||
|
||||
int lock_camera_mass_center = input.camera_mass_center_lock;
|
||||
DrawMenuToggleSlider(1, 3, 1, 1, "Current Block (Y)", "Graph Center (Y)",
|
||||
&lock_camera_mass_center, color, input.camera_lock);
|
||||
if (lock_camera_mass_center != input.camera_mass_center_lock) {
|
||||
input.ToggleCameraMassCenterLock();
|
||||
}
|
||||
|
||||
int projection = camera.projection == CAMERA_ORTHOGRAPHIC;
|
||||
DrawMenuToggleSlider(0, 3, 1, 1, "Perspective (Alt)", "Orthographic (Alt)",
|
||||
DrawMenuToggleSlider(2, 3, 1, 1, "Perspective (Alt)", "Orthographic (Alt)",
|
||||
&projection, color);
|
||||
if (projection != (camera.projection == CAMERA_ORTHOGRAPHIC)) {
|
||||
input.ToggleCameraProjection();
|
||||
|
||||
@ -43,7 +43,7 @@ auto InputHandler::InitHandlers() -> void {
|
||||
RegisterKeyPressedHandler(KEY_C, &InputHandler::ClearGraph);
|
||||
RegisterKeyPressedHandler(KEY_I, &InputHandler::ToggleMarkSolutions);
|
||||
RegisterKeyPressedHandler(KEY_O, &InputHandler::ToggleConnectSolutions);
|
||||
RegisterKeyPressedHandler(KEY_U, &InputHandler::ToggleMarkPath);
|
||||
// RegisterKeyPressedHandler(KEY_U, &InputHandler::ToggleMarkPath);
|
||||
RegisterKeyPressedHandler(KEY_SPACE, &InputHandler::MakeOptimalMove);
|
||||
RegisterKeyPressedHandler(KEY_V, &InputHandler::GoToWorstState);
|
||||
RegisterKeyPressedHandler(KEY_B, &InputHandler::GoToNearestTarget);
|
||||
@ -60,6 +60,7 @@ auto InputHandler::InitHandlers() -> void {
|
||||
RegisterKeyPressedHandler(KEY_LEFT_ALT,
|
||||
&InputHandler::ToggleCameraProjection);
|
||||
RegisterKeyPressedHandler(KEY_X, &InputHandler::ClearGoal);
|
||||
RegisterKeyPressedHandler(KEY_Y, &InputHandler::ToggleCameraMassCenterLock);
|
||||
}
|
||||
|
||||
auto InputHandler::MouseInMenuPane() -> bool { return mouse.y < MENU_HEIGHT; }
|
||||
@ -145,6 +146,15 @@ auto InputHandler::ToggleCameraLock() -> void {
|
||||
camera_lock = !camera_lock;
|
||||
}
|
||||
|
||||
auto InputHandler::ToggleCameraMassCenterLock() -> void {
|
||||
if (!camera_mass_center_lock) {
|
||||
camera_lock = true;
|
||||
camera_panning = false;
|
||||
}
|
||||
|
||||
camera_mass_center_lock = !camera_mass_center_lock;
|
||||
}
|
||||
|
||||
auto InputHandler::ToggleCameraProjection() -> void {
|
||||
camera.projection = camera.projection == CAMERA_PERSPECTIVE
|
||||
? CAMERA_ORTHOGRAPHIC
|
||||
|
||||
11
src/main.cpp
11
src/main.cpp
@ -16,6 +16,8 @@
|
||||
#endif
|
||||
|
||||
// TODO: Click states in the graph to display them in the board
|
||||
// TODO: Move selection accordingly when undoing moves (need to diff two states
|
||||
// and get the moved blocks)
|
||||
|
||||
// TODO: Add some popups (my split between input.cpp/gui.cpp makes this ugly)
|
||||
// - Next move, goto target, goto worst: Notify that the graph needs to be
|
||||
@ -83,8 +85,9 @@ auto main(int argc, char *argv[]) -> int {
|
||||
unsigned int loop_iterations = 0;
|
||||
|
||||
unsigned int fps = 0;
|
||||
unsigned int ups = 0; // Read from physics
|
||||
std::vector<Vector3> masses; // Read from physics
|
||||
unsigned int ups = 0; // Read from physics
|
||||
Vector3 mass_center = Vector3Zero(); // Read from physics
|
||||
std::vector<Vector3> masses; // Read from physics
|
||||
|
||||
// Game loop
|
||||
while (!WindowShouldClose()) {
|
||||
@ -114,6 +117,7 @@ auto main(int argc, char *argv[]) -> int {
|
||||
#endif
|
||||
|
||||
ups = physics.state.ups;
|
||||
mass_center = physics.state.mass_center;
|
||||
|
||||
// Only copy data if any has been produced
|
||||
if (physics.state.data_ready) {
|
||||
@ -135,7 +139,8 @@ auto main(int argc, char *argv[]) -> int {
|
||||
std::size_t current_index = state.CurrentMassIndex();
|
||||
if (masses.size() > current_index) {
|
||||
const Mass ¤t_mass = masses.at(current_index);
|
||||
camera.Update(current_mass.position, input.camera_lock);
|
||||
camera.Update(current_mass.position, mass_center, input.camera_lock,
|
||||
input.camera_mass_center_lock);
|
||||
}
|
||||
|
||||
// Rendering
|
||||
|
||||
@ -276,6 +276,11 @@ auto ThreadedPhysics::PhysicsThread(ThreadedPhysics::PhysicsState &state)
|
||||
loop_iterations = 0;
|
||||
ups_accumulator = std::chrono::duration<double>(0);
|
||||
}
|
||||
if (mass_springs.octree.nodes.size() > 0) {
|
||||
state.mass_center = mass_springs.octree.nodes.at(0).mass_center;
|
||||
} else {
|
||||
state.mass_center = Vector3Zero();
|
||||
}
|
||||
|
||||
state.masses.clear();
|
||||
state.masses.reserve(mass_springs.masses.size());
|
||||
|
||||
@ -129,13 +129,13 @@ auto Renderer::DrawMassSprings(const std::vector<Vector3> &masses) -> void {
|
||||
const Vector3 &winning_mass = masses.at(winning_index);
|
||||
if (input.mark_solutions) {
|
||||
DrawCube(winning_mass, 2 * VERTEX_SIZE, 2 * VERTEX_SIZE,
|
||||
2 * VERTEX_SIZE, TARGET_BLOCK_COLOR);
|
||||
2 * VERTEX_SIZE, VERTEX_TARGET_COLOR);
|
||||
}
|
||||
|
||||
std::size_t current_index = state.CurrentMassIndex();
|
||||
if (input.connect_solutions && masses.size() > current_index) {
|
||||
const Vector3 ¤t_mass = masses.at(current_index);
|
||||
DrawLine3D(winning_mass, current_mass, ORANGE);
|
||||
DrawLine3D(winning_mass, current_mass, Fade(TARGET_BLOCK_COLOR, 0.5));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,7 +148,7 @@ auto Renderer::DrawMassSprings(const std::vector<Vector3> &masses) -> void {
|
||||
if (masses.size() > visited_index) {
|
||||
const Vector3 &visited_mass = masses.at(visited_index);
|
||||
DrawCube(visited_mass, VERTEX_SIZE * 1.5, VERTEX_SIZE * 1.5,
|
||||
VERTEX_SIZE * 1.5, PURPLE);
|
||||
VERTEX_SIZE * 1.5, VERTEX_VISITED_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
@ -158,7 +158,7 @@ auto Renderer::DrawMassSprings(const std::vector<Vector3> &masses) -> void {
|
||||
if (masses.size() > _state) {
|
||||
const Vector3 &path_mass = masses.at(_state);
|
||||
DrawCube(path_mass, VERTEX_SIZE * 1.75, VERTEX_SIZE * 1.75,
|
||||
VERTEX_SIZE * 1.75, YELLOW);
|
||||
VERTEX_SIZE * 1.75, VERTEX_PATH_COLOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -168,7 +168,7 @@ auto Renderer::DrawMassSprings(const std::vector<Vector3> &masses) -> void {
|
||||
if (masses.size() > starting_index) {
|
||||
const Vector3 &starting_mass = masses.at(starting_index);
|
||||
DrawCube(starting_mass, VERTEX_SIZE * 2, VERTEX_SIZE * 2, VERTEX_SIZE * 2,
|
||||
ORANGE);
|
||||
VERTEX_START_COLOR);
|
||||
}
|
||||
|
||||
// Mark current state
|
||||
@ -176,7 +176,7 @@ auto Renderer::DrawMassSprings(const std::vector<Vector3> &masses) -> void {
|
||||
if (masses.size() > current_index) {
|
||||
const Vector3 ¤t_mass = masses.at(current_index);
|
||||
DrawCube(current_mass, VERTEX_SIZE * 2, VERTEX_SIZE * 2, VERTEX_SIZE * 2,
|
||||
BLUE);
|
||||
VERTEX_CURRENT_COLOR);
|
||||
}
|
||||
|
||||
EndMode3D();
|
||||
|
||||
Reference in New Issue
Block a user