210 lines
6.3 KiB
JavaScript
210 lines
6.3 KiB
JavaScript
|
// PendulumComponents.js
|
||
|
// John Breaux 2022-06-30
|
||
|
// Classes and data structures for Pendulum.js
|
||
|
|
||
|
"use strict"
|
||
|
|
||
|
// Classes
|
||
|
// homo2: Stores a 2d vector or point in homog. coords
|
||
|
class homog2 {
|
||
|
constructor(x = 0, y = 0, w = 0) {
|
||
|
this.x = x;
|
||
|
this.y = y;
|
||
|
this.w = w;
|
||
|
}
|
||
|
// Add with modify
|
||
|
add_m(rhs) {
|
||
|
if (rhs) {
|
||
|
this.x += rhs.x;
|
||
|
this.y += rhs.y;
|
||
|
this.w += rhs.w;
|
||
|
return this;
|
||
|
}
|
||
|
else return null;
|
||
|
}
|
||
|
// scalar multiply with modify
|
||
|
smul_m(scalar) {
|
||
|
if (typeof (rhs) === "number") {
|
||
|
this.x *= rhs;
|
||
|
this.y *= rhs;
|
||
|
this.w *= rhs;
|
||
|
return this;
|
||
|
}
|
||
|
else return null;
|
||
|
}
|
||
|
// copy
|
||
|
copy() {
|
||
|
return new homog2(this.x, this.y, this.w);
|
||
|
}
|
||
|
// create vector/point from 2d polar coordinates
|
||
|
from_polar(r = 0, theta = 0, w = 0) {
|
||
|
this.x = r * Math.cos(theta);
|
||
|
this.y = r * Math.sin(theta);
|
||
|
this.w = w;
|
||
|
return this;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
class Anchor {
|
||
|
constructor({ center = { x: 0, y: 0 } } = {}) {
|
||
|
this.position = new homog2(center.x, center.y, 1);
|
||
|
}
|
||
|
// Convert to Float32Array [center, v0, v1, ...]
|
||
|
vertex_array() {
|
||
|
// allocate space for center.xy + vertices.xy
|
||
|
var ret = new Float32Array(2);
|
||
|
// save the vertices
|
||
|
ret[0] = this.position.x, ret[1] = this.position.y;
|
||
|
console.log(ret);
|
||
|
return ret;
|
||
|
}
|
||
|
// Generate the index_array for the shape
|
||
|
index_array() {
|
||
|
var ret = new Uint8Array(1);
|
||
|
ret[0] = 0;
|
||
|
console.log(ret);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
init(gl) {
|
||
|
// Make the buffers
|
||
|
this.vertexBuffer = acquire_buffer(gl);
|
||
|
this.indexBuffer = acquire_buffer(gl);
|
||
|
|
||
|
// Bind the buffers
|
||
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
||
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
||
|
|
||
|
// Acquire a reference to a_Position
|
||
|
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
|
||
|
if (a_Position < 0) {
|
||
|
console.log('Failed to get the storage location of a_Position');
|
||
|
return -1;
|
||
|
}
|
||
|
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
|
||
|
|
||
|
// Enable the assignment to a_Position variable
|
||
|
gl.enableVertexAttribArray(a_Position);
|
||
|
|
||
|
// Write date into the buffers
|
||
|
gl.bufferData(gl.ARRAY_BUFFER, this.vertex_array(), gl.STATIC_DRAW);
|
||
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.index_array(), gl.STATIC_DRAW);
|
||
|
}
|
||
|
|
||
|
draw(gl, modelMatrix, u_ModelMatrix) {
|
||
|
// Bind the buffers
|
||
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
||
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
||
|
// Pass the rotation matrix to the vertex shader
|
||
|
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
|
||
|
// Draw the Anchor
|
||
|
gl.drawElements(gl.POINTS, 1, gl.UNSIGNED_BYTE, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// hexagon2 class: Holds vertices and a center point. Only constructs regular polygons
|
||
|
class Polygon {
|
||
|
// constructor: Make a new regular polygon
|
||
|
constructor({ sides = 6, radius = 1, rotation = 0, center = { x: 0, y: 0 }, color = { r: 0, g: 0, b: 1 } } = {}) {
|
||
|
this.length = 0;
|
||
|
// vertices
|
||
|
this.vertices = [];
|
||
|
this.center = new homog2(center.x, center.y, 1);
|
||
|
for (var i = 0; i <= sides; i++) {
|
||
|
this.vertices[i] = new homog2().from_polar(radius, rotation + (i * 2 * Math.PI / sides)).add_m(this.center);
|
||
|
this.length++;
|
||
|
}
|
||
|
}
|
||
|
// Convert to Float32Array [center, v0, v1, ...]
|
||
|
vertex_array() {
|
||
|
// allocate space for center.xy + vertices.xy
|
||
|
var ret = new Float32Array((this.vertices.length) * 2);
|
||
|
// save the vertices
|
||
|
for (var i = 0; i < this.vertices.length; i++) {
|
||
|
var j = 2 * i;
|
||
|
ret[j] = this.vertices[i].x;
|
||
|
ret[j + 1] = this.vertices[i].y;
|
||
|
}
|
||
|
return ret;
|
||
|
}
|
||
|
// Generate the index_array for the shape
|
||
|
index_array() {
|
||
|
var ret = new Uint8Array(this.vertices.length + 1);
|
||
|
for (var i = 0; i < this.vertices.length; i++) {
|
||
|
ret[i] = i
|
||
|
}
|
||
|
ret[this.vertices.length] = 0;
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
init(gl) {
|
||
|
// Make the buffers
|
||
|
this.vertexBuffer = acquire_buffer(gl);
|
||
|
this.indexBuffer = acquire_buffer(gl);
|
||
|
|
||
|
// Bind the buffers
|
||
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
||
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
||
|
|
||
|
// Acquire a reference to a_Position
|
||
|
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
|
||
|
if (a_Position < 0) {
|
||
|
console.log('Failed to get the storage location of a_Position');
|
||
|
return -1;
|
||
|
}
|
||
|
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
|
||
|
|
||
|
// Enable the assignment to a_Position variable
|
||
|
gl.enableVertexAttribArray(a_Position);
|
||
|
|
||
|
// Write date into the buffers
|
||
|
gl.bufferData(gl.ARRAY_BUFFER, this.vertex_array(), gl.STATIC_DRAW);
|
||
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.index_array(), gl.STATIC_DRAW);
|
||
|
}
|
||
|
|
||
|
draw(gl, modelMatrix, u_ModelMatrix) {
|
||
|
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
||
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
||
|
// Pass the rotation matrix to the vertex shader
|
||
|
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
|
||
|
// Draw the shape
|
||
|
gl.drawElements(gl.TRIANGLE_FAN, this.length, gl.UNSIGNED_BYTE, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Pendulum {
|
||
|
constructor({ angle = 0, length = PEN_LENGTH, radius = BOB_RADIUS, anchor = { x: 0, y: 0 } } = {}) {
|
||
|
this.angle = angle;
|
||
|
this.components = [
|
||
|
new Anchor({ center: anchor }),
|
||
|
new Polygon({ radius: radius, center: { x: 0, y: -length } })
|
||
|
];
|
||
|
}
|
||
|
|
||
|
// Tick the pendulum (update and perform movement)
|
||
|
tick() {
|
||
|
var now = Date.now(), elapsed = now - this.t_prev;
|
||
|
this.t_prev = now;
|
||
|
this.angle = (this.angle + (A_VELOCITY * elapsed / 1000)) % 360;
|
||
|
}
|
||
|
|
||
|
// Initialize the pendulum
|
||
|
init(gl) {
|
||
|
// initialize the components
|
||
|
for(var component of this.components) {
|
||
|
component?.init(gl);
|
||
|
}
|
||
|
// start the clock
|
||
|
this.t_prev = Date.now();
|
||
|
}
|
||
|
// Draw the pendulum
|
||
|
draw(gl, modelMatrix, u_ModelMatrix) {
|
||
|
// Rotate the pendulum
|
||
|
modelMatrix.setRotate(this.angle, 0, 0, 1);
|
||
|
// Draw each component
|
||
|
for (var component of this.components) {
|
||
|
component?.draw(gl, modelMatrix, u_ModelMatrix);
|
||
|
}
|
||
|
}
|
||
|
}
|