From a00c0aab1eb5a7a55bef8ca08115bdd722ab5699 Mon Sep 17 00:00:00 2001 From: Matthew Kosarek Date: Sun, 16 May 2021 19:50:15 -0400 Subject: Moved the frontend directory up so that it no longer exists --- .../2d/_collisions/rectangle_rectangle/main.cpp | 447 --------------------- 1 file changed, 447 deletions(-) delete mode 100644 frontend/2d/_collisions/rectangle_rectangle/main.cpp (limited to 'frontend/2d/_collisions/rectangle_rectangle/main.cpp') diff --git a/frontend/2d/_collisions/rectangle_rectangle/main.cpp b/frontend/2d/_collisions/rectangle_rectangle/main.cpp deleted file mode 100644 index 99dafe5..0000000 --- a/frontend/2d/_collisions/rectangle_rectangle/main.cpp +++ /dev/null @@ -1,447 +0,0 @@ -#include "../../../shared_cpp/OrthographicRenderer.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 -#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, -50.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 IntersectionResult { - bool intersect = false; - Vector2 collisionNormal; - Vector2 relativeVelocity; - Vector2 firstPointOfApplication; - Vector2 secondPointOfApplication; -}; - -struct Edge { - Vector2 normal; - Vector2 start; - Vector2 end; -}; - -struct Rectangle { - OrthographicShape shape; - Rigidbody body; - Rigidbody previousBody; - Vector4 color; - float32 width = 0.f; - float32 height = 0.f; - - void load(OrthographicRenderer* renderer, Vector4 inColor, float32 inWidth, float32 inHeight) { - color = inColor.toNormalizedColor(); - width = inWidth;; - height = inHeight; - - float32 halfWidth = width / 2.f; - float32 halfHeight = height / 2.f; - - OrthographicVertex vertices[6]; - vertices[0].position = Vector2 { -halfWidth, -halfHeight }; - vertices[1].position = Vector2 { -halfWidth, halfHeight }; - vertices[2].position = Vector2 { halfWidth, halfHeight }; - vertices[3].position = Vector2 { -halfWidth, -halfHeight }; - vertices[4].position = Vector2 { halfWidth, -halfHeight }; - vertices[5].position = Vector2 { halfWidth, halfHeight }; - - for (int32 i = 0; i < 6; i++) { - vertices[i].color = color; - } - - shape.load(vertices, 6, renderer); - body.reset(); - body.momentOfInertia = (1.f / 12.f) * body.mass * (width + height * height * height); - } - - void update(float32 dtSeconds) { - previousBody = body; - - body.update(dtSeconds); - shape.model = Mat4x4().translateByVec2(body.position).rotate2D(body.rotation); - } - - void render(OrthographicRenderer* renderer) { - shape.render(renderer); - } - - void unload() { - shape.unload(); - } - - void restorePreviousBody() { - body = previousBody; - } - - Vector2 getPoint(int index) { - switch (index) { - case 0: return shape.model * Vector2 { -width / 2.f, -height / 2.f }; - case 1: return shape.model * Vector2 { -width / 2.f, height / 2.f }; - case 2: return shape.model * Vector2 { width / 2.f, height / 2.f }; - case 3: return shape.model * Vector2 { width / 2.f, -height / 2.f }; - default: { - printf("Unable to find point: index=%d", index); - return Vector2(); - } - } - } - - // Note that these getters are needlessly verbose for demonstration's sake - void getPoints(Vector2* pointList) { - Vector2 botLeft = shape.model * Vector2 { -width / 2.f, -height / 2.f }; - Vector2 topLeft = shape.model * Vector2 { -width / 2.f, height / 2.f }; - Vector2 topRight = shape.model * Vector2 { width / 2.f, height / 2.f }; - Vector2 botRight = shape.model * Vector2 { width / 2.f, -height / 2.f }; - - pointList[0] = botLeft; - pointList[1] = topLeft; - pointList[2] = topRight; - pointList[3] = botRight; - } - - void getEdges(Edge* edgeList) { - Vector2 pointsList[4]; - getPoints(pointsList); - - for (int i = 0; i < 4; i++) { - edgeList[i].start = pointsList[i]; - if (i + 1 == 4) { - edgeList[i].end = pointsList[0]; - } else { - edgeList[i].end = pointsList[i + 1]; - } - - edgeList[i].normal = (edgeList[i].end - edgeList[i].start).getPerp().normalize(); - } - } -}; - -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; -OrthographicRenderer renderer; -MainLoop mainLoop; -Rectangle rectangleList[4]; - -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); - - rectangleList[0].load(&renderer, Vector4 { 235.f, 35.f, 35.f, 255.f }, 24.f, 32.f); - rectangleList[0].body.position = Vector2 { context.width / 3.f, context.height / 3.f }; - rectangleList[0].body.velocity = Vector2 { 100.f, 250.f }; - rectangleList[0].body.rotation = 0.2f; - - rectangleList[1].load(&renderer, Vector4 { 35.f, 235.f, 35.f, 255.f }, 64.f, 96.f); - rectangleList[1].body.position = Vector2 { context.width / 3.f, context.height * (2.f / 3.f) }; - rectangleList[1].body.rotation = 1.3f; - - rectangleList[2].load(&renderer, Vector4 { 235.f, 35.f, 235.f, 255.f }, 64.f, 32.f); - rectangleList[2].body.position = Vector2 { context.width * (2.f / 3.f), context.height / 3.f }; - rectangleList[2].body.velocity = Vector2 { -100.f, 250.f }; - rectangleList[2].body.rotation = -0.5f; - - rectangleList[3].load(&renderer, Vector4 { 35.f, 235.f, 235.f, 255.f }, 8.f, 16.f); - rectangleList[3].body.position = Vector2 { context.width * (2.f / 3.f), context.height * (2.f / 3.f) }; - rectangleList[3].body.rotation = -3.23f; - - mainLoop.run(update); -} - -Vector2 getProjection(Vector2* vertices, Vector2 axis) { - float32 min = axis.dot(vertices[0]); - float32 max = min; - - for (int v = 1; v < 4; v++) { - float32 d = axis.dot(vertices[v]); - - if (d < min) { - min = d; - } else if (d > max) { - max = d; - } - } - - return Vector2 { min, max }; -} - -bool projectionsOverlap(Vector2 first, Vector2 second) { - return first.x <= second.y && second.x <= first.y; -} - -float32 getProjectionOverlap(Vector2 first, Vector2 second) { - float32 firstOverlap = fabs(first.x - second.y); - float32 secondOverlap = fabs(second.x - first.y); - return firstOverlap > secondOverlap ? secondOverlap : firstOverlap; -} - -const float32 EPSILON = 1.f; -IntersectionResult getIntersection(Rectangle* first, Rectangle* second) { - IntersectionResult ir; - - // For two rectangles to overlap, it means that at least one of the corners of one is inside of the other - Edge firstEdges[4]; - first->getEdges(firstEdges); - Vector2 firstPoints[4]; - first->getPoints(firstPoints); - - Edge secondEdges[4]; - second->getEdges(secondEdges); - Vector2 secondPoints[4]; - second->getPoints(secondPoints); - - float32 minOverlap = FLT_MAX; - Vector2 minOverlapAxis; - Edge* minOverlapEdge = NULL; - bool minOverlapWasFirstRect = false; - - for (int i = 0; i < 4; i++) { - Vector2 normal = firstEdges[i].normal; - - Vector2 firstProj = getProjection(firstPoints, normal); - Vector2 secondProj = getProjection(secondPoints, normal); - - if (!projectionsOverlap(firstProj, secondProj)) { - return ir; - } - - float32 overlap = getProjectionOverlap(firstProj, secondProj); - if (overlap < minOverlap) { - minOverlap = overlap; - minOverlapAxis = normal; - minOverlapEdge = &firstEdges[i]; - minOverlapWasFirstRect = true; - } - } - - for (int i = 0; i < 4; i++) { - Vector2 normal = secondEdges[i].normal; - - Vector2 firstProj = getProjection(firstPoints, normal); - Vector2 secondProj = getProjection(secondPoints, normal); - - if (!projectionsOverlap(firstProj, secondProj)) { - return ir; - } - - float32 overlap = getProjectionOverlap(firstProj, secondProj); - if (overlap < minOverlap) { - minOverlap = overlap; - minOverlapAxis = normal; - minOverlapEdge = &secondEdges[i]; - } - } - - ir.intersect = true; - ir.relativeVelocity = first->body.velocity - second->body.velocity; - ir.collisionNormal = minOverlapAxis; - - // Find the point of collision, this is kind of tricky, and it is just an approximation for now. - // At this point, we know that we intersected along the minOverlapAxis, but we do not know where - // that exactly happened. To remedy this will, we create two parallel lines: one at the top of the - // normal area, and one at the bottom. For point on both of the Rectangles, we will check: - // (1) if it is between these two planes - // (2) if, for that rectangle, it is the closest point to the original normal vector - // (3) or if it is equally distant from normal vector as another point (then this is a "flat" collision) - // - // The collision point MUST be between these two planes. We can then say the corner/face of the non-monoverlapAxis - // Rectangle is the collision point. This enables us to then solve for their respective points of application fairly - // easily. If the collision "point" is an entire face, we make the collision point be the center point. - // - - Vector2 closestPoint; - float32 minDistance = FLT_MAX; - - for (int p = 0; p < 4; p++) { - Vector2 point = minOverlapWasFirstRect ? secondPoints[p] : firstPoints[p]; - - float32 distFromPointToStart = (minOverlapEdge->start - point).length(); - float32 distFromPointToEnd = (minOverlapEdge->end - point).length(); - float32 potentialMin = MIN(distFromPointToStart, distFromPointToEnd); - - if (potentialMin < minDistance) { - closestPoint = point; - minDistance = potentialMin; - } - } - - ir.firstPointOfApplication = closestPoint - first->body.position; - ir.secondPointOfApplication = closestPoint - second->body.position;; - - return ir; -} - -void resolveCollision(Rigidbody* first, Rigidbody* second, IntersectionResult* ir) { - Vector2 relativeVelocity = ir->relativeVelocity; - Vector2 collisionNormal = ir->collisionNormal; - Vector2 firstPerp = ir->firstPointOfApplication.getPerp(); - Vector2 secondPerp = ir->secondPointOfApplication.getPerp(); - float32 firstPerpNorm = firstPerp.dot(collisionNormal); - float32 sndPerpNorm = secondPerp.dot(collisionNormal); - - float32 cofOfRestition = (first->cofOfRestition + second->cofOfRestition) / 2.f; - float32 numerator = (relativeVelocity * (-1 * (1.f + cofOfRestition))).dot(collisionNormal); - float32 linearDenomPart = collisionNormal.dot(collisionNormal * (1.f / first->mass + 1.f / second->mass)); - float32 rotationalDenomPart = (firstPerpNorm * firstPerpNorm) / first->momentOfInertia + (sndPerpNorm * sndPerpNorm) / second->momentOfInertia; - - float32 impulseMagnitude = numerator / (linearDenomPart + rotationalDenomPart); - first->velocity = first->velocity + (collisionNormal * (impulseMagnitude / first->mass)); - second->velocity = second->velocity - (collisionNormal * (impulseMagnitude / second->mass)); - - first->rotationalVelocity = first->rotationalVelocity + firstPerp.dot(collisionNormal * impulseMagnitude) / first->momentOfInertia; - second->rotationalVelocity = second->rotationalVelocity - secondPerp.dot(collisionNormal * impulseMagnitude) / second->momentOfInertia; -} - -void update(float32 deltaTimeSeconds, void* userData) { - // Update - for (int r = 0; r < 4; r++) { - rectangleList[r].update(deltaTimeSeconds); - } - - // Check collisions with other rectangles - for (int i = 0; i < 4; i++) { - Rectangle* first = &rectangleList[i]; - for (int j = i + 1; j < 4; j++) { - Rectangle* second = &rectangleList[j]; - - IntersectionResult ir = getIntersection(first, second); - if (!ir.intersect) { - continue; - } - - // Handle collison here - IntersectionResult irCopy = ir; - float32 copyDt = deltaTimeSeconds; - - do { - first->restorePreviousBody(); - second->restorePreviousBody(); - - ir = irCopy; - copyDt = copyDt /= 2.f; - - first->update(copyDt); - second->update(copyDt); - - irCopy = getIntersection(first, second); - - if (copyDt <= 0.f) { - printf("Error: Should not be happening.\n"); - break; - } - - } while (irCopy.intersect); - - printf("Found intersection at timestamp: %f\n", copyDt); - - resolveCollision(&first->body, &second->body, &ir); - float32 frameTimeRemaining = deltaTimeSeconds - copyDt; - - first->update(frameTimeRemaining); - second->update(frameTimeRemaining); - } - } - - // Check collisions with walls - for (int r = 0; r < 4; r++) { - Rectangle* rect = &rectangleList[r]; - if (rect->body.position.x <= 0.f) { - rect->body.velocity = rect->body.velocity - Vector2 { 1.f, 0.f } * (2 * (rect->body.velocity.dot(Vector2 { 1.f, 0.f }))); - } - if (rect->body.position.y <= 0.f) { - rect->body.velocity = rect->body.velocity - Vector2 { 0.f, 1.f } * (2 * (rect->body.velocity.dot(Vector2 { 0.f, 1.f }))); - } - if (rect->body.position.x >= 640.f) { - rect->body.velocity = rect->body.velocity - Vector2 { -1.f, 0.f } * (2 * (rect->body.velocity.dot(Vector2{ -1.f, 0.f }))); - } - if (rect->body.position.y >= 480.f) { - rect->body.velocity = rect->body.velocity - Vector2 { 0.f, -1.f } * (2 * (rect->body.velocity.dot(Vector2 { 0.f, -1.f }))) ; - } - } - - // Renderer - renderer.render(); - for (int r = 0; r < 4; r++) { - rectangleList[r].render(&renderer); - } -} - -void unload() { - mainLoop.stop(); - renderer.unload(); - for (int r = 0; r < 4; r++) { - rectangleList[r].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; -} -- cgit v1.2.1