summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/Header.h23
-rw-r--r--backend/Server/Server/Server.vcxproj1
-rw-r--r--backend/Server/Server/Server.vcxproj.filters3
-rw-r--r--backend/server.cpp39
-rw-r--r--frontend/2d_part_1.html126
-rw-r--r--frontend/2d_part_2.html71
-rw-r--r--frontend/2d_part_3.html60
-rw-r--r--frontend/_rigidbody/circle.js12
-rw-r--r--frontend/_rigidbody/pill.js0
-rw-r--r--frontend/_rigidbody/rigidbody_1.js211
-rw-r--r--frontend/_rigidbody/rigidbody_2.js260
-rw-r--r--frontend/_rigidbody/rigidbody_3.js158
-rw-r--r--frontend/_rigidbody/rigidbody_3a.js189
-rw-r--r--frontend/_rigidbody/rigidbody_3b.js192
-rw-r--r--frontend/dog-114-203766.pngbin8343 -> 0 bytes
-rw-r--r--frontend/dog-120-203766.pngbin8262 -> 0 bytes
-rw-r--r--frontend/dog-144-203766.pngbin9834 -> 0 bytes
-rw-r--r--frontend/dog-152-203766.pngbin8748 -> 0 bytes
-rw-r--r--frontend/dog-16-203766.pngbin969 -> 0 bytes
-rw-r--r--frontend/dog-24-203766.pngbin1203 -> 0 bytes
-rw-r--r--frontend/dog-32-203766.pngbin1742 -> 0 bytes
-rw-r--r--frontend/dog-48-203766.pngbin3026 -> 0 bytes
-rw-r--r--frontend/dog-512-203766.pngbin41072 -> 0 bytes
-rw-r--r--frontend/dog-57-203766.pngbin3686 -> 0 bytes
-rw-r--r--frontend/dog-64-203766.pngbin4111 -> 0 bytes
-rw-r--r--frontend/dog-72-203766.pngbin4493 -> 0 bytes
-rw-r--r--frontend/favicon.icobin32038 -> 0 bytes
-rw-r--r--frontend/favicon/favicon.icobin0 -> 32038 bytes
-rw-r--r--frontend/favicon/little-penguin-114-27563.pngbin0 -> 28726 bytes
-rw-r--r--frontend/favicon/little-penguin-120-27563.pngbin0 -> 27274 bytes
-rw-r--r--frontend/favicon/little-penguin-144-27563.pngbin0 -> 31335 bytes
-rw-r--r--frontend/favicon/little-penguin-152-27563.pngbin0 -> 25239 bytes
-rw-r--r--frontend/favicon/little-penguin-16-27563.pngbin0 -> 1600 bytes
-rw-r--r--frontend/favicon/little-penguin-24-27563.pngbin0 -> 3033 bytes
-rw-r--r--frontend/favicon/little-penguin-32-27563.pngbin0 -> 4649 bytes
-rw-r--r--frontend/favicon/little-penguin-48-27563.pngbin0 -> 8985 bytes
-rw-r--r--frontend/favicon/little-penguin-57-27563.pngbin0 -> 11380 bytes
-rw-r--r--frontend/favicon/little-penguin-64-27563.pngbin0 -> 13108 bytes
-rw-r--r--frontend/favicon/little-penguin-72-27563.pngbin0 -> 14528 bytes
-rw-r--r--frontend/index.css15
-rw-r--r--frontend/index.html59
-rw-r--r--frontend/index.js16
-rw-r--r--frontend/readme.txt26
-rw-r--r--frontend/rigidbody.html33
44 files changed, 843 insertions, 651 deletions
diff --git a/backend/Header.h b/backend/Header.h
deleted file mode 100644
index 5282066..0000000
--- a/backend/Header.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-#ifdef WIN32
-
-#include <Windows.h>
-
-#else
-// TODO: Support Linux threads
-#include <pthread.h>
-#endif
-
-struct ThreadInstance {
- DWORD mThreadId;
- HANDLE mThreadHandle;
-};
-
-bool initThreadInstance(ThreadInstance* instance) {
- instance->mThreadHandle = CreateThread(NULL, 0,, NULL, 0, NULL);
-}
-
-struct ThreadPool {
-
-}; \ No newline at end of file
diff --git a/backend/Server/Server/Server.vcxproj b/backend/Server/Server/Server.vcxproj
index 0e067f6..0e87860 100644
--- a/backend/Server/Server/Server.vcxproj
+++ b/backend/Server/Server/Server.vcxproj
@@ -142,7 +142,6 @@
<ClCompile Include="..\..\server.cpp" />
</ItemGroup>
<ItemGroup>
- <ClInclude Include="..\..\Header.h" />
<ClInclude Include="..\..\stringmanip.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
diff --git a/backend/Server/Server/Server.vcxproj.filters b/backend/Server/Server/Server.vcxproj.filters
index b507bf5..5026929 100644
--- a/backend/Server/Server/Server.vcxproj.filters
+++ b/backend/Server/Server/Server.vcxproj.filters
@@ -23,8 +23,5 @@
<ClInclude Include="..\..\stringmanip.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="..\..\Header.h">
- <Filter>Header Files</Filter>
- </ClInclude>
</ItemGroup>
</Project> \ No newline at end of file
diff --git a/backend/server.cpp b/backend/server.cpp
index a58eed1..ac8f9fb 100644
--- a/backend/server.cpp
+++ b/backend/server.cpp
@@ -143,17 +143,6 @@ struct HeaderParseResult {
HttpRequestError error = HttpRequestError_None;
};
-int fixNewLines(char* str, int strSize) {
- int removed = 0;
- for(int i = 0; i < strSize; i++) {
- if(str[i] == '\n') {
- str[i] = '\r\n';
- removed++;
- }
- }
-
- return removed;
-}
struct HeaderParser {
char buffer[4096];
@@ -275,15 +264,15 @@ void sendErrorMessage(SOCKET socket, HttpStatusCode status, const char* errorHtm
#define MAXBUFLEN 1000000
-int readFileToMemory(char* filepath, char source[MAXBUFLEN + 1]) {
+int readFileToMemory(char* filepath, char source[MAXBUFLEN + 1], bool isBinary) {
FILE* file;
- fopen_s(&file, filepath, "r+");
+ fopen_s(&file, filepath, isBinary ? "rb" : "r+");
if(file == NULL) {
printf("Failed to read the file\n");
return -1;
-
}
+
size_t newLen = fread(source, sizeof(char), MAXBUFLEN, file);
if ( ferror( file ) != 0 ) {
fputs("Error reading file", stderr);
@@ -295,19 +284,35 @@ int readFileToMemory(char* filepath, char source[MAXBUFLEN + 1]) {
}
+int fixNewLines(char* str, int strSize) {
+ int removed = 0;
+ for(int i = 0; i < strSize; i++) {
+ if(str[i] == '\n') {
+ str[i] = '\r\n';
+ removed++;
+ }
+ }
+
+ return removed;
+}
+
+
bool trySendFile(SOCKET clientSocket, char* filename) {
- FILE* file;
char filePath[128];
sprintf(filePath, "../../frontend%s", filename);
+ bool isBinary = false;
+ if (endsWith(filename, ".ico")) {
+ isBinary = true;
+ }
+
char source[MAXBUFLEN + 1];
- int fileSizeBytes = readFileToMemory(filePath, source);
+ int fileSizeBytes = readFileToMemory(filePath, source, isBinary);
if (fileSizeBytes <= 0) {
return false;
}
-
const char* contentType;
if (endsWith(filename, ".html")) {
contentType = "text/html";
diff --git a/frontend/2d_part_1.html b/frontend/2d_part_1.html
index 312611a..830f201 100644
--- a/frontend/2d_part_1.html
+++ b/frontend/2d_part_1.html
@@ -7,6 +7,7 @@
<link rel="stylesheet" href="/../index.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,300" rel="stylesheet" type="text/css">
<title>Physics for Games</title>
+ <link rel="shortcut icon" href="favicon/favicon.ico" type="image/x-icon">
<script src="_rigidbody/vec2.js"></script>
<script src="_rigidbody/mat4.js"></script>
@@ -26,68 +27,71 @@
<a href="2d_part_2.html">2D - Rotational Forces</a>
<a href="2d_part_3.html">2D - Collision Forces</a>
</nav>
- <section id="linear-forces">
- <h2>Part 1: Linear Forces</h2>
- <p>
- The first - and perhaps easiest - part of implementing any rigid body physics system is getting the entities in your scene to move in response to linear forces.
- With this implementation alone, you can achieve an interesting level of realism in your 2D (and even 3D) scene.
- </p>
- <p>
- Let's begin by recalling the relationships between acceleration, velocity, and position.
- </p>
- <p>
- Knowing all this, you should be able to understand the following source code fairly easily;
- <pre>
- <code>
-<span class="code_keyword">function</span> update(dtSeconds) {
- <span class="code_comment">// Add up the forces acting on the circle</span>
- <span class="code_keyword">const</span> GRAVITY = 9.8;
- <span class="code_keyword">const</span> lGravityForce = vec2(0, -1.0 * (lCircle.mass * <span class="code_constant">GRAVITY</span>));
- lCircle.force = addVec2(lCircle.force, lGravityForce);
-
- <span class="code_comment">// Figure out acceleration (a = F / m)</span>
- <span class="code_keyword">const</span> lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass);
-
- <span class="code_comment">// Calculate the new velocity: v = v0 + a * t</span>
- lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, dtSeconds));
-
- <span class="code_comment">// Update the position based on velocity: x = x0 + v * t</span>
- lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, dtSeconds));
-
- <span class="code_comment">// Update the model matrix accordingly</span>
- lCircle.model = translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0);
-
- <span class="code_comment">// Reset the force vector for the next update</span>
- lCircle.force = vec2()
-}
- </code>
- </pre>
- </p>
- <div id="rigidbody_1" class="opengl_canvas_container">
- <canvas width="640" height="480"></canvas>
- <div class="opengl_canvas_sidebar">
- <ul class="opengl_value_tracker">
- <li><b>Linear Force:</b><span id="rigidbody_1_force_field">N/A</span></li>
- <li><b>Linear Acceleration:</b><span id="rigidbody_1_acceleration_field">N/A</span></li>
- <li><b>Linear Velocity:</b><span id="rigidbody_1_velocity_field">N/A</span></li>
- <li><b>Linear Position:</b><span id="rigidbody_1_position_field">N/A</span></li>
- </ul>
- <form id="rigidbody_1_force_submit_button" style="text-align: right; padding: 0.5rem;">
- <div class="vec2_input_group">
- <label>Force Vector</label>
- <input class="vec2_x_input" type="number" placeholder="X (Default 0)"/>
- <input class="vec2_y_input" type="number" placeholder="Y (Default 5000 N)"/>
- </div>
- <input type="submit" value="Apply Force"></input>
- </form>
+ <section>
+ <article>
+ <h2>Part 1: Linear Forces</h2>
+ <p>
+ The first - and perhaps easiest - part of implementing any rigid body physics system is getting the entities in your scene to move in response to linear forces.
+ With this implementation alone, you can achieve an interesting level of realism in your 2D (and even 3D) scene.
+ </p>
+ <p>
+ Let's begin by recalling the relationships between acceleration, velocity, and position.
+ </p>
+ <p>
+ Knowing all this, you should be able to understand the following source code fairly easily;
+ <pre>
+ <code>
+ <span class="code_keyword">function</span> update(dtSeconds) {
+ <span class="code_comment">// Add up the forces acting on the circle</span>
+ <span class="code_keyword">const</span> GRAVITY = 9.8;
+ <span class="code_keyword">const</span> lGravityForce = vec2(0, -1.0 * (lCircle.mass * <span class="code_constant">GRAVITY</span>));
+ lCircle.force = addVec2(lCircle.force, lGravityForce);
+
+ <span class="code_comment">// Figure out acceleration (a = F / m)</span>
+ <span class="code_keyword">const</span> lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass);
+
+ <span class="code_comment">// Calculate the new velocity: v = v0 + a * t</span>
+ lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, dtSeconds));
+
+ <span class="code_comment">// Update the position based on velocity: x = x0 + v * t</span>
+ lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, dtSeconds));
+
+ <span class="code_comment">// Update the model matrix accordingly</span>
+ lCircle.model = translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0);
+
+ <span class="code_comment">// Reset the force vector for the next update</span>
+ lCircle.force = vec2()
+ }
+ </code>
+ </pre>
+ </p>
+ <div id="rigidbody_1" class="opengl_canvas_container">
+ <canvas width="640" height="480"></canvas>
+ <div class="opengl_canvas_sidebar">
+ <ul class="opengl_value_tracker">
+ <li><b>Linear Force:</b><span id="rigidbody_1_force_field">N/A</span></li>
+ <li><b>Linear Acceleration:</b><span id="rigidbody_1_acceleration_field">N/A</span></li>
+ <li><b>Linear Velocity:</b><span id="rigidbody_1_velocity_field">N/A</span></li>
+ <li><b>Linear Position:</b><span id="rigidbody_1_position_field">N/A</span></li>
+ </ul>
+ <form id="rigidbody_1_force_submit_button" style="text-align: right; padding: 0.5rem;">
+ <div class="vec2_input_group">
+ <label>Force Vector</label>
+ <input class="vec2_x_input" type="number" placeholder="X (Default 0)"/>
+ <input class="vec2_y_input" type="number" placeholder="Y (Default 5000 N)"/>
+ </div>
+ <input type="submit" value="Apply Force"></input>
+ </form>
+ </div>
+ <button class="play_button">
+ Play
+ </button>
+ <button class="stop_button">
+ Stop
+ </button>
</div>
- <button class="play_button">
- Play
- </button>
- <button class="stop_button">
- Stop
- </button>
- </div>
+ </article>
+ </section>
</main>
</body>
</html> \ No newline at end of file
diff --git a/frontend/2d_part_2.html b/frontend/2d_part_2.html
index 01a7767..845985c 100644
--- a/frontend/2d_part_2.html
+++ b/frontend/2d_part_2.html
@@ -7,6 +7,7 @@
<link rel="stylesheet" href="/../index.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,300" rel="stylesheet" type="text/css">
<title>Physics for Games</title>
+ <link rel="shortcut icon" href="favicon/favicon.ico" type="image/x-icon">
<script src="_rigidbody/vec2.js"></script>
<script src="_rigidbody/mat4.js"></script>
@@ -26,41 +27,43 @@
<a href="2d_part_2.html">2D - Rotational Forces</a>
<a href="2d_part_3.html">2D - Collision Forces</a>
</nav>
- <section id="rotational-forces">
- <h2>Part 2: Rotational Forces</h2>
- <p>
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
- </p>
- <div id="rigidbody_2" class="opengl_canvas_container">
- <canvas width="640" height="480"></canvas>
- <div class="opengl_canvas_sidebar">
- <ul class="opengl_value_tracker">
- <li><b>Angular Force:</b><span id="rigidbody_2_force_field">N/A</span></li>
- <li><b>Angular Acceleration:</b><span id="rigidbody_2_acceleration_field">N/A</span></li>
- <li><b>Angular Velocity:</b><span id="rigidbody_2_velocity_field">N/A</span></li>
- <li><b>Angular Position:</b><span id="rigidbody_2_position_field">N/A</span></li>
- </ul>
- <form id="rigidbody_2_force_submit_button" style="text-align: right; padding: 0.5rem;">
- <div id="rigidbody_2_force_input" class="vec2_input_group">
- <label>Force Vector</label>
- <input class="vec2_x_input" type="number" placeholder="X (Default 0)"/>
- <input class="vec2_y_input" type="number" placeholder="Y (Default 5000 N)"/>
- </div>
- <div id="rigidbody_2_position_input" class="vec2_input_group">
- <label>Point of Application (Unit Vector)</label>
- <input class="vec2_x_input" type="number" placeholder="X (Default 2 Root 2)"/>
- <input class="vec2_y_input" type="number" placeholder="Y (Default 2 Root 2)"/>
- </div>
- <input type="submit" value="Apply Force"></input>
- </form>
+ <section>
+ <article>
+ <h2>Part 2: Rotational Forces</h2>
+ <p>
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ </p>
+ <div id="rigidbody_2" class="opengl_canvas_container">
+ <canvas width="640" height="480"></canvas>
+ <div class="opengl_canvas_sidebar">
+ <ul class="opengl_value_tracker">
+ <li><b>Angular Force:</b><span id="rigidbody_2_force_field">N/A</span></li>
+ <li><b>Angular Acceleration:</b><span id="rigidbody_2_acceleration_field">N/A</span></li>
+ <li><b>Angular Velocity:</b><span id="rigidbody_2_velocity_field">N/A</span></li>
+ <li><b>Angular Position:</b><span id="rigidbody_2_position_field">N/A</span></li>
+ </ul>
+ <form id="rigidbody_2_force_submit_button" style="text-align: right; padding: 0.5rem;">
+ <div id="rigidbody_2_force_input" class="vec2_input_group">
+ <label>Force Vector</label>
+ <input class="vec2_x_input" type="number" placeholder="X (Default 0)"/>
+ <input class="vec2_y_input" type="number" placeholder="Y (Default 5000 N)"/>
+ </div>
+ <div id="rigidbody_2_position_input" class="vec2_input_group">
+ <label>Point of Application (Unit Vector)</label>
+ <input class="vec2_x_input" type="number" placeholder="X (Default 2 Root 2)"/>
+ <input class="vec2_y_input" type="number" placeholder="Y (Default 2 Root 2)"/>
+ </div>
+ <input type="submit" value="Apply Force"></input>
+ </form>
+ </div>
+ <button class="play_button">
+ Play
+ </button>
+ <button class="stop_button">
+ Stop
+ </button>
</div>
- <button class="play_button">
- Play
- </button>
- <button class="stop_button">
- Stop
- </button>
- </div>
+ </article>
</section>
</main>
</body>
diff --git a/frontend/2d_part_3.html b/frontend/2d_part_3.html
index ae00c9b..6e46843 100644
--- a/frontend/2d_part_3.html
+++ b/frontend/2d_part_3.html
@@ -7,13 +7,15 @@
<link rel="stylesheet" href="/../index.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,300" rel="stylesheet" type="text/css">
<title>Physics for Games</title>
+ <link rel="shortcut icon" href="favicon/favicon.ico" type="image/x-icon">
<script src="_rigidbody/vec2.js"></script>
<script src="_rigidbody/mat4.js"></script>
<script src="_rigidbody/shader.js"></script>
<script src="_rigidbody/circle.js"></script>
<script src="_rigidbody/program_common.js"></script>
- <script src="_rigidbody/rigidbody_3.js"></script>
+ <script src="_rigidbody/rigidbody_3a.js"></script>
+ <script src="_rigidbody/rigidbody_3b.js"></script>
</head>
<body>
<header>
@@ -26,26 +28,46 @@
<a href="2d_part_2.html">2D - Rotational Forces</a>
<a href="2d_part_3.html">2D - Collision Forces</a>
</nav>
- <section id="collisions">
- <h2>Part 3: Collisions</h2>
- <p>
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
- </p>
- <div id="rigidbody_3" class="opengl_canvas_container">
- <canvas width="640" height="480"></canvas>
- <div class="opengl_canvas_sidebar">
- <div class="slider_container">
- <label for="time_step_slider">Time Step</label>
- <input type="range" min="0.1" max="1.0" value="1.0" step="0.1" class="slider" id="time_step_slider">
+ <section>
+ <article>
+ <h2>Part 3: Collisions</h2>
+ <p>
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ </p>
+ <div id="rigidbody_3a" class="opengl_canvas_container">
+ <canvas width="640" height="480"></canvas>
+ <div class="opengl_canvas_sidebar">
+ <div class="slider_container">
+ <label for="time_step_slider">Time Step</label>
+ <input type="range" min="0.1" max="1.0" value="1.0" step="0.1" class="slider" id="time_step_slider">
+ </div>
</div>
+ <button class="play_button">
+ Play
+ </button>
+ <button class="stop_button">
+ Stop
+ </button>
</div>
- <button class="play_button">
- Play
- </button>
- <button class="stop_button">
- Stop
- </button>
- </div>
+ </article>
+ <article>
+ <h2>Fun Example: Plinko Game</h2>
+ <p>
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+ </p>
+ <div id="rigidbody_3b" class="opengl_canvas_container">
+ <canvas width="640" height="480"></canvas>
+ <div class="opengl_canvas_sidebar">
+
+ </div>
+ <button class="play_button">
+ Play
+ </button>
+ <button class="stop_button">
+ Stop
+ </button>
+ </div>
+ </article>
</section>
</main>
</body>
diff --git a/frontend/_rigidbody/circle.js b/frontend/_rigidbody/circle.js
index 35044e3..1cec7ce 100644
--- a/frontend/_rigidbody/circle.js
+++ b/frontend/_rigidbody/circle.js
@@ -1,3 +1,6 @@
+/// <reference path="mat4.js" />
+/// <reference path="vec2.js" />
+
const BYTES_PER_FLOAT = 4;
/**
@@ -42,13 +45,14 @@ function circle(pGl, pRadius, pSegments, pColorList, pInitialPosition, pMass) {
vertexCount: vertexCount,
prevPos: vec2(),
position: pInitialPosition || vec2(),
+ prevVelocity: vec2(),
velocity: vec2(),
force: vec2(),
torque: 0,
- mass: pMass || 1,
+ mass: pMass === undefined ? 1 : pMass,
rotationVelocity: 0,
rotationRadians: 0,
- model: mat4(),
+ model: translateMatrix(mat4(), pInitialPosition ? pInitialPosition.x : 0, pInitialPosition ? pInitialPosition.y : 0, 0),
radius: pRadius
};
}
@@ -106,4 +110,8 @@ function getIntersectionDataForCircles(pFirst, pSecond) {
firstPointOfApplication: subVec2(lMedianIntersectingPoint, pFirst.position),
secondPointOfApplication: subVec2(lMedianIntersectingPoint, pSecond.position)
}
+}
+
+function freeCircle(pGl, pCircle) {
+ pGl.deleteBuffer(pCircle.buffer);
} \ No newline at end of file
diff --git a/frontend/_rigidbody/pill.js b/frontend/_rigidbody/pill.js
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/frontend/_rigidbody/pill.js
diff --git a/frontend/_rigidbody/rigidbody_1.js b/frontend/_rigidbody/rigidbody_1.js
index c5e4f0a..697822d 100644
--- a/frontend/_rigidbody/rigidbody_1.js
+++ b/frontend/_rigidbody/rigidbody_1.js
@@ -5,110 +5,113 @@
/// <reference path="circle.js" />
/// <reference path="program_common.js" />
-function main() {
- // Define Constants
- const CIRCLE_RADIUS = 16;
- const GRAVITY = 9.8;
-
- // Retrieve context
- const lProgramContext = getContext('#rigidbody_1');
-
- if (lProgramContext.gl === null) {
- console.error('Unable to initialize WebGL. Your browser or machine may not support it.');
- return;
- }
-
- lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
- lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
-
- function run() {
- console.log('Running Rigid Body 1');
- lProgramContext.load().then(function(pProgramInfo) {
- const lCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [{ x: 0.3, y: 0.3, z: 0.3, w: 1 }], vec2(lProgramContext.width / 2.0, lProgramContext.height / 2.0));
-
- function update(pDeltaTimeSeconds) {
- // Physics updates
- const lGravityForce = vec2(0, -1.0 * (lCircle.mass * GRAVITY));
-
- // Add up the forces acting on the circle
- lCircle.force = addVec2(lCircle.force, lGravityForce);
-
- // Figure out acceleration (a = F / m)
- const lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass);
-
- // Calculate the new velocity: v = v0 + a * t
- lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds));
-
- // Update the position based on velocity: x = x0 + v * t
- lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, pDeltaTimeSeconds));
-
- // Update the model matrix accordingly
- lCircle.model = translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0);
-
- // Report the current state to the frontend
- $('#rigidbody_1_force_field').text(vec2str(lCircle.force));
- $('#rigidbody_1_acceleration_field').text(vec2str(lCurrentAcceleration));
- $('#rigidbody_1_velocity_field').text(vec2str(lCircle.velocity));
- $('#rigidbody_1_position_field').text(vec2str(lCircle.position));
-
- // Reset the circle's force vector
- lCircle.force = vec2();
-
- // Render Code only
- lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
- lProgramContext.gl.clearDepth(1.0); // Clear everything
- lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST); // Enable depth testing
- lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL); // Near things obscure far things
- lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT);
-
- lProgramContext.gl.useProgram(pProgramInfo.program);
- lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective);
- lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.model, false, lCircle.model);
-
- renderCircle(lProgramContext.gl, pProgramInfo, lCircle);
- }
-
- function addForce(ev) {
- ev.preventDefault();
- ev.stopPropagation();
-
- let lXValue = $(this).find('.vec2_x_input').val(),
- lYValue = $(this).find('.vec2_y_input').val();
-
- if (lXValue.length === 0) {
- lXValue = 0;
+(function() {
+
+ function main() {
+ // Define Constants
+ const CIRCLE_RADIUS = 16;
+ const GRAVITY = 9.8;
+
+ // Retrieve context
+ const lProgramContext = getContext('#rigidbody_1');
+
+ if (lProgramContext.gl === null) {
+ console.error('Unable to initialize WebGL. Your browser or machine may not support it.');
+ return;
+ }
+
+ lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
+
+ function run() {
+ console.log('Running Rigid Body 1');
+ lProgramContext.load().then(function(pProgramInfo) {
+ const lCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [{ x: 0.3, y: 0.3, z: 0.3, w: 1 }], vec2(lProgramContext.width / 2.0, lProgramContext.height / 2.0));
+
+ function update(pDeltaTimeSeconds) {
+ // Physics updates
+ const lGravityForce = vec2(0, -1.0 * (lCircle.mass * GRAVITY));
+
+ // Add up the forces acting on the circle
+ lCircle.force = addVec2(lCircle.force, lGravityForce);
+
+ // Figure out acceleration (a = F / m)
+ const lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass);
+
+ // Calculate the new velocity: v = v0 + a * t
+ lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds));
+
+ // Update the position based on velocity: x = x0 + v * t
+ lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, pDeltaTimeSeconds));
+
+ // Update the model matrix accordingly
+ lCircle.model = translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0);
+
+ // Report the current state to the frontend
+ $('#rigidbody_1_force_field').text(vec2str(lCircle.force));
+ $('#rigidbody_1_acceleration_field').text(vec2str(lCurrentAcceleration));
+ $('#rigidbody_1_velocity_field').text(vec2str(lCircle.velocity));
+ $('#rigidbody_1_position_field').text(vec2str(lCircle.position));
+
+ // Reset the circle's force vector
+ lCircle.force = vec2();
+
+ // Render Code only
+ lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
+ lProgramContext.gl.clearDepth(1.0); // Clear everything
+ lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST); // Enable depth testing
+ lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL); // Near things obscure far things
+ lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT);
+
+ lProgramContext.gl.useProgram(pProgramInfo.program);
+ lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective);
+ lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.model, false, lCircle.model);
+
+ renderCircle(lProgramContext.gl, pProgramInfo, lCircle);
}
-
- if (lYValue.length === 0) {
- lYValue = 5000;
+
+ function addForce(ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+
+ let lXValue = $(this).find('.vec2_x_input').val(),
+ lYValue = $(this).find('.vec2_y_input').val();
+
+ if (lXValue.length === 0) {
+ lXValue = 0;
+ }
+
+ if (lYValue.length === 0) {
+ lYValue = 5000;
+ }
+
+ console.log('Applying force: ' + lXValue + ', ' + lYValue);
+ lCircle.force = addVec2(lCircle.force, vec2(Number(lXValue), Number(lYValue)));
}
-
- console.log('Applying force: ' + lXValue + ', ' + lYValue);
- lCircle.force = addVec2(lCircle.force, vec2(Number(lXValue), Number(lYValue)));
- }
-
- function cleanup() {
- lProgramContext.gl.deleteBuffer(lCircle.buffer);
- lProgramContext.gl.deleteProgram(pProgramInfo.program);
- lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
- lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
- }
-
- function reset() {
- lExitRequestFunc();
- lProgramContext.reset();
- $('#rigidbody_1_force_submit_button').unbind('submit').submit(false);
- }
-
- const lExitRequestFunc = requestUpdateLoop(update, cleanup);
- lProgramContext.stopButton.on('click', reset);
- $('#rigidbody_1_force_submit_button').submit(addForce);
- });
+
+ function cleanup() {
+ lProgramContext.gl.deleteBuffer(lCircle.buffer);
+ lProgramContext.gl.deleteProgram(pProgramInfo.program);
+ lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
+ }
+
+ function reset() {
+ lExitRequestFunc();
+ lProgramContext.reset();
+ $('#rigidbody_1_force_submit_button').unbind('submit').submit(false);
+ }
+
+ const lExitRequestFunc = requestUpdateLoop(update, cleanup);
+ lProgramContext.stopButton.on('click', reset);
+ $('#rigidbody_1_force_submit_button').submit(addForce);
+ });
+ }
+
+ lProgramContext.playButton.on('click', run);
+ $('#rigidbody_1_force_submit_button').submit(false);
+
}
-
- lProgramContext.playButton.on('click', run);
- $('#rigidbody_1_force_submit_button').submit(false);
-
-}
-
-$(document).ready(main); \ No newline at end of file
+
+ $(document).ready(main);
+})() \ No newline at end of file
diff --git a/frontend/_rigidbody/rigidbody_2.js b/frontend/_rigidbody/rigidbody_2.js
index 1c6b79f..c878c1a 100644
--- a/frontend/_rigidbody/rigidbody_2.js
+++ b/frontend/_rigidbody/rigidbody_2.js
@@ -4,140 +4,142 @@
/// <reference path="shader.js" />
/// <reference path="circle.js" />
-function main() {
- // Define Constants
- const CIRCLE_RADIUS = 16;
- const GRAVITY = 9.8;
-
- // Retrieve context
- const lProgramContext = getContext('#rigidbody_2');
-
- if (lProgramContext.gl === null) {
- console.error('Unable to initialize WebGL. Your browser or machine may not support it.');
- return;
- }
-
- lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
- lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
-
- function run() {
- console.log('Running Rigid Body 2');
- lProgramContext.load().then(function(pProgramInfo) {
- const lCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [
- { x: 1, y: 1, z: 0, w: 1 },
- { x: 1, y: 0, z: 1, w: 1 },
- { x: 0, y: 1, z: 1, w: 1 },
- { x: 0, y: 1, z: 0, w: 1 }
- ], vec2(lProgramContext.width / 2.0, lProgramContext.height / 2.0));
-
- function update(pDeltaTimeSeconds) {
- // Same physics updates from part 1
- applyForce(vec2(0, -1.0 * (lCircle.mass * GRAVITY)));
- const lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass);
- lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds));
- lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, pDeltaTimeSeconds));
- lCircle.force = vec2();
-
- // Angular code starts here
-
- // Retrieve the moment of inertia for our shape (Ours is a circle by default)
- const lMomentOfInertia = getMomentOfInertia(lCircle);
-
- // Calculate the angular acceperation (omega = T / I)
- const lAngularAcceleration = lCircle.torque / lMomentOfInertia;
-
- // Calculate the rotation in radians
- lCircle.rotationVelocity += lAngularAcceleration * pDeltaTimeSeconds;
- lCircle.rotationRadians += lCircle.rotationVelocity * pDeltaTimeSeconds;
- lCircle.torque = 0;
-
- // Calculate the model as previously, but this time, also rotate it
- lCircle.model = rotateMatrix2d(translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0), lCircle.rotationRadians);
-
- // Render Code only
- lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
- lProgramContext.gl.clearDepth(1.0);
- lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST);
- lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL);
- lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT);
-
- lProgramContext.gl.useProgram(pProgramInfo.program);
- lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective);
- lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.model, false, lCircle.model);
-
- renderCircle(lProgramContext.gl, pProgramInfo, lCircle);
- }
-
- const TORQUE_MULTIPLIER = 100.0; // TODO: This may be unncessary
-
- function applyForce(pForceVector, pPointOfApplication) {
- if (pPointOfApplication !== undefined) {
- const lOriginToPointOfApp = subVec2(vec2(), pPointOfApplication), // The point of application is relative to the model (i.e. the center of the circle, not the scene)
- lPerpVec = vec2(-lOriginToPointOfApp.y, lOriginToPointOfApp.x); // Retrieve the perpendicular vector
+(function() {
+ function main() {
+ // Define Constants
+ const CIRCLE_RADIUS = 16;
+ const GRAVITY = 9.8;
- // Calculate the torque from the perp dot (T = r_perp . F)
- lCircle.torque += TORQUE_MULTIPLIER * dot2(lPerpVec, pForceVector);
- }
-
- lCircle.force = addVec2(lCircle.force, pForceVector);
- }
-
- function cleanup() {
- lProgramContext.gl.deleteBuffer(lCircle.buffer);
- lProgramContext.gl.deleteProgram(pProgramInfo.program);
- lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
- lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
- }
-
- function reset() {
- lExitRequestFunc();
- lProgramContext.reset();
- $('#rigidbody_2_force_submit_button').unbind('submit').submit(false);
- }
-
- const lExitRequestFunc = requestUpdateLoop(update, cleanup);
- lProgramContext.stopButton.on('click', reset);
- $('#rigidbody_2_force_submit_button').submit(function(pEv) {
- pEv.preventDefault();
- pEv.stopPropagation();
-
- // Read in the force vector from the form
- const lForceGroup = $('#rigidbody_2_force_input'),
- lPositionGroup = $('#rigidbody_2_position_input');
-
- let lForceVectorX = lForceGroup.find('.vec2_x_input').val(),
- lForceVectorY = lForceGroup.find('.vec2_y_input').val();
-
- if (lForceVectorX.length === 0) {
- lForceVectorX = 0;
+ // Retrieve context
+ const lProgramContext = getContext('#rigidbody_2');
+
+ if (lProgramContext.gl === null) {
+ console.error('Unable to initialize WebGL. Your browser or machine may not support it.');
+ return;
+ }
+
+ lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
+
+ function run() {
+ console.log('Running Rigid Body 2');
+ lProgramContext.load().then(function(pProgramInfo) {
+ const lCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [
+ { x: 1, y: 1, z: 0, w: 1 },
+ { x: 1, y: 0, z: 1, w: 1 },
+ { x: 0, y: 1, z: 1, w: 1 },
+ { x: 0, y: 1, z: 0, w: 1 }
+ ], vec2(lProgramContext.width / 2.0, lProgramContext.height / 2.0));
+
+ function update(pDeltaTimeSeconds) {
+ // Same physics updates from part 1
+ applyForce(vec2(0, -1.0 * (lCircle.mass * GRAVITY)));
+ const lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass);
+ lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds));
+ lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, pDeltaTimeSeconds));
+ lCircle.force = vec2();
+
+ // Angular code starts here
+
+ // Retrieve the moment of inertia for our shape (Ours is a circle by default)
+ const lMomentOfInertia = getMomentOfInertia(lCircle);
+
+ // Calculate the angular acceperation (omega = T / I)
+ const lAngularAcceleration = lCircle.torque / lMomentOfInertia;
+
+ // Calculate the rotation in radians
+ lCircle.rotationVelocity += lAngularAcceleration * pDeltaTimeSeconds;
+ lCircle.rotationRadians += lCircle.rotationVelocity * pDeltaTimeSeconds;
+ lCircle.torque = 0;
+
+ // Calculate the model as previously, but this time, also rotate it
+ lCircle.model = rotateMatrix2d(translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0), lCircle.rotationRadians);
+
+ // Render Code only
+ lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ lProgramContext.gl.clearDepth(1.0);
+ lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST);
+ lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL);
+ lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT);
+
+ lProgramContext.gl.useProgram(pProgramInfo.program);
+ lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective);
+ lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.model, false, lCircle.model);
+
+ renderCircle(lProgramContext.gl, pProgramInfo, lCircle);
}
-
- if (lForceVectorY.length === 0) {
- lForceVectorY = 5000;
+
+ const TORQUE_MULTIPLIER = 100.0; // TODO: This may be unncessary
+
+ function applyForce(pForceVector, pPointOfApplication) {
+ if (pPointOfApplication !== undefined) {
+ const lOriginToPointOfApp = subVec2(vec2(), pPointOfApplication), // The point of application is relative to the model (i.e. the center of the circle, not the scene)
+ lPerpVec = vec2(-lOriginToPointOfApp.y, lOriginToPointOfApp.x); // Retrieve the perpendicular vector
+
+ // Calculate the torque from the perp dot (T = r_perp . F)
+ lCircle.torque += TORQUE_MULTIPLIER * dot2(lPerpVec, pForceVector);
+ }
+
+ lCircle.force = addVec2(lCircle.force, pForceVector);
}
-
- // Read in the point of application vector from the form
- let lPositionGroupX = lPositionGroup.find('.vec2_x_input').val(),
- lPositionGroupY = lPositionGroup.find('.vec2_y_input').val();
-
- if (lPositionGroupX.length === 0) {
- lPositionGroupX = -Math.sqrt(2) / 2;
+
+ function cleanup() {
+ lProgramContext.gl.deleteBuffer(lCircle.buffer);
+ lProgramContext.gl.deleteProgram(pProgramInfo.program);
+ lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
}
-
- if (lPositionGroupY.length === 0) {
- lPositionGroupY = -Math.sqrt(2) / 2;
+
+ function reset() {
+ lExitRequestFunc();
+ lProgramContext.reset();
+ $('#rigidbody_2_force_submit_button').unbind('submit').submit(false);
}
-
- const lForceVector = vec2(Number(lForceVectorX), Number(lForceVectorY));
- const lPointOfApplication = scaleVec2(normalize2(vec2(Number(lPositionGroupX), Number(lPositionGroupY))), lCircle.radius);
-
- applyForce(lForceVector, lPointOfApplication);
+
+ const lExitRequestFunc = requestUpdateLoop(update, cleanup);
+ lProgramContext.stopButton.on('click', reset);
+ $('#rigidbody_2_force_submit_button').submit(function(pEv) {
+ pEv.preventDefault();
+ pEv.stopPropagation();
+
+ // Read in the force vector from the form
+ const lForceGroup = $('#rigidbody_2_force_input'),
+ lPositionGroup = $('#rigidbody_2_position_input');
+
+ let lForceVectorX = lForceGroup.find('.vec2_x_input').val(),
+ lForceVectorY = lForceGroup.find('.vec2_y_input').val();
+
+ if (lForceVectorX.length === 0) {
+ lForceVectorX = 0;
+ }
+
+ if (lForceVectorY.length === 0) {
+ lForceVectorY = 5000;
+ }
+
+ // Read in the point of application vector from the form
+ let lPositionGroupX = lPositionGroup.find('.vec2_x_input').val(),
+ lPositionGroupY = lPositionGroup.find('.vec2_y_input').val();
+
+ if (lPositionGroupX.length === 0) {
+ lPositionGroupX = -Math.sqrt(2) / 2;
+ }
+
+ if (lPositionGroupY.length === 0) {
+ lPositionGroupY = -Math.sqrt(2) / 2;
+ }
+
+ const lForceVector = vec2(Number(lForceVectorX), Number(lForceVectorY));
+ const lPointOfApplication = scaleVec2(normalize2(vec2(Number(lPositionGroupX), Number(lPositionGroupY))), lCircle.radius);
+
+ applyForce(lForceVector, lPointOfApplication);
+ });
});
- });
+ }
+
+ lProgramContext.playButton.on('click', run);
+ $('#rigidbody_2_force_submit_button').submit(false);
}
- lProgramContext.playButton.on('click', run);
- $('#rigidbody_2_force_submit_button').submit(false);
-}
-
-$(document).ready(main); \ No newline at end of file
+ $(document).ready(main);
+})() \ No newline at end of file
diff --git a/frontend/_rigidbody/rigidbody_3.js b/frontend/_rigidbody/rigidbody_3.js
deleted file mode 100644
index 0316268..0000000
--- a/frontend/_rigidbody/rigidbody_3.js
+++ /dev/null
@@ -1,158 +0,0 @@
-/// <reference path="../scripts/jquery-3.5.1.min.js"/>
-/// <reference path="vec2.js" />
-/// <reference path="mat4.js" />
-/// <reference path="shader.js" />
-/// <reference path="circle.js" />
-
-function main() {
- // Define Constants
- const CIRCLE_RADIUS = 16;
- const GRAVITY = 9.8;
- const COF_OF_RESTITUITION = 0.7;
-
- // Retrieve context
- const lProgramContext = getContext('#rigidbody_3');
-
- if (lProgramContext.gl === null) {
- console.error('Unable to initialize WebGL. Your browser or machine may not support it.');
- return;
- }
-
- lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
- lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
-
- function run() {
- console.log('Running Rigid Body 3');
- lProgramContext.load().then(function(pProgramInfo) {
- // Circile initialization
- const horizontalCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [
- { x: 1, y: 1, z: 0, w: 1 },
- { x: 1, y: 0, z: 1, w: 1 },
- { x: 0, y: 1, z: 1, w: 1 },
- { x: 0, y: 1, z: 0, w: 1 }
- ], vec2(400, lProgramContext.height / 2.0));
-
- const verticalCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [
- { x: 1, y: 0, z: 0, w: 1 },
- { x: 0, y: 1, z: 0, w: 1 },
- { x: 0, y: 0, z: 1, w: 1 }
- ], vec2(lProgramContext.width / 2.0, lProgramContext.height / 2.0 + 100));
-
- horizontalCircle.velocity = vec2(-100, 0);
- verticalCircle.velocity = vec2(0, -100);
-
- lTimeStepScale = $('#time_step_slider').val();
-
- /**
- * Run the update method of a single circle
- *
- * @param {circle} pCircle
- * @param {number} pDeltaTimeSeconds
- */
- function updateCircle(pCircle, pDeltaTimeSeconds) {
- // Same physics updates from part 1
- applyForce(pCircle, vec2(0, -1.0 * (pCircle.mass * GRAVITY)));
- const lCurrentAcceleration = scaleVec2(pCircle.force, 1.0 / pCircle.mass);
- pCircle.velocity = addVec2(pCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds));
- pCircle.prevPos = { ...pCircle.position };
- pCircle.position = addVec2(pCircle.position, scaleVec2(pCircle.velocity, pDeltaTimeSeconds));
- pCircle.force = vec2();
-
- // Same physics updates from part 2
- const lMomentOfInertia = getMomentOfInertia(pCircle);
- const lAngularAcceleration = pCircle.torque / lMomentOfInertia;
- pCircle.rotationVelocity += lAngularAcceleration * pDeltaTimeSeconds;
- pCircle.rotationRadians += pCircle.rotationVelocity * pDeltaTimeSeconds;
- pCircle.torque = 0;
-
- pCircle.model = rotateMatrix2d(translateMatrix(mat4(), pCircle.position.x, pCircle.position.y, 0), pCircle.rotationRadians);
- }
-
- function update(pDeltaTimeSeconds) {
- pDeltaTimeSeconds = pDeltaTimeSeconds * lTimeStepScale;
- updateCircle(horizontalCircle, pDeltaTimeSeconds);
- updateCircle(verticalCircle, pDeltaTimeSeconds);
- collision();
- render();
- }
-
- function collision() {
- if (!doCirclesIntersect(horizontalCircle, verticalCircle)) {
- return false;
- }
-
- const lIntersectionResult = getIntersectionDataForCircles(horizontalCircle, verticalCircle);
-
- console.log('We have a collision');
- const lRelativeVelocity = lIntersectionResult.relativeVelocity,
- lCollisionNormal = lIntersectionResult.collisionNormal,
- lFirstPerp = getPerp2(lIntersectionResult.firstPointOfApplication),
- lSecondPerp = getPerp2(lIntersectionResult.secondPointOfApplication);
-
- console.log(lIntersectionResult);
-
- const lNumerator = dot2(scaleVec2(lRelativeVelocity, -(1.0 + COF_OF_RESTITUITION)), lCollisionNormal);
- const lLinearDenomPart = dot2(lCollisionNormal, (scaleVec2(lCollisionNormal, 1 / horizontalCircle.mass + 1 / verticalCircle.mass)));
- const lRotationalDenomPart = (Math.pow(dot2(lFirstPerp, lCollisionNormal), 2) / getMomentOfInertia(horizontalCircle))
- + (Math.pow(dot2(lSecondPerp, lCollisionNormal), 2) / getMomentOfInertia(verticalCircle))
-
- const lImpulseMagnitude = lNumerator / (lLinearDenomPart + lRotationalDenomPart);
-
- horizontalCircle.velocity = addVec2(horizontalCircle.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / horizontalCircle.mass));
- verticalCircle.velocity = subVec2(verticalCircle.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / verticalCircle.mass));
-
- horizontalCircle.rotationVelocity = horizontalCircle.rotationVelocity + dot2(lFirstPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / getMomentOfInertia(horizontalCircle);
- verticalCircle.rotationVelocity = verticalCircle.rotationVelocity - dot2(lSecondPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / getMomentOfInertia(verticalCircle);
-
- return true;
- }
-
- function render() {
- lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
- lProgramContext.gl.clearDepth(1.0);
- lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST);
- lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL);
- lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT);
- lProgramContext.gl.useProgram(pProgramInfo.program);
- lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective);
-
- renderCircle(lProgramContext.gl, pProgramInfo, horizontalCircle);
- renderCircle(lProgramContext.gl, pProgramInfo, verticalCircle);
- }
-
- const TORQUE_MULTIPLIER = 100.0; // TODO: This may be unncessary
- function applyForce(pCircle, pForceVector, pPointOfApplication) {
- if (pPointOfApplication !== undefined) {
- const lOriginToPointOfApp = subVec2(vec2(), pPointOfApplication),
- lPerpVec = vec2(-lOriginToPointOfApp.y, lOriginToPointOfApp.x);
-
- pCircle.torque += TORQUE_MULTIPLIER * dot2(lPerpVec, pForceVector);
- }
-
- pCircle.force = addVec2(pCircle.force, pForceVector);
- }
-
- function cleanup() {
- lProgramContext.gl.deleteBuffer(horizontalCircle.buffer);
- lProgramContext.gl.deleteBuffer(verticalCircle.buffer);
- lProgramContext.gl.deleteProgram(pProgramInfo.program);
- lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
- lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
- }
-
- function reset() {
- lExitRequestFunc();
- lProgramContext.reset();
- $('#time_step_slider').unbind('change');
- }
-
- const lExitRequestFunc = requestUpdateLoop(update, cleanup);
- lProgramContext.stopButton.on('click', reset);
- $('#time_step_slider').on('change', function() { lTimeStepScale = $(this).val(); });
- });
- }
-
- lProgramContext.playButton.on('click', run);
-}
-
-$(document).ready(main); \ No newline at end of file
diff --git a/frontend/_rigidbody/rigidbody_3a.js b/frontend/_rigidbody/rigidbody_3a.js
new file mode 100644
index 0000000..74d309b
--- /dev/null
+++ b/frontend/_rigidbody/rigidbody_3a.js
@@ -0,0 +1,189 @@
+/// <reference path="../scripts/jquery-3.5.1.min.js"/>
+/// <reference path="vec2.js" />
+/// <reference path="mat4.js" />
+/// <reference path="shader.js" />
+/// <reference path="circle.js" />
+
+(function() {
+ function main() {
+ // Define Constants
+ const CIRCLE_RADIUS = 16;
+ const GRAVITY = 9.8;
+ const COF_OF_RESTITUITION = 0.7;
+
+ // Retrieve context
+ const lProgramContext = getContext('#rigidbody_3a');
+
+ if (lProgramContext.gl === null) {
+ console.error('Unable to initialize WebGL. Your browser or machine may not support it.');
+ return;
+ }
+
+ lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
+
+ function run() {
+ console.log('Running Rigid Body 3a');
+ lProgramContext.load().then(function(pProgramInfo) {
+ // Circile initialization
+ const horizontalCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [
+ { x: 1, y: 1, z: 0, w: 1 },
+ { x: 1, y: 0, z: 1, w: 1 },
+ { x: 0, y: 1, z: 1, w: 1 },
+ { x: 0, y: 1, z: 0, w: 1 }
+ ], vec2(400, lProgramContext.height / 2.0));
+
+ const verticalCircle = circle(lProgramContext.gl, CIRCLE_RADIUS, 30, [
+ { x: 1, y: 0, z: 0, w: 1 },
+ { x: 0, y: 1, z: 0, w: 1 },
+ { x: 0, y: 0, z: 1, w: 1 }
+ ], vec2(lProgramContext.width / 2.0, lProgramContext.height / 2.0 + 100));
+
+ horizontalCircle.velocity = vec2(-100, 0);
+ verticalCircle.velocity = vec2(0, -100);
+
+ lTimeStepScale = $('#time_step_slider').val();
+
+ /**
+ * Run the update method of a single circle
+ *
+ * @param {circle} pCircle
+ * @param {number} pDeltaTimeSeconds
+ */
+ function updateCircle(pCircle, pDeltaTimeSeconds) {
+ // Same physics updates from part 1
+ applyForce(pCircle, vec2(0, -1.0 * (pCircle.mass * GRAVITY)));
+ const lCurrentAcceleration = scaleVec2(pCircle.force, 1.0 / pCircle.mass);
+ pCircle.prevVelocity = pCircle.velocity;
+ pCircle.velocity = addVec2(pCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds));
+ pCircle.prevPos = { ...pCircle.position };
+ pCircle.position = addVec2(pCircle.position, scaleVec2(pCircle.velocity, pDeltaTimeSeconds));
+ pCircle.force = vec2();
+
+ // Same physics updates from part 2
+ const lMomentOfInertia = getMomentOfInertia(pCircle);
+ const lAngularAcceleration = pCircle.torque / lMomentOfInertia;
+ pCircle.rotationVelocity += lAngularAcceleration * pDeltaTimeSeconds;
+ pCircle.rotationRadians += pCircle.rotationVelocity * pDeltaTimeSeconds;
+ pCircle.torque = 0;
+
+ pCircle.model = rotateMatrix2d(translateMatrix(mat4(), pCircle.position.x, pCircle.position.y, 0), pCircle.rotationRadians);
+ }
+
+ function update(pDeltaTimeSeconds) {
+ pDeltaTimeSeconds = pDeltaTimeSeconds * lTimeStepScale;
+ updateCircle(horizontalCircle, pDeltaTimeSeconds);
+ updateCircle(verticalCircle, pDeltaTimeSeconds);
+ collision(pDeltaTimeSeconds);
+ render();
+ }
+
+ function collision(pDeltaTimeSeconds) {
+ if (!doCirclesIntersect(horizontalCircle, verticalCircle)) {
+ return false;
+ }
+
+ // We have an intersection! Let's try and figure out precisely when that happened.
+ let lSubdividedDeltaTime = pDeltaTimeSeconds;
+ let lSubdivideHorizontalBall = undefined,
+ lSubdivideVerticalBall = undefined;
+
+ do {
+ lSubdivideHorizontalBall = JSON.parse(JSON.stringify(horizontalCircle));
+ lSubdivideHorizontalBall.position = {...horizontalCircle.prevPos};
+ lSubdivideHorizontalBall.velocity = {...horizontalCircle.prevVelocity};
+
+ lSubdivideVerticalBall = JSON.parse(JSON.stringify(verticalCircle));
+ lSubdivideVerticalBall.position = {...verticalCircle.prevPos};
+ lSubdivideVerticalBall.velocity = {...verticalCircle.prevVelocity};
+
+ lSubdividedDeltaTime = lSubdividedDeltaTime / 2.0;
+ updateCircle(lSubdivideHorizontalBall, lSubdividedDeltaTime);
+ updateCircle(lSubdivideVerticalBall, lSubdividedDeltaTime);
+
+ if (lSubdividedDeltaTime === 0) {
+ console.error('This should NOT be happening');
+ break;
+ }
+ } while (doCirclesIntersect(lSubdivideHorizontalBall, lSubdivideVerticalBall))
+
+ const lIntersectionResult = getIntersectionDataForCircles(lSubdivideHorizontalBall, lSubdivideVerticalBall);
+
+ console.log('We have a collision');
+ const lRelativeVelocity = lIntersectionResult.relativeVelocity,
+ lCollisionNormal = lIntersectionResult.collisionNormal,
+ lFirstPerp = getPerp2(lIntersectionResult.firstPointOfApplication),
+ lSecondPerp = getPerp2(lIntersectionResult.secondPointOfApplication);
+
+ const lNumerator = dot2(scaleVec2(lRelativeVelocity, -(1.0 + COF_OF_RESTITUITION)), lCollisionNormal);
+ const lLinearDenomPart = dot2(lCollisionNormal, (scaleVec2(lCollisionNormal, 1 / horizontalCircle.mass + 1 / verticalCircle.mass)));
+ const lRotationalDenomPart = (Math.pow(dot2(lFirstPerp, lCollisionNormal), 2) / getMomentOfInertia(horizontalCircle))
+ + (Math.pow(dot2(lSecondPerp, lCollisionNormal), 2) / getMomentOfInertia(verticalCircle))
+
+ const lImpulseMagnitude = lNumerator / (lLinearDenomPart + lRotationalDenomPart);
+
+ horizontalCircle.position = lSubdivideHorizontalBall.position;
+ verticalCircle.position = lSubdivideVerticalBall.position;
+
+ horizontalCircle.velocity = addVec2(horizontalCircle.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / horizontalCircle.mass));
+ verticalCircle.velocity = subVec2(verticalCircle.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / verticalCircle.mass));
+
+ horizontalCircle.rotationVelocity = horizontalCircle.rotationVelocity + dot2(lFirstPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / getMomentOfInertia(horizontalCircle);
+ verticalCircle.rotationVelocity = verticalCircle.rotationVelocity - dot2(lSecondPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / getMomentOfInertia(verticalCircle);
+
+ updateCircle(horizontalCircle, pDeltaTimeSeconds - lSubdividedDeltaTime);
+ updateCircle(verticalCircle, pDeltaTimeSeconds - lSubdividedDeltaTime);
+
+ return true;
+ }
+
+ function render() {
+ lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ lProgramContext.gl.clearDepth(1.0);
+ lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST);
+ lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL);
+ lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT);
+ lProgramContext.gl.useProgram(pProgramInfo.program);
+ lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective);
+
+ renderCircle(lProgramContext.gl, pProgramInfo, horizontalCircle);
+ renderCircle(lProgramContext.gl, pProgramInfo, verticalCircle);
+ }
+
+ const TORQUE_MULTIPLIER = 100.0; // TODO: This may be unncessary
+ function applyForce(pCircle, pForceVector, pPointOfApplication) {
+ if (pPointOfApplication !== undefined) {
+ const lOriginToPointOfApp = subVec2(vec2(), pPointOfApplication),
+ lPerpVec = vec2(-lOriginToPointOfApp.y, lOriginToPointOfApp.x);
+
+ pCircle.torque += TORQUE_MULTIPLIER * dot2(lPerpVec, pForceVector);
+ }
+
+ pCircle.force = addVec2(pCircle.force, pForceVector);
+ }
+
+ function cleanup() {
+ lProgramContext.gl.deleteBuffer(horizontalCircle.buffer);
+ lProgramContext.gl.deleteBuffer(verticalCircle.buffer);
+ lProgramContext.gl.deleteProgram(pProgramInfo.program);
+ lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
+ }
+
+ function reset() {
+ lExitRequestFunc();
+ lProgramContext.reset();
+ $('#time_step_slider').unbind('change');
+ }
+
+ const lExitRequestFunc = requestUpdateLoop(update, cleanup);
+ lProgramContext.stopButton.on('click', reset);
+ $('#time_step_slider').on('change', function() { lTimeStepScale = $(this).val(); });
+ });
+ }
+
+ lProgramContext.playButton.on('click', run);
+ }
+
+ $(document).ready(main);
+})() \ No newline at end of file
diff --git a/frontend/_rigidbody/rigidbody_3b.js b/frontend/_rigidbody/rigidbody_3b.js
new file mode 100644
index 0000000..df81582
--- /dev/null
+++ b/frontend/_rigidbody/rigidbody_3b.js
@@ -0,0 +1,192 @@
+/// <reference path="../scripts/jquery-3.5.1.min.js"/>
+/// <reference path="vec2.js" />
+/// <reference path="mat4.js" />
+/// <reference path="shader.js" />
+/// <reference path="circle.js" />
+/// <reference path="program_common.js" />
+
+(function() {
+ // Define Constants
+ const GRAVITY = 50.0;
+ const COF_OF_RESTITUITION = 0.2;
+
+ var lProgramContext = undefined;
+
+ function main() {
+ lProgramContext = getContext('#rigidbody_3b');
+
+ if (lProgramContext.gl === null) {
+ console.error('Unable to initialize WebGL. Your browser or machine may not support it.');
+ return;
+ }
+
+ lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
+ lProgramContext.playButton.on('click', run);
+ }
+
+ function run() {
+ console.log('Running Rigid Body 3b');
+ lProgramContext.load().then(function(pProgramInfo) {
+ const lNumHorizontalPegs = lProgramContext.width / 80.0,
+ lNumVerticalPegs = lProgramContext.height / 80.0,
+ lBall = circle(lProgramContext.gl, 16.0, 16,
+ [ { x: 1, y: 0, z: 0, w: 1 }, { x: 0, y: 1, z: 0, w: 1 }, { x: 0, y: 0, z: 1, w: 1 } ],
+ vec2(38 * 8, lProgramContext.height - 24.0), 10.0),
+ lPegList = [];
+
+ lBall.velocity = vec2(0, -50.0);
+
+ // Generate a peg. These pegs will NOT be updated, so that they
+ // dont' fall due to gravity.
+ for (let lRowIdx = 1; lRowIdx < lNumVerticalPegs - 1; lRowIdx++) {
+ for (let lColIdx = 0; lColIdx < lNumHorizontalPegs -1; lColIdx++) {
+ lPegList.push(circle(lProgramContext.gl,
+ 16.0, 16,
+ [ { x: 165.0 / 255.0, y: 42.0 / 255.0, z: 42.0 / 255.0, w: 1.0 }],
+ vec2((lColIdx + 1) * 80.0, lRowIdx * 80.0),
+ 10000 // Real big so it's almost negligble
+ ));
+ }
+ }
+
+ function updateCircle(pCircle, pDeltaTimeSeconds) {
+ // Same physics updates from part 1
+ applyForce(pCircle, vec2(0, -1.0 * (pCircle.mass * GRAVITY)));
+ const lCurrentAcceleration = scaleVec2(pCircle.force, 1.0 / pCircle.mass);
+ pCircle.prevVelocity = pCircle.velocity;
+ pCircle.velocity = addVec2(pCircle.velocity, scaleVec2(lCurrentAcceleration, pDeltaTimeSeconds));
+ pCircle.prevPos = { ...pCircle.position };
+ pCircle.position = addVec2(pCircle.position, scaleVec2(pCircle.velocity, pDeltaTimeSeconds));
+ pCircle.force = vec2();
+
+ // Same physics updates from part 2
+
+ const lMomentOfInertia = getMomentOfInertia(pCircle);
+ const lAngularAcceleration = pCircle.torque / lMomentOfInertia;
+ pCircle.rotationVelocity += lAngularAcceleration * pDeltaTimeSeconds;
+ pCircle.rotationRadians += pCircle.rotationVelocity * pDeltaTimeSeconds;
+ pCircle.torque = 0;
+
+ pCircle.model = rotateMatrix2d(translateMatrix(mat4(), pCircle.position.x, pCircle.position.y, 0), pCircle.rotationRadians);
+ }
+
+ function update(pDeltaTimeSeconds) {
+ updateCircle(lBall, pDeltaTimeSeconds);
+ collision(pDeltaTimeSeconds);
+ render();
+ }
+
+ function collision(pDeltaTimeSeconds) {
+ for (let lPegIdx = 0; lPegIdx < lPegList.length; lPegIdx++) {
+ const lPeg = lPegList[lPegIdx];
+
+ if (!doCirclesIntersect(lPeg, lBall)) {
+ continue;
+ }
+
+ // We have an intersection! Let's try and figure out precisely when that happened.
+ let lSubdividedDeltaTime = pDeltaTimeSeconds;
+
+ // Create a ball and move it back to the balls previous position
+ let lSubdividedBall = undefined;
+
+ do {
+ // Move the subdivided ball back to the previous position, and then
+ // advance its position by increasingly smaller timestep. This could be pretty
+ // slow in some circumstances, and it most definitely does not prevent tunneling,
+ // but - for now - this is not so bad.
+ lSubdividedBall = JSON.parse(JSON.stringify(lBall));
+ lSubdividedBall.position = {...lBall.prevPos};
+ lSubdividedBall.velocity = {...lBall.prevVelocity};
+ lSubdividedDeltaTime = lSubdividedDeltaTime / 2.0;
+ updateCircle(lSubdividedBall, lSubdividedDeltaTime);
+ if (lSubdividedDeltaTime === 0) {
+ console.error('This should NOT be happening');
+ break;
+ }
+ } while (doCirclesIntersect(lPeg, lSubdividedBall))
+
+ // The ball is no longer intersecting at the time presented here. That means this is
+ // (nearly) the precise point of intersection.
+
+ const lIntersectionResult = getIntersectionDataForCircles(lPeg, lSubdividedBall);
+
+ console.log(lIntersectionResult);
+
+ const lRelativeVelocity = lIntersectionResult.relativeVelocity,
+ lCollisionNormal = lIntersectionResult.collisionNormal,
+ lFirstPerp = getPerp2(lIntersectionResult.firstPointOfApplication),
+ lSecondPerp = getPerp2(lIntersectionResult.secondPointOfApplication);
+
+ const lNumerator = dot2(scaleVec2(lRelativeVelocity, -(1.0 + COF_OF_RESTITUITION)), lCollisionNormal);
+ const lLinearDenomPart = dot2(lCollisionNormal, (scaleVec2(lCollisionNormal, 1 / lBall.mass)));
+ const lRotationalDenomPart = (Math.pow(dot2(lFirstPerp, lCollisionNormal), 2) / getMomentOfInertia(lPeg))
+ + (Math.pow(dot2(lSecondPerp, lCollisionNormal), 2) / getMomentOfInertia(lBall))
+
+ const lImpulseMagnitude = lNumerator / (lLinearDenomPart + lRotationalDenomPart);
+
+ lBall.position = lSubdividedBall.position; // Move the ball back to its proper subdivided position
+ lBall.velocity = subVec2(lBall.velocity, scaleVec2(lCollisionNormal, lImpulseMagnitude / lBall.mass));
+ lBall.rotationVelocity = lBall.rotationVelocity - dot2(lSecondPerp, scaleVec2(lCollisionNormal, lImpulseMagnitude)) / getMomentOfInertia(lBall);
+
+ console.log(lBall.rotationVelocity);
+
+ // Now we update in our new direction with the remaining time that we have left.
+ updateCircle(lBall, pDeltaTimeSeconds - lSubdividedDeltaTime);
+
+ break;
+ }
+ }
+
+ function render() {
+ lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ lProgramContext.gl.clearDepth(1.0);
+ lProgramContext.gl.enable(lProgramContext.gl.DEPTH_TEST);
+ lProgramContext.gl.depthFunc(lProgramContext.gl.LEQUAL);
+ lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT | lProgramContext.gl.DEPTH_BUFFER_BIT);
+ lProgramContext.gl.useProgram(pProgramInfo.program);
+ lProgramContext.gl.uniformMatrix4fv(pProgramInfo.uniformLocations.projection, false, lProgramContext.perspective);
+
+ lPegList.forEach(function(pCircle) {
+ renderCircle(lProgramContext.gl, pProgramInfo, pCircle);
+ });
+
+ renderCircle(lProgramContext.gl, pProgramInfo, lBall);
+ }
+
+ const TORQUE_MULTIPLIER = 100.0; // TODO: This may be unncessary
+ function applyForce(pCircle, pForceVector, pPointOfApplication) {
+ if (pPointOfApplication !== undefined) {
+ const lOriginToPointOfApp = subVec2(vec2(), pPointOfApplication),
+ lPerpVec = vec2(-lOriginToPointOfApp.y, lOriginToPointOfApp.x);
+
+ pCircle.torque += TORQUE_MULTIPLIER * dot2(lPerpVec, pForceVector);
+ }
+
+ pCircle.force = addVec2(pCircle.force, pForceVector);
+ }
+
+ function cleanup() {
+ lPegList.forEach(function(pCircle) { freeCircle(lProgramContext.gl, pCircle); });
+ freeCircle(lProgramContext.gl, lBall);
+
+ lProgramContext.gl.deleteProgram(pProgramInfo.program);
+ lProgramContext.gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ lProgramContext.gl.clear(lProgramContext.gl.COLOR_BUFFER_BIT);
+ }
+
+ function reset() {
+ lExitRequestFunc();
+ lProgramContext.reset();
+ $('#time_step_slider').unbind('change');
+ }
+
+ const lExitRequestFunc = requestUpdateLoop(update, cleanup);
+ lProgramContext.stopButton.on('click', reset);
+ $('#time_step_slider').on('change', function() { lTimeStepScale = $(this).val(); });
+ });
+ }
+
+ $(document).ready(main);
+})() \ No newline at end of file
diff --git a/frontend/dog-114-203766.png b/frontend/dog-114-203766.png
deleted file mode 100644
index 1bed84f..0000000
--- a/frontend/dog-114-203766.png
+++ /dev/null
Binary files differ
diff --git a/frontend/dog-120-203766.png b/frontend/dog-120-203766.png
deleted file mode 100644
index 8630006..0000000
--- a/frontend/dog-120-203766.png
+++ /dev/null
Binary files differ
diff --git a/frontend/dog-144-203766.png b/frontend/dog-144-203766.png
deleted file mode 100644
index f99123a..0000000
--- a/frontend/dog-144-203766.png
+++ /dev/null
Binary files differ
diff --git a/frontend/dog-152-203766.png b/frontend/dog-152-203766.png
deleted file mode 100644
index c0e2c85..0000000
--- a/frontend/dog-152-203766.png
+++ /dev/null
Binary files differ
diff --git a/frontend/dog-16-203766.png b/frontend/dog-16-203766.png
deleted file mode 100644
index bed9af9..0000000
--- a/frontend/dog-16-203766.png
+++ /dev/null
Binary files differ
diff --git a/frontend/dog-24-203766.png b/frontend/dog-24-203766.png
deleted file mode 100644
index b70836f..0000000
--- a/frontend/dog-24-203766.png
+++ /dev/null
Binary files differ
diff --git a/frontend/dog-32-203766.png b/frontend/dog-32-203766.png
deleted file mode 100644
index 46b6f77..0000000
--- a/frontend/dog-32-203766.png
+++ /dev/null
Binary files differ
diff --git a/frontend/dog-48-203766.png b/frontend/dog-48-203766.png
deleted file mode 100644
index ba10a5b..0000000
--- a/frontend/dog-48-203766.png
+++ /dev/null
Binary files differ
diff --git a/frontend/dog-512-203766.png b/frontend/dog-512-203766.png
deleted file mode 100644
index 814c34e..0000000
--- a/frontend/dog-512-203766.png
+++ /dev/null
Binary files differ
diff --git a/frontend/dog-57-203766.png b/frontend/dog-57-203766.png
deleted file mode 100644
index 0ee3c44..0000000
--- a/frontend/dog-57-203766.png
+++ /dev/null
Binary files differ
diff --git a/frontend/dog-64-203766.png b/frontend/dog-64-203766.png
deleted file mode 100644
index d28a1be..0000000
--- a/frontend/dog-64-203766.png
+++ /dev/null
Binary files differ
diff --git a/frontend/dog-72-203766.png b/frontend/dog-72-203766.png
deleted file mode 100644
index 25c5c50..0000000
--- a/frontend/dog-72-203766.png
+++ /dev/null
Binary files differ
diff --git a/frontend/favicon.ico b/frontend/favicon.ico
deleted file mode 100644
index 7c96d7e..0000000
--- a/frontend/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/frontend/favicon/favicon.ico b/frontend/favicon/favicon.ico
new file mode 100644
index 0000000..53a7c84
--- /dev/null
+++ b/frontend/favicon/favicon.ico
Binary files differ
diff --git a/frontend/favicon/little-penguin-114-27563.png b/frontend/favicon/little-penguin-114-27563.png
new file mode 100644
index 0000000..51730fa
--- /dev/null
+++ b/frontend/favicon/little-penguin-114-27563.png
Binary files differ
diff --git a/frontend/favicon/little-penguin-120-27563.png b/frontend/favicon/little-penguin-120-27563.png
new file mode 100644
index 0000000..50b8538
--- /dev/null
+++ b/frontend/favicon/little-penguin-120-27563.png
Binary files differ
diff --git a/frontend/favicon/little-penguin-144-27563.png b/frontend/favicon/little-penguin-144-27563.png
new file mode 100644
index 0000000..39eedc2
--- /dev/null
+++ b/frontend/favicon/little-penguin-144-27563.png
Binary files differ
diff --git a/frontend/favicon/little-penguin-152-27563.png b/frontend/favicon/little-penguin-152-27563.png
new file mode 100644
index 0000000..f003d59
--- /dev/null
+++ b/frontend/favicon/little-penguin-152-27563.png
Binary files differ
diff --git a/frontend/favicon/little-penguin-16-27563.png b/frontend/favicon/little-penguin-16-27563.png
new file mode 100644
index 0000000..6e0581f
--- /dev/null
+++ b/frontend/favicon/little-penguin-16-27563.png
Binary files differ
diff --git a/frontend/favicon/little-penguin-24-27563.png b/frontend/favicon/little-penguin-24-27563.png
new file mode 100644
index 0000000..2d047d3
--- /dev/null
+++ b/frontend/favicon/little-penguin-24-27563.png
Binary files differ
diff --git a/frontend/favicon/little-penguin-32-27563.png b/frontend/favicon/little-penguin-32-27563.png
new file mode 100644
index 0000000..1850a4a
--- /dev/null
+++ b/frontend/favicon/little-penguin-32-27563.png
Binary files differ
diff --git a/frontend/favicon/little-penguin-48-27563.png b/frontend/favicon/little-penguin-48-27563.png
new file mode 100644
index 0000000..4ecf57a
--- /dev/null
+++ b/frontend/favicon/little-penguin-48-27563.png
Binary files differ
diff --git a/frontend/favicon/little-penguin-57-27563.png b/frontend/favicon/little-penguin-57-27563.png
new file mode 100644
index 0000000..2ba0965
--- /dev/null
+++ b/frontend/favicon/little-penguin-57-27563.png
Binary files differ
diff --git a/frontend/favicon/little-penguin-64-27563.png b/frontend/favicon/little-penguin-64-27563.png
new file mode 100644
index 0000000..45b7595
--- /dev/null
+++ b/frontend/favicon/little-penguin-64-27563.png
Binary files differ
diff --git a/frontend/favicon/little-penguin-72-27563.png b/frontend/favicon/little-penguin-72-27563.png
new file mode 100644
index 0000000..9bea6de
--- /dev/null
+++ b/frontend/favicon/little-penguin-72-27563.png
Binary files differ
diff --git a/frontend/index.css b/frontend/index.css
index 40c74bd..c8cc394 100644
--- a/frontend/index.css
+++ b/frontend/index.css
@@ -79,7 +79,7 @@ nav > a:hover {
100% { transform: rotate(360deg); }
}
-section > p {
+article > p {
padding-left: 2rem;
padding-right: 2rem;
}
@@ -122,7 +122,7 @@ section > p {
/*
WebGL container styling from here on.
*/
-section .opengl_canvas_container {
+article .opengl_canvas_container {
position: relative;
width: 100%;
text-align: center;
@@ -131,7 +131,7 @@ section .opengl_canvas_container {
justify-content: center;
}
-section .opengl_canvas_container .play_button {
+article .opengl_canvas_container .play_button {
all: unset;
font-size: 2rem;
width: 128px;
@@ -149,11 +149,11 @@ section .opengl_canvas_container .play_button {
justify-content: center;
}
-section .opengl_canvas_container .play_button:hover {
+article .opengl_canvas_container .play_button:hover {
cursor: pointer;
}
-section .opengl_canvas_container .stop_button {
+article .opengl_canvas_container .stop_button {
all: unset;
font-size: 1rem;
background-color: red;
@@ -167,14 +167,15 @@ section .opengl_canvas_container .stop_button {
display: none;
}
-section .opengl_canvas_container .stop_button:hover {
+article .opengl_canvas_container .stop_button:hover {
cursor: pointer;
}
-section pre {
+article pre {
width: 90%;
overflow-x: auto;
padding-left: 2rem;
+ font-size: 0.9rem;
}
.opengl_canvas_sidebar {
diff --git a/frontend/index.html b/frontend/index.html
index 1694121..c62696d 100644
--- a/frontend/index.html
+++ b/frontend/index.html
@@ -7,6 +7,7 @@
<link rel="stylesheet" href="index.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,300" rel="stylesheet" type="text/css">
<title>Physics for Games</title>
+ <link rel="shortcut icon" href="favicon/favicon.ico" type="image/x-icon">
</head>
<body>
<header>
@@ -19,34 +20,36 @@
<a href="2d_part_2.html">2D - Rotational Forces</a>
<a href="2d_part_3.html">2D - Collision Forces</a>
</nav>
- <section id='introduction'>
- <h2>Introduction: Rigid Body Physics</h2>
- <p>
- You're most likely here because you have some interest in the world of rigid body physics. Maybe you have some knowledge of rendering via OpenGL or Vulkan,
- and you want to begin watching your up-until-now static scene come to life. Well, you're in the right place! In the course of this tutorial series I will walk
- you through the entirety of a 2D rigid body physics system entirely in the web. All of this information will be extendable to other languages, but we will use
- JavaScript and WebGL in these blog posts. Additionally, much of the information presented here can be extended to 3 dimensions, but 3D carries some complications
- with it, that we will discuss in future blog posts.
- </p>
- <p>
- In implementing a rigidy body physics system, we're primarily interested in two sub-fields of physics, namely <b>dynamics</b> and <b>kinematics</b>. Although I'm
- far as can be from being an expert in either of these fields, I will explain - from a programmer's persepctive - what they mean to me:
- <ul>
- <li>
- <b>Kinematics</b> is the study of how an object's movement changes over time. These are the classic position, velocity, and acceleration equations
- that you're most likely familiar with from high school or college physics.
- </li>
- <li>
- <b>Dynamics</b> is the study of whats <i>causes</i> kinematic movement. These are the classic force and momentum equations that you may already be familiar
- with as well.
- </li>
- </ul>
- </p>
- <p>
- Finally, I must provide a disclaimer that all of rigid body systems are very math-y. You will need to know a decent amount of vector calculus and linear algebra to really understand
- what's going on here. I am going to assume that you have this knowledge. If you don't already have this knowledge, I will try and provide some resources on the Books
- n' References page of the website.
- </p>
+ <section>
+ <article>
+ <h2>Introduction: Rigid Body Physics</h2>
+ <p>
+ You're most likely here because you have some interest in the world of rigid body physics. Maybe you have some knowledge of rendering via OpenGL or Vulkan,
+ and you want to begin watching your up-until-now static scene come to life. Well, you're in the right place! In the course of this tutorial series I will walk
+ you through the entirety of a 2D rigid body physics system entirely in the web. All of this information will be extendable to other languages, but we will use
+ JavaScript and WebGL in these blog posts. Additionally, much of the information presented here can be extended to 3 dimensions, but 3D carries some complications
+ with it, that we will discuss in future blog posts.
+ </p>
+ <p>
+ In implementing a rigidy body physics system, we're primarily interested in two sub-fields of physics, namely <b>dynamics</b> and <b>kinematics</b>. Although I'm
+ far as can be from being an expert in either of these fields, I will explain - from a programmer's persepctive - what they mean to me:
+ <ul>
+ <li>
+ <b>Kinematics</b> is the study of how an object's movement changes over time. These are the classic position, velocity, and acceleration equations
+ that you're most likely familiar with from high school or college physics.
+ </li>
+ <li>
+ <b>Dynamics</b> is the study of whats <i>causes</i> kinematic movement. These are the classic force and momentum equations that you may already be familiar
+ with as well.
+ </li>
+ </ul>
+ </p>
+ <p>
+ Finally, I must provide a disclaimer that all of rigid body systems are very math-y. You will need to know a decent amount of vector calculus and linear algebra to really understand
+ what's going on here. I am going to assume that you have this knowledge. If you don't already have this knowledge, I will try and provide some resources on the Books
+ n' References page of the website.
+ </p>
+ </article>
</section>
</main>
</body>
diff --git a/frontend/index.js b/frontend/index.js
index 0cbd896..f481bc6 100644
--- a/frontend/index.js
+++ b/frontend/index.js
@@ -1,10 +1,10 @@
/// <reference path="scripts/jquery-3.5.1.min.js"/>
-function main() {
- console.log('Document ready.');
- const lPathName = window.location.pathname.length > 1 && window.location.pathname.startsWith('/') ? window.location.pathname.substr(1) : window.location.pathname;
- console.log(lPathName);
- $('nav').find('a[href="' + lPathName + '"').addClass('nav-selected');
-}
-
-$(document).ready(main); \ No newline at end of file
+(function() {
+ function main() {
+ const lPathName = window.location.pathname.length > 1 && window.location.pathname.startsWith('/') ? window.location.pathname.substr(1) : window.location.pathname;
+ $('nav').find('a[href="' + lPathName + '"').addClass('nav-selected');
+ }
+
+ $(document).ready(main);
+})() \ No newline at end of file
diff --git a/frontend/readme.txt b/frontend/readme.txt
deleted file mode 100644
index aa00c22..0000000
--- a/frontend/readme.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-Thank you for downloading a favicon from Free Favicon! This favicon was created from an image at http://openclipart.org/ and converted to a favicon and other sizes for you to use in your projects. For more details about this image visit this page: https://openclipart.org/detail/203766/dog
-
-For more information about how you can use this image from OpenClipArt see this page: http://openclipart.org/may-clipart-be-used-comparison
-
-Here are the contents of this compressed package:
-
-* favicon.ico -- The favicon file (supports both 16*16 and 32*32 dimensions). You will need to rename this to favicon.ico and upload to your web site.
-
- * You can add a favicon to your web page by uploading favicon.ico to Root of your website and inserting the following HTML tag between the <head> ... </head> tags of your web page.
-
-<link rel="shortcut icon" href="favicon.ico" />
-
-* There are many different sized png files for use a icons for smartphones, tablets and desktop use.
-
-If you are having any problems installing your favicon we have tips on the Free Favicon blog. http://www.freefavicon.com/blog/
-
-Thank you once again for download from Free Favicon! If you like your favicon we appreciate you taking the time to mention our service to others, blogging about us and of course by linking to us.
-
-We also encourage you to check out Backblaze online backup. We use Backblaze to backup our computers and keep our data safe. They offer a free 15 day trial and are the easiest online backup service we have used.
-
-Use this link http://www.freefavicon.com/blog/outgoing/backblaze.php to try Backblaze for Free!
-
-By signing up for Backblaze you help keep Free Favicon free!
-
-Thank you,
-FreeFavicon.com \ No newline at end of file
diff --git a/frontend/rigidbody.html b/frontend/rigidbody.html
index d83e29e..f3616b5 100644
--- a/frontend/rigidbody.html
+++ b/frontend/rigidbody.html
@@ -15,7 +15,7 @@
<script src="_rigidbody/program_common.js"></script>
<script src="_rigidbody/rigidbody_1.js"></script>
<script src="_rigidbody/rigidbody_2.js"></script>
- <script src="_rigidbody/rigidbody_3.js"></script>
+ <script src="_rigidbody/rigidbody_3a.js"></script>
</head>
<body>
<header>
@@ -37,35 +37,6 @@
</ul>
</p>
</section>
- <section id='introduction'>
- <h2>Introduction: Rigid Body Physics</h2>
- <p>
- You're most likely here because you have some interest in the world of rigid body physics. Maybe you have some knowledge of rendering via OpenGL or Vulkan,
- and you want to begin watching your up-until-now static scene come to life. Well, you're in the right place! In the course of this tutorial series I will walk
- you through the entirety of a 2D rigid body physics system entirely in the web. All of this information will be extendable to other languages, but we will use
- JavaScript and WebGL in these blog posts. Additionally, much of the information presented here can be extended to 3 dimensions, but 3D carries some complications
- with it, that we will discuss in future blog posts.
- </p>
- <p>
- In implementing a rigidy body physics system, we're primarily interested in two sub-fields of physics, namely <b>dynamics</b> and <b>kinematics</b>. Although I'm
- far as can be from being an expert in either of these fields, I will explain - from a programmer's persepctive - what they mean to me:
- <ul>
- <li>
- <b>Kinematics</b> is the study of how an object's movement changes over time. These are the classic position, velocity, and acceleration equations
- that you're most likely familiar with from high school or college physics.
- </li>
- <li>
- <b>Dynamics</b> is the study of whats <i>causes</i> kinematic movement. These are the classic force and momentum equations that you may already be familiar
- with as well.
- </li>
- </ul>
- </p>
- <p>
- Finally, I must provide a disclaimer that all of rigid body systems are very math-y. You will need to know a decent amount of vector calculus and linear algebra to really understand
- what's going on here. I am going to assume that you have this knowledge. If you don't already have this knowledge, I will try and provide some resources on the Books
- n' References page of the website.
- </p>
- </section>
<hr />
<section id="linear-forces">
<h2>Part 1: Linear Forces</h2>
@@ -172,7 +143,7 @@
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
- <div id="rigidbody_3" class="opengl_canvas_container">
+ <div id="rigidbody_3a" class="opengl_canvas_container">
<canvas width="640" height="480"></canvas>
<div class="opengl_canvas_sidebar">
</div>