summaryrefslogtreecommitdiff
path: root/frontend/_shared/math
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/_shared/math')
-rw-r--r--frontend/_shared/math/circle.js112
-rw-r--r--frontend/_shared/math/mat4.js43
-rw-r--r--frontend/_shared/math/vec2.js56
3 files changed, 211 insertions, 0 deletions
diff --git a/frontend/_shared/math/circle.js b/frontend/_shared/math/circle.js
new file mode 100644
index 0000000..340d7dc
--- /dev/null
+++ b/frontend/_shared/math/circle.js
@@ -0,0 +1,112 @@
+/// <reference path="mat4.js" />
+/// <reference path="vec2.js" />
+
+const BYTES_PER_FLOAT = 4;
+
+/**
+ * Initializes a new circle object for the WebGL context.
+ *
+ * @param {WebGLRenderingContext} pGl
+ * @param {number} pRadius
+ * @param {number} pSegments
+ * @param {Array<Vector4>} pColorList
+ * @param {vec2} pInitialPosition
+ * @param {number} pMass
+ */
+function circle(pGl, pRadius, pSegments, pColorList, pInitialPosition, pMass) {
+ const lBuffer = pGl.createBuffer();
+
+ pGl.bindBuffer(pGl.ARRAY_BUFFER, lBuffer);
+
+ var lBufferedData = [];
+ vertexCount = 0;
+
+ const lAngleIncrements = (360.0 / pSegments) * (Math.PI / 180.0);
+ for (let lSegIdx = 0; lSegIdx < pSegments; lSegIdx++) {
+ const lAngle = lAngleIncrements * lSegIdx,
+ lNextAngle = lAngleIncrements * (lSegIdx + 1),
+ lColorIndex = Math.floor(pColorList.length * (lSegIdx / pSegments)),
+ lColor = pColorList[lColorIndex]; // TODO: Calculate which one to use
+
+ lBufferedData = lBufferedData.concat([
+ 0, 0, lColor.x, lColor.y, lColor.z, lColor.w,
+ pRadius * Math.sin(lAngle), pRadius * Math.cos(lAngle), lColor.x, lColor.y, lColor.z, lColor.w,
+ pRadius * Math.sin(lNextAngle), pRadius * Math.cos(lNextAngle), lColor.x, lColor.y, lColor.z, lColor.w
+ ]);
+
+ vertexCount += 3;
+ }
+
+ pGl.bufferData(pGl.ARRAY_BUFFER, new Float32Array(lBufferedData), pGl.STATIC_DRAW)
+ pGl.bindBuffer(pGl.ARRAY_BUFFER, undefined);
+
+ return {
+ buffer: lBuffer,
+ vertexCount: vertexCount,
+ prevPos: vec2(),
+ position: pInitialPosition || vec2(),
+ prevVelocity: vec2(),
+ velocity: vec2(),
+ force: vec2(),
+ torque: 0,
+ mass: pMass === undefined ? 1 : pMass,
+ rotationVelocity: 0,
+ rotationRadians: 0,
+ model: translateMatrix(mat4(), pInitialPosition ? pInitialPosition.x : 0, pInitialPosition ? pInitialPosition.y : 0, 0),
+ radius: pRadius
+ };
+}
+
+function renderCircle(pGl, pProgramInfo, pCircle) {
+ pGl.uniformMatrix4fv(pProgramInfo.uniformLocations.model, false, pCircle.model);
+ pGl.bindBuffer(pGl.ARRAY_BUFFER, pCircle.buffer);
+ {
+ pGl.enableVertexAttribArray(pProgramInfo.attributeLocations.position);
+ pGl.vertexAttribPointer(pProgramInfo.attributeLocations.position, 2, pGl.FLOAT, false, BYTES_PER_FLOAT * 6, 0);
+
+ pGl.enableVertexAttribArray(pProgramInfo.attributeLocations.color);
+ pGl.vertexAttribPointer(pProgramInfo.attributeLocations.color, 4, pGl.FLOAT, false, BYTES_PER_FLOAT * 6, BYTES_PER_FLOAT * 2);
+ }
+
+ pGl.drawArrays(pGl.TRIANGLE_STRIP, 0, pCircle.vertexCount);
+}
+
+function getMomentOfInertia(pCircle) {
+ return (Math.PI * Math.pow(pCircle.radius, 4)) / 4;
+}
+
+function doCirclesIntersect(pFirst, pSecond) {
+ const lDistanceBetween = Math.pow(pFirst.position.x - pSecond.position.x, 2)
+ + Math.pow(pFirst.position.y - pSecond.position.y, 2)
+ return lDistanceBetween <= Math.pow(pFirst.radius + pSecond.radius, 2);
+}
+
+/**
+ * Returns intersection information about the intersecting circles.
+ *
+ * Warning! Only use this if doCirclesIntersect returned true for these circles.
+ *
+ * @param {circle} pFirst
+ * @param {circle} pSecond
+ */
+function getIntersectionDataForCircles(pFirst, pSecond) {
+ // The collision normal is simply the difference between the two current positions
+ const lCollisionNormal = normalize2(subVec2(pFirst.position, pSecond.position));
+ const lCollisionPoint = vec2(
+ ((pFirst.position.x * pSecond.radius) + (pSecond.position.x * pFirst.radius)) / (pFirst.radius + pSecond.radius),
+ ((pFirst.position.y * pSecond.radius) + (pSecond.position.y * pFirst.radius)) / (pFirst.radius + pSecond.radius)
+ );
+
+ return {
+ relativeVelocity: subVec2(pFirst.velocity, pSecond.velocity),
+ collisionNormal: lCollisionNormal,
+ //firstPointOfApplication: addVec2(scaleVec2(normalize2(pFirst.velocity), pFirst.radius), pFirst.position),
+ //secondPointOfApplication: addVec2(scaleVec2(normalize2(pSecond.velocity), pSecond.radius), pSecond.position)
+ firstPointOfApplication: subVec2(lCollisionPoint, pFirst.position),
+ secondPointOfApplication: subVec2(lCollisionPoint, pSecond.position)
+ }
+}
+
+function freeCircle(pGl, pCircle) {
+ pGl.deleteBuffer(pCircle.buffer);
+} \ No newline at end of file
diff --git a/frontend/_shared/math/mat4.js b/frontend/_shared/math/mat4.js
new file mode 100644
index 0000000..6ab29e2
--- /dev/null
+++ b/frontend/_shared/math/mat4.js
@@ -0,0 +1,43 @@
+function mat4() {
+ return [
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
+ ]
+}
+
+function orthographic(pLeft, pRight, pBottom, pTop) {
+ const lResult = mat4();
+ lResult[0] = 2.0 / (pRight - pLeft);
+ lResult[5] = 2.0 / (pTop - pBottom);
+ lResult[10] = 1.0;
+ lResult[12] = -(pRight + pLeft) / (pRight - pLeft);
+ lResult[13] = -(pTop + pBottom) / (pTop - pBottom);
+ return lResult;
+}
+
+function translateMatrix(m, x, y, z) {
+ m = [...m];
+ m[12] += x;
+ m[13] += y;
+ m[14] += z;
+ return m;
+}
+
+function rotateMatrix2d(m, angle) {
+ m = [...m];
+ m[0] = Math.cos(angle);
+ m[1] = -Math.sin(angle);
+ m[4] = Math.sin(angle);
+ m[5] = Math.cos(angle);
+ return m;
+}
+
+function scaleMatrix(m, x, y, z) {
+ m = [...m];
+ m[0] = m[0] * x;
+ m[5] = m[5] * y;
+ m[10] = m[10] * z;
+ return m;
+} \ No newline at end of file
diff --git a/frontend/_shared/math/vec2.js b/frontend/_shared/math/vec2.js
new file mode 100644
index 0000000..cff38ce
--- /dev/null
+++ b/frontend/_shared/math/vec2.js
@@ -0,0 +1,56 @@
+function vec2(x = 0, y = 0) {
+ return { x: x, y: y};
+}
+
+function addVec2(v1, v2) {
+ return {
+ x: v1.x + v2.x,
+ y: v1.y + v2.y
+ };
+}
+
+function subVec2(v1, v2) {
+ return {
+ x: v1.x - v2.x,
+ y: v1.y - v2.y
+ };
+}
+
+function scaleVec2(v, s) {
+ return {
+ x: v.x * s,
+ y: v.y * s
+ };
+}
+
+function dot2(v1, v2) {
+ return v1.x * v2.x + v1.y * v2.y;
+}
+
+function length2(v) {
+ return Math.sqrt(v.x * v.x + v.y * v.y);
+}
+
+function normalize2(v) {
+ const lLength = length2(v);
+ const lInverseLength = lLength === 0 ? 1.0 : 1.0 / length2(v);
+ return { x: v.x * lInverseLength, y: v.y * lInverseLength };
+}
+
+function vec2str(v) {
+ return `(${v.x.toFixed(2)}, ${v.y.toFixed(2)})`;
+}
+
+function getPerp2(v) {
+ return {
+ x: -v.y,
+ y: v.x
+ };
+}
+
+function negate2(v) {
+ return {
+ x: -v.x,
+ y: -v.y
+ };
+} \ No newline at end of file