diff --git a/include/config.hpp b/include/config.hpp index f239b0e..7157098 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -6,11 +6,12 @@ constexpr int WIDTH = 800; constexpr int HEIGHT = 800; -constexpr float VERTEX_SIZE = 5.0; +constexpr float VERTEX_SIZE = 50.0; constexpr Color VERTEX_COLOR = {27, 188, 104, 255}; constexpr Color EDGE_COLOR = {20, 133, 38, 255}; constexpr float SIM_SPEED = 4.0; +constexpr float ROTATION_SPEED = 1.0; constexpr float CAMERA_DISTANCE = 2.2; constexpr float DEFAULT_SPRING_CONSTANT = 1.5; diff --git a/include/mass_springs.hpp b/include/mass_springs.hpp index 495bdc6..6b28899 100644 --- a/include/mass_springs.hpp +++ b/include/mass_springs.hpp @@ -115,9 +115,7 @@ public: auto CalculateSpringForces() -> void; - auto IntegrateVelocities(const float delta_time) -> void; - - auto IntegratePositions(const float delta_time) -> void; + auto EulerUpdate(const float delta_time) -> void; auto VerletUpdate(const float delta_time) -> void; }; diff --git a/include/renderer.hpp b/include/renderer.hpp index dcb45c6..60c60d5 100644 --- a/include/renderer.hpp +++ b/include/renderer.hpp @@ -8,8 +8,11 @@ #include "mass_springs.hpp" -using Edge2Set = std::vector>; using Edge3Set = std::vector>; +using Edge2Set = std::vector>; +using Vertex2Set = + std::vector; // Vertex2Set uses Vector3 to retain the z-coordinate + // for circle size adaptation class Renderer { private: @@ -40,10 +43,12 @@ private: auto Map(const Vector2 &a) -> Vector2; public: - auto Transform(Edge2Set &edges, const MassSpringSystem &mass_springs, - const float angle, const float distance) -> void; + auto Transform(Edge2Set &edges, Vertex2Set &vertices, + const MassSpringSystem &mass_springs, const float angle, + const float distance) -> void; - auto Draw(const Edge2Set &edges) -> void; + auto DrawMassSprings(const Edge2Set &edges, const Vertex2Set &vertices) + -> void; }; #endif diff --git a/src/main.cpp b/src/main.cpp index 5dab9e6..851dce9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,9 +23,6 @@ auto main(int argc, char *argv[]) -> int { InitWindow(WIDTH, HEIGHT, "MassSprings"); - Edge3Set edges; - Edge2Set viewport; - viewport.reserve(edges.size()); MassSpringSystem mass_springs; mass_springs.AddMass(1.0, Vector3(-0.5, 0.5, 0.0), true); @@ -37,6 +34,10 @@ auto main(int argc, char *argv[]) -> int { DEFAULT_DAMPENING_CONSTANT, DEFAULT_REST_LENGTH); Renderer renderer(WIDTH, HEIGHT); + Edge2Set edges; + edges.reserve(mass_springs.springs.size()); + Vertex2Set vertices; + vertices.reserve(mass_springs.masses.size()); float frametime; float abstime = 0.0; @@ -48,28 +49,15 @@ auto main(int argc, char *argv[]) -> int { #ifdef VERLET_UPDATE mass_springs.VerletUpdate(frametime * SIM_SPEED); #else - mass_springs.IntegrateVelocities(frametime * SIM_SPEED); - mass_springs.IntegratePositions(frametime * SIM_SPEED); + mass_springs.EulerUpdate(frametime * SIM_SPEED); #endif - // std::cout << "Calculating Spring Forces: A: (" << massA.force.x << ", " - // << massA.force.y << ", " << massA.force.z << ") B: (" - // << massB.force.x << ", " << massB.force.y << ", " << - // massB.force.z - // << ")" << std::endl; - // std::cout << "Calculating Velocities: A: (" << massA.velocity.x << ", " - // << massA.velocity.y << ", " << massA.velocity.z << ") B: (" - // << massB.velocity.x << ", " << massB.velocity.y << ", " - // << massB.velocity.z << ")" << std::endl; - // std::cout << "Calculating Positions: A: (" << massA.position.x << ", " - // << massA.position.y << ", " << massA.position.z << ") B: (" - // << massB.position.x << ", " << massB.position.y << ", " - // << massB.position.z << ")" << std::endl; + renderer.Transform(edges, vertices, mass_springs, abstime * ROTATION_SPEED, + CAMERA_DISTANCE); + renderer.DrawMassSprings(edges, vertices); - renderer.Transform(viewport, mass_springs, 0.0, CAMERA_DISTANCE); renderer.Draw(viewport); - - abstime += frametime * SIM_SPEED; + abstime += frametime; } CloseWindow(); diff --git a/src/mass_springs.cpp b/src/mass_springs.cpp index 1bc7794..ee3d41e 100644 --- a/src/mass_springs.cpp +++ b/src/mass_springs.cpp @@ -104,14 +104,9 @@ auto MassSpringSystem::CalculateSpringForces() -> void { } } -auto MassSpringSystem::IntegrateVelocities(const float delta_time) -> void { +auto MassSpringSystem::EulerUpdate(const float delta_time) -> void { for (auto &mass : masses) { mass.CalculateVelocity(delta_time); - } -} - -auto MassSpringSystem::IntegratePositions(const float delta_time) -> void { - for (auto &mass : masses) { mass.CalculatePosition(delta_time); } } diff --git a/src/renderer.cpp b/src/renderer.cpp index f0ff754..037f62b 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -21,31 +21,47 @@ auto Renderer::Map(const Vector2 &a) -> Vector2 { return Vector2((1.0 + a.x) / 2.0 * width, (1.0 - a.y) * height / 2.0); } -auto Renderer::Transform(Edge2Set &edges, const MassSpringSystem &mass_springs, +auto Renderer::Transform(Edge2Set &edges, Vertex2Set &vertices, + const MassSpringSystem &mass_springs, const float angle, const float distance) -> void { - edges.clear(); - const float cos_angle = cos(angle); const float sin_angle = sin(angle); + edges.clear(); for (const auto &spring : mass_springs.springs) { - Vector2 at = Map(Project(Translate( + Vector2 a = Map(Project(Translate( Rotate(spring.massA.position, cos_angle, sin_angle), distance))); - Vector2 bt = Map(Project(Translate( + Vector2 b = Map(Project(Translate( Rotate(spring.massB.position, cos_angle, sin_angle), distance))); - edges.emplace_back(at, bt); + edges.emplace_back(a, b); + } + + // This is duplicated work, but easy to read + vertices.clear(); + for (const auto &mass : mass_springs.masses) { + Vector3 a = + Translate(Rotate(mass.position, cos_angle, sin_angle), distance); + Vector2 b = Map(Project(a)); + + vertices.emplace_back(b.x, b.y, a.z); } } -auto Renderer::Draw(const Edge2Set &edges) -> void { +auto Renderer::DrawMassSprings(const Edge2Set &edges, + const Vertex2Set &vertices) -> void { BeginTextureMode(render_target); ClearBackground(RAYWHITE); for (const auto &[a, b] : edges) { DrawLine(a.x, a.y, b.x, b.y, EDGE_COLOR); - DrawCircle(a.x, a.y, VERTEX_SIZE, VERTEX_COLOR); - DrawCircle(b.x, b.y, VERTEX_SIZE, VERTEX_COLOR); } + for (const auto &a : vertices) { + // Increase the perspective perception by squaring the z-coordinate + const float size = VERTEX_SIZE / (a.z * a.z); + + DrawRectangle(a.x - size / 2.0, a.y - size / 2.0, size, size, VERTEX_COLOR); + } + DrawLine(0, 0, 0, height, BLACK); EndTextureMode(); BeginDrawing();