summaryrefslogtreecommitdiff
path: root/2d/softbody/softbody_1/undamped.cpp
diff options
context:
space:
mode:
Diffstat (limited to '2d/softbody/softbody_1/undamped.cpp')
-rw-r--r--2d/softbody/softbody_1/undamped.cpp227
1 files changed, 227 insertions, 0 deletions
diff --git a/2d/softbody/softbody_1/undamped.cpp b/2d/softbody/softbody_1/undamped.cpp
new file mode 100644
index 0000000..ec53f50
--- /dev/null
+++ b/2d/softbody/softbody_1/undamped.cpp
@@ -0,0 +1,227 @@
+#include "undamped.h"
+#include "../../../shared_cpp/Renderer2d.h"
+#include "../../../shared_cpp/types.h"
+#include "../../../shared_cpp/WebglContext.h"
+#include "../../../shared_cpp/mathlib.h"
+#include "../../../shared_cpp/MainLoop.h"
+#include <cstdio>
+#include <cmath>
+#include <emscripten/html5.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <cmath>
+#include <cfloat>
+
+namespace Undamped {
+
+ struct SpringWeight {
+ Mesh2d shape;
+ float32 radius;
+ float32 mass = 2.f;
+
+ void load(Renderer2d* renderer, float32 inRadius, Vector4 startColor, Vector4 endColor);
+ void update(float32 dtSeconds);
+ void render(Renderer2d* renderer);
+ void unload();
+ };
+
+ struct Spring {
+ SpringWeight* weight;
+
+ Mesh2d shape;
+
+ Vertex2d* vertices = NULL;
+ int32 numSegments = 0;
+ int32 numVertices = 0;
+ float32 k = 4; // Spring Constant, in N / m
+ float32 initialDisplacement = 3.f;
+ float32 initialVelocity = 0.f;
+ float32 angularVelocity = 0.f; // To be calculated
+ float32 displacement = 0.f;
+ float32 timeElapsed = 0.f;
+
+ void load(Renderer2d* renderer, SpringWeight* inWieight, float32 length, float32 loopRadius);
+ void update(float32 dtSeconds);
+ void render(Renderer2d* renderer);
+ void unload();
+ };
+
+ WebglContext* context;
+ Renderer2d renderer;
+ MainLoop mainLoop;
+ SpringWeight weight;
+ Spring spring;
+
+ EM_BOOL onUndampedPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
+ EM_BOOL onUndampedStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData);
+ void load();
+ void update(float32 deltaTimeSeconds, void* userData);
+ void unload();
+
+ void init(WebglContext* inContext) {
+ context = inContext;
+ emscripten_set_click_callback("#gl_canvas_play_undamped", NULL, false, onUndampedPlayClicked);
+ emscripten_set_click_callback("#gl_canvas_stop_undamped", NULL, false, onUndampedStopClicked);
+ }
+
+ void load() {
+ context->init("#gl_canvas_undamped");
+
+ renderer.load(context);
+
+ weight.load(&renderer, 32.f, Vector4 { 55.f, 235.f, 35.f, 255.f }, Vector4 { 235.f, 5.f, 235.f, 255.f });
+ spring.load(&renderer, &weight, 250.f, 64.f);
+
+ mainLoop.run(update);
+ }
+
+ void update(float32 deltaTimeSeconds, void* userData) {
+ // -- Update
+ spring.update(deltaTimeSeconds);
+ weight.update(deltaTimeSeconds);
+
+ // -- Render
+ renderer.render();
+ weight.render(&renderer);
+ spring.render(&renderer);
+ }
+
+ void unload() {
+ mainLoop.stop();
+ renderer.unload();
+ weight.unload();
+ spring.unload();
+
+ context->destroy();
+ }
+
+
+ void SpringWeight::load(Renderer2d* renderer, float32 inRadius, Vector4 startColor, Vector4 endColor) {
+ radius = inRadius;
+ const int32 numSegments = 96;
+ const float32 radiansPerSegment = (2.f * PI) / static_cast<float>(numSegments);
+ const int32 numVertices = numSegments * 3;
+
+ float32 t = 0.f;
+ float32 tIncrement = 1.f / (numSegments / 2.f);
+ startColor = startColor.toNormalizedColor();
+ endColor = endColor.toNormalizedColor();
+
+ Vertex2d vertices[numVertices];
+ for (int idx = 0; idx < numSegments; idx++) {
+ int vIdx = idx * 3;
+
+ Vector4 color = lerp(startColor, endColor, t);
+ if (idx >= numSegments / 2) {
+ t -= tIncrement;
+ } else {
+ t += tIncrement;
+ }
+
+ vertices[vIdx].color = color;
+ vertices[vIdx].position = Vector2 { radius * cosf(radiansPerSegment * idx), radius * sinf(radiansPerSegment * idx) };
+ vertices[vIdx + 1].color = color;
+ vertices[vIdx + 1].position = Vector2 { 0.f, 0.f };
+ vertices[vIdx + 2].color = color;
+ vertices[vIdx + 2].position = Vector2 { radius * cosf(radiansPerSegment * (idx + 1)), radius * sinf(radiansPerSegment * (idx + 1)) };
+ }
+
+ shape.load(vertices, numVertices, renderer);
+ }
+
+ void SpringWeight::update(float32 dtSeconds) {
+
+ }
+
+ void SpringWeight::render(Renderer2d* renderer) {
+ shape.render(renderer);
+ }
+
+ void SpringWeight::unload() {
+ shape.unload();
+ }
+
+ void Spring::load(Renderer2d* renderer, SpringWeight* inWeight, float32 length, float32 loopRadius) {
+ weight = inWeight;
+ angularVelocity = sqrtf(k / weight->mass);
+ timeElapsed = 0.f;
+
+ const int32 verticesPerSegment = 6;
+ numSegments = 256;
+ numVertices = numSegments * verticesPerSegment;
+ vertices = new Vertex2d[numVertices];
+
+ float32 lengthIncrement = length / static_cast<float32>(numSegments);
+
+ const float32 frequency = 0.25f;
+ const float32 loopWidth = 20.f;
+ const float32 offset = 0.25f;
+
+ int32 vidx = 0;
+ for (int pidx = 0; pidx < numSegments; pidx++) {
+ float32 y1 = lengthIncrement * pidx;
+ float32 x1 = loopWidth * sinf(frequency * y1 + offset);
+
+ float32 y2 = y1 + lengthIncrement;
+ float32 x2 = loopWidth * sinf(frequency * y2 + offset);
+
+ vertices[vidx++].position = Vector2(x1, y1);
+ vertices[vidx++].position = Vector2(x1, y2);
+ vertices[vidx++].position = Vector2(x2, y1);
+ vertices[vidx++].position = Vector2(x2, y1);
+ vertices[vidx++].position = Vector2(x1, y2);
+ vertices[vidx++].position = Vector2(x2, y2);
+ }
+
+ shape.load(vertices, numVertices, renderer, GL_DYNAMIC_DRAW);
+ shape.model = Mat4x4().translateByVec2(Vector2(400, 300));
+
+ weight->shape.model = shape.model.translateByVec2(Vector2(0, -weight->radius));
+ }
+
+ void Spring::update(float32 dtSeconds) {
+ timeElapsed += dtSeconds;
+ displacement = initialDisplacement * cosf(angularVelocity * timeElapsed - initialVelocity);
+
+ int32 vidx = 0;
+ for (int pidx = 0; pidx < numSegments; pidx++) {
+ float32 y1Offset = displacement * (1.f - pidx / static_cast<float32>(numSegments));
+ float32 y2Offset = displacement * (1.f - (pidx + 1) / static_cast<float32>(numSegments));
+ vertices[vidx++].position.y += y1Offset;
+ vertices[vidx++].position.y += y2Offset;
+ vertices[vidx++].position.y += y1Offset;
+ vertices[vidx++].position.y += y1Offset;
+ vertices[vidx++].position.y += y2Offset;
+ vertices[vidx++].position.y += y2Offset;
+ }
+
+ weight->shape.model = weight->shape.model.translateByVec2(Vector2(0, displacement));
+ }
+
+ void Spring::render(Renderer2d* renderer) {
+ glBindBuffer(GL_ARRAY_BUFFER, shape.vbo);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, numVertices * sizeof(Vertex2d), &vertices[0]);
+
+ shape.render(renderer);
+ }
+
+ void Spring::unload() {
+ shape.unload();
+ delete[] vertices;
+ }
+
+
+ EM_BOOL onUndampedPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) {
+ printf("Play clicked\n");
+
+ load();
+ return true;
+ }
+
+ EM_BOOL onUndampedStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) {
+ printf("Stop clicked\n");
+ unload();
+ return true;
+ }
+
+}