// 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); } } }