#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 #include #include #include #include #include struct Rigidbody { Vector2 force = { 0, 0 }; Vector2 velocity = { 0, 0 }; Vector2 position = { 0, 0 }; float32 rotationalVelocity = 0.f; float32 rotation = 0.f; float32 mass = 1.f; float32 cofOfRestition = 1.f; float32 momentOfInertia = 0.f; void reset() { force = { 0, 0 }; velocity = { 0, 0 }; rotationalVelocity = 0.f; rotation = 0.f; } void applyForce(Vector2 f) { force += f; } void applyGravity(float32 deltaTimeSeconds) { velocity += (Vector2 { 0.f, -96.f } * deltaTimeSeconds); } void update(float32 deltaTimeSeconds) { applyGravity(deltaTimeSeconds); Vector2 acceleration = force / mass; velocity += (acceleration * deltaTimeSeconds); position += (velocity * deltaTimeSeconds); force = Vector2 { 0.f, 0.f }; rotation += (rotationalVelocity * deltaTimeSeconds); } void setMomentOfInertia(float32 moi) { momentOfInertia = moi; } }; struct PillInData { Vector4 color = Vector4 { 255.f, 0.f, 0.f, 255.f }; float32 width = 0; float32 height = 0; float32 numSegments = 0; }; struct Pill { Mesh2d shape; Rigidbody body; float32 a = 0; float32 b = 0; Pill copy() { Pill retval; retval.shape = shape; retval.body = body; retval.a = a; retval.b = b; return retval; } void load(Renderer2d* renderer, PillInData data) { float32 angleIncrements = (2.f * PI) / data.numSegments; uint32 numVertices = static_cast(data.numSegments * 3.f); Vertex2d* vertices = new Vertex2d[numVertices]; a = data.width / 2.f; b = data.height / 2.f; Vector4 color = Vector4().fromColor(data.color.x, data.color.y, data.color.z, data.color.w); for (uint32 vertexIndex = 0; vertexIndex < numVertices; vertexIndex += 3) { // Create a single "slice" of the ellipse (like a pizza) float32 currAngle = (vertexIndex / 3.f) * angleIncrements; float32 nextAngle = (vertexIndex / 3.f + 1.f) * angleIncrements; vertices[vertexIndex].position = Vector2 { 0.f, 0.f }; vertices[vertexIndex].color = color; vertices[vertexIndex + 1].position = Vector2 { a * cosf(currAngle), b * sinf(currAngle) }; vertices[vertexIndex + 1].color = color; vertices[vertexIndex + 2].position = Vector2 { a * cosf(nextAngle), b * sinf(nextAngle) }; vertices[vertexIndex + 2].color = color; } shape.load(vertices, numVertices, renderer); body.reset(); body.mass = 100.f; body.momentOfInertia = (body.mass * (a * a + b * b)) / 4.f; delete[] vertices; } void update(float32 deltaTimeSeconds) { body.update(deltaTimeSeconds); shape.model = Mat4x4().translateByVec2(body.position).rotate2D(body.rotation); } void render(Renderer2d* renderer) { shape.render(renderer); } void unload() { shape.unload(); } float32 getArea() { return 0.f; } }; struct IntersectionResult { bool intersect = false; Vector2 collisionNormal; Vector2 relativeVelocity; Vector2 firstPointOfApplication; Vector2 secondPointOfApplication; }; EM_BOOL onPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData); EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData); void load(); void update(float32 time, void* userData); void unload(); WebglContext context; Renderer2d renderer; MainLoop mainLoop; Pill pillList[2]; int main() { context.init("#gl_canvas"); emscripten_set_click_callback("#gl_canvas_play", NULL, false, onPlayClicked); emscripten_set_click_callback("#gl_canvas_stop", NULL, false, onStopClicked); return 0; } void load() { renderer.load(&context); PillInData _0data; _0data.width = 100.f; _0data.height = 50.f; _0data.numSegments = 64.f; _0data.color = Vector4 { 233.f, 100.f, 0.f, 255.f }; pillList[0].load(&renderer, _0data); PillInData _1data; _1data.width = 35.f; _1data.height = 60.f; _1data.numSegments = 64.f; _1data.color = Vector4 { 0.f, 100.f, 233.f, 255.f }; pillList[1].load(&renderer, _1data); pillList[0].body.position = Vector2 { context.width / 2.f, static_cast(context.height) }; pillList[1].body.position = Vector2 { context.width / 2.f, context.height / 2.f }; pillList[1].body.velocity = Vector2 { 0.f, 150.f }; mainLoop.run(update); } IntersectionResult getIntersection(Pill* first, Pill* second) { IntersectionResult ir; float32 a1 = first->a; float32 b1 = first->b; float32 a1Squared = a1 * a1; float32 b1Squared = b1 * b1; float32 a1Quad = a1Squared * a1Squared; float32 b1Quad = b1Squared * b1Squared; float32 a2 = second->a; float32 b2 = second->b; float32 a2Squared = a2 * a2; float32 b2Squared = b2 * b2; float32 a2Quad = a2Squared * a2Squared; float32 b2Quad = b2Squared * b2Squared; float32 A = (b1Quad / (a1Quad * b2Squared)); float32 B = (2.f * b1Quad) / (a1Squared * b2Squared) + (1.f / a1Squared); float32 C = (b1Quad / b2Squared) - 1.f; float32 determinant = (B * B) - (4.f * A * C); printf("%f\n", determinant); return ir; } void update(float32 deltaTimeSeconds, void* userData) { // Update for (int32 pillIdx = 0; pillIdx < 2; pillIdx++) { pillList[pillIdx].update(deltaTimeSeconds); } getIntersection(&pillList[0], &pillList[1]); // Render renderer.render(); for (int32 pillIdx = 0; pillIdx < 2; pillIdx++) { pillList[pillIdx].render(&renderer); } } void unload() { mainLoop.stop(); for (int32 pillIdx = 0; pillIdx < 2; pillIdx++) { pillList[pillIdx].unload(); } renderer.unload(); } // // Interactions with DOM handled below // EM_BOOL onPlayClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) { printf("Play clicked\n"); load(); return true; } EM_BOOL onStopClicked(int eventType, const EmscriptenMouseEvent* mouseEvent, void* userData) { printf("Stop clicked\n"); unload(); return true; }