diff --git a/Pendulum/Homogeneous2D.js b/Pendulum/Homogeneous2D.js new file mode 100644 index 0000000..fdfa008 --- /dev/null +++ b/Pendulum/Homogeneous2D.js @@ -0,0 +1,39 @@ +// Homogeneous2D.js +// John Breaux 2022-07-01 +// 2D Homogeneous coordinate library + +"use strict" + +// +// Classes +// + +// Homogeneous2D: Stores a 2d vector or point in homogeneous coords +class Homogeneous2D { + 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; + } + // copy + copy() { + return new Homogeneous2D(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 + Math.PI / 2); + this.y = r * Math.sin(theta + Math.PI / 2); + this.w = w; + return this; + } +} \ No newline at end of file diff --git a/Pendulum/Pendulum.html b/Pendulum/Pendulum.html index 999bab9..1b932c3 100644 --- a/Pendulum/Pendulum.html +++ b/Pendulum/Pendulum.html @@ -21,6 +21,9 @@ + + + diff --git a/Pendulum/Pendulum.js b/Pendulum/Pendulum.js index 480c395..35c54c5 100644 --- a/Pendulum/Pendulum.js +++ b/Pendulum/Pendulum.js @@ -7,94 +7,85 @@ "use strict" const vertex_shader = ` - attribute vec4 a_Position; - uniform mat4 u_ModelMatrix; + attribute vec4 a_Position; + uniform mat4 u_ModelMatrix; - void main() - { - gl_Position = u_ModelMatrix * a_Position; - gl_PointSize = 5.0; - } `; + void main() + { + gl_Position = u_ModelMatrix * a_Position; + gl_PointSize = 5.0; + } `; const fragment_shader = ` - precision mediump float; - uniform vec4 u_Color; - void main() - { - gl_FragColor = u_Color; - } `; - -// Point size of the anchor -var POINT_SIZE = 5; -// Radius of the bob -var BOB_RADIUS = 0.1; -// length of the wire -var PEN_LENGTH = 0.8; -// Rotation angle (degrees/second) -var A_VELOCITY = 45.0; - + precision mediump float; + uniform vec4 u_Color; + void main() + { + gl_FragColor = u_Color; + } `; +var SIDES_DELTA = 0; function main() { - // Retrieve element - var canvas = document.getElementById('webgl'); + // Retrieve element + var canvas = document.getElementById('webgl'); - // Get the rendering context for WebGL - var gl = getWebGLContext(canvas); - if (!gl) { - console.log('Failed to get the rendering context for WebGL'); - return; - } + // Get the rendering context for WebGL + var gl = getWebGLContext(canvas); + if (!gl) { + console.log('Failed to get the rendering context for WebGL'); + return; + } - // Initialize shaders - if (!initShaders(gl, vertex_shader, fragment_shader)) { - console.log('Failed to intialize shaders.'); - return; - } + // Initialize shaders + if (!initShaders(gl, vertex_shader, fragment_shader)) { + console.log('Failed to intialize shaders.'); + return; + } - // create a pendulum object - var pendulum = new Pendulum({ angle: 0, length: PEN_LENGTH, radius: BOB_RADIUS }); - pendulum.init(gl); + // create a pendulum object + var pendulum = new Pendulum({ angle: 0, length: PEN_LENGTH, radius: BOB_RADIUS }); + pendulum.init(gl); - // Specify the color for clearing - gl.clearColor(0, 0, 0, 1); + // Specify the color for clearing + gl.clearColor(0, 0, 0, 1); - // Get storage location of u_ModelMatrix - var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix'); - if (!u_ModelMatrix) { - console.log('Failed to get the storage location of u_ModelMatrix'); - return; - } + // Get storage location of u_ModelMatrix + var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix'); + if (!u_ModelMatrix) { + console.log('Failed to get the storage location of u_ModelMatrix'); + return; + } - // Model matrix - var modelMatrix = new Matrix4(); - // Set it to the I matrix - modelMatrix.setIdentity(); + // Model matrix + var modelMatrix = new Matrix4(); + // Set it to the I matrix + modelMatrix.setIdentity(); - // Start drawing - var tick = function () { - // Tick the pendulum - pendulum.tick(); - // Draw the pendulum - draw(gl, pendulum, modelMatrix, u_ModelMatrix); - // Request that the browser ?calls tick - requestAnimationFrame(tick, canvas); - }; - tick(); + // Start drawing + var tick = function () { + // Tick the pendulum + pendulum.tick(); + // Draw the pendulum + draw(gl, pendulum, modelMatrix, u_ModelMatrix); + // Request that the browser ?calls tick + requestAnimationFrame(tick, canvas); + }; + tick(); } function draw(gl, pendulum, modelMatrix, u_ModelMatrix) { - // Clear - gl.clear(gl.COLOR_BUFFER_BIT); - // Draw the pendulum - pendulum.draw(gl, modelMatrix, u_ModelMatrix); + // Clear + gl.clear(gl.COLOR_BUFFER_BIT); + // Draw the pendulum + pendulum.draw(gl, modelMatrix, u_ModelMatrix); } function up() { - A_VELOCITY += 10; + A_VELOCITY += 10; } function down() { - A_VELOCITY -= 10; + A_VELOCITY -= 10; } diff --git a/Pendulum/PendulumComponents.js b/Pendulum/PendulumComponents.js index 2fd57a6..cd119f4 100644 --- a/Pendulum/PendulumComponents.js +++ b/Pendulum/PendulumComponents.js @@ -1,294 +1,72 @@ // PendulumComponents.js // John Breaux 2022-06-30 -// Classes, functions, and data structures for Pendulum.js +// Classes used by Pendulum.js "use strict" -// Common functions: -// acquire_buffer: Get a vertex buffer object from gl -function acquire_buffer(gl) { - // Create a buffer object - var vertexBuffer = gl.createBuffer(); - if (!vertexBuffer) { - console.log('Failed to create the buffer object'); - return -1; - } - return vertexBuffer; -} - -function acquire_attribute(gl, name, size, type) { - // Acquire a reference to named attr - var ret = gl.getAttribLocation(gl.program, name); - if (ret < 0) { - console.log(`Failed to get the storage location of ${name}`); - return -1; - } - gl.vertexAttribPointer(ret, size, type, false, 0, 0); - return ret; -} -function acquire_uniform(gl, name) { - // Acquire a reference to named attr - var ret = gl.getUniformLocation(gl.program, name); - if (!ret) { - console.log(`Failed to get the storage location of ${name}`); - return -1; - } - return ret; -} - +// // Classes -// homo2: Stores a 2d vector or point in homog. coords -class Homogeneous2D { - 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 Homogeneous2D(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 Rod { - constructor({ anchor = { x: 0, y: 0 }, bob = { x: 0, y: 0 }, color = { r: 1.0, g: 0.0, b: 0.0, a: 1.0 } } = {}) { - // Set the object's vertices - this.vertices = [ new Homogeneous2D(anchor.x, anchor.y, 1), - new Homogeneous2D(bob.x, bob.y, 1)] - // Set object's color - this.color = [color.r, color.g, color.b, color.a]; - } - // Convert to Float32Array [x, y] - 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; - } - // Initialize the object's drawing parameters - 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); - - // 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 the object - draw(gl, modelMatrix, u_ModelMatrix) { - // Bind the buffers - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - // Set the object's color - var u_Color = acquire_uniform(gl, 'u_Color'); - gl.uniform4fv(u_Color, this.color); - - // get a_Position - var a_Position = acquire_attribute(gl, 'a_Position', 2, gl.FLOAT); - // Enable the assignment to a_Position variable - gl.enableVertexAttribArray(a_Position); - - // Pass the rotation matrix to the vertex shader - gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements); - // Draw the Anchor - gl.drawElements(gl.LINES, 2, gl.UNSIGNED_BYTE, 0); - } -} - -class Anchor { - constructor({ center = { x: 0, y: 0 }, color = { r: 0.0, g: 1.0, b: 0.0, a: 1.0 } } = {}) { - this.position = new Homogeneous2D(center.x, center.y, 1); - // Set object color - this.color = [color.r, color.g, color.b, color.a]; - } - // Convert to Float32Array [x, y] - 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; - } - // Initialize the object's drawing parameters - 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); - - // 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 the object - draw(gl, modelMatrix, u_ModelMatrix) { - // Bind the buffers - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - // Set the object's color - var u_Color = acquire_uniform(gl, 'u_Color'); - gl.uniform4fv(u_Color, this.color); - - // get a_Position - var a_Position = acquire_attribute(gl, 'a_Position', 2, gl.FLOAT); - // Enable the assignment to a_Position variable - gl.enableVertexAttribArray(a_Position); - - // 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); - } -} - -// Polygon class: Holds vertices and a center point. Only constructs regular polygons -class Polygon { +// Polygon class: Construct and display a regular polygon in 2D +class Polygon extends ShapedObject { // 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, a: 1 } } = {}) { - this.length = 0; - // Mark center point - this.center = new Homogeneous2D(center.x, center.y, 1); + constructor({ sides = 6, radius = 1, center = { x: 0, y: 0 }, color = { r: 0, g: 0, b: 1, a: 1 } } = {}) { + super({ color: color }); // Create vertices this.vertices = []; for (var i = 0; i <= sides; i++) { - this.vertices[i] = new Homogeneous2D().from_polar(radius, rotation + (i * 2 * Math.PI / sides)).add_m(this.center); - this.length++; + // Create vertices by adding center-point in Homogeneous coordinates to an offset vector generated from polar coordinates. + this.vertices[i] = new Homogeneous2D().from_polar(radius, 2 * Math.PI * i / sides) + .add_m(new Homogeneous2D(center.x, center.y, 1)); } - // Set object color - this.color = [color.r, color.g, color.b, color.a]; } - // 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; - } - // Initialize the object's drawing parameters + // Wrap the init function to set the draw_primitive type to TRIANGLE_FAN 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); - - // 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 the object - draw(gl, modelMatrix, u_ModelMatrix) { - // Bind the buffers - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - // Set the object's color - var u_Color = acquire_uniform(gl, 'u_Color'); - gl.uniform4fv(u_Color, this.color); - - // get a_Position - var a_Position = acquire_attribute(gl, 'a_Position', 2, gl.FLOAT); - // Enable the assignment to a_Position variable - gl.enableVertexAttribArray(a_Position); - - // 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); + this.draw_primitive = gl.TRIANGLE_FAN; + super.init(gl); } } -class Pendulum { - constructor({ angle = 0, length = PEN_LENGTH, radius = BOB_RADIUS, anchor = { x: 0, y: 0 } } = {}) { - this.angle = angle; - var bob = {x: 0, y: -length}; - this.components = [ - new Rod({ anchor: anchor, bob: bob}), - new Anchor({ center: anchor }), - new Polygon({ radius: radius, center: { x: 0, y: -length } }) - ]; +class Rod extends ShapedObject { + constructor({ anchor = { x: 0, y: 0 }, bob = { x: 0, y: 0 }, color = { r: 1.0, g: 0.0, b: 0.0, a: 1.0 } } = {}) { + super({ color: color }); + // Set the object's vertices + this.vertices = [new Homogeneous2D(anchor.x, anchor.y, 1), new Homogeneous2D(bob.x, bob.y, 1)] } + // Wrap the init function to set the draw_primitive type to LINES + init(gl) { + this.draw_primitive = gl.LINES; + super.init(gl); + } +} - // 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; +class Anchor extends ShapedObject { + constructor({ center = { x: 0, y: 0 }, color = { r: 0.0, g: 1.0, b: 0.0, a: 1.0 } } = {}) { + super({ color: color }); + // Set the object's vertices + this.vertices = [new Homogeneous2D(center.x, center.y, 1)]; + } + // Wrap the init function to set the draw_primitive type to POINTS + init(gl) { + this.draw_primitive = gl.POINTS; + super.init(gl); + } +} + + +// This doesn't need to extend ShapedObject, but I love the symmetry +class Pendulum extends ShapedObject { + constructor({ angle = 0, length = PEN_LENGTH, radius = BOB_RADIUS} = {}) { + super(); + this.angle = angle; + var anchor = { x: 0, y: 0 }, bob = { x: 0, y: -length }; + this.components = [ + new Rod({ anchor: anchor, bob: bob }), + new Anchor({ center: anchor }), + new Polygon({ sides: 6, radius: radius, center: bob }) + ]; } // Initialize the pendulum @@ -300,13 +78,22 @@ class Pendulum { // 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); + modelMatrix.setIdentity(); + modelMatrix.rotate(this.angle, 0, 0, 1); // Draw each component for (var component of this.components) { component?.draw(gl, modelMatrix, u_ModelMatrix); } } + + // 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; + } } \ No newline at end of file diff --git a/Pendulum/ShapedObject.js b/Pendulum/ShapedObject.js new file mode 100644 index 0000000..703dd51 --- /dev/null +++ b/Pendulum/ShapedObject.js @@ -0,0 +1,76 @@ +// PendulumComponents.js +// John Breaux 2022-06-30 +// Super-class for simple, flat-color drawn primitives + +"use strict" + +// +// Classes +// + +// ShapedObject: Super-class for simple drawn primitives +class ShapedObject { + constructor({ color = { r: 1, g: 1, b: 1, a: 0.5 } } = {}) { + // Set object color + this.color = [color.r, color.g, color.b, color.a]; + } + + // Convert to Float32Array [x, y] + 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; + } + + // Initialize the object's drawing parameters + 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); + + // 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 the object + draw(gl, modelMatrix, u_ModelMatrix) { + // Bind the buffers + gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + + // Set the object's color + var u_Color = acquire_uniform(gl, 'u_Color'); + gl.uniform4fv(u_Color, this.color); + + // get a_Position + enable_attribute(gl, 'a_Position', 2, gl.FLOAT); + + // Pass the rotation matrix to the vertex shader + gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements); + // Draw the Anchor + gl.drawElements(this.draw_primitive, this.vertices.length, gl.UNSIGNED_BYTE, 0); + } +} + +// Give me your [HeartShapedObject] \ No newline at end of file diff --git a/Pendulum/common.js b/Pendulum/common.js new file mode 100644 index 0000000..1a82222 --- /dev/null +++ b/Pendulum/common.js @@ -0,0 +1,55 @@ +// PendulumComponents.js +// John Breaux 2022-06-30 +// Classes, functions, and data structures for Pendulum.js + +"use strict" + +// +// Global variables +// + +// Point size of the anchor +var POINT_SIZE = 5; +// Radius of the bob +var BOB_RADIUS = 0.1; +// length of the wire +var PEN_LENGTH = 0.8; +// Rotation angle (degrees/second) +var A_VELOCITY = 45.0; + +// +// Common functions: +// + +// acquire_buffer: Get a vertex buffer object from gl +function acquire_buffer(gl) { + // Create a buffer object + var vertexBuffer = gl.createBuffer(); + if (!vertexBuffer) { + console.log('Failed to create the buffer object'); + return -1; + } + return vertexBuffer; +} + +function enable_attribute(gl, name, size, type) { + // Acquire a reference to named attr + var attr = gl.getAttribLocation(gl.program, name); + if (attr < 0) { + console.log(`Failed to get the storage location of ${name}`); + return -1; + } + gl.vertexAttribPointer(attr, size, type, false, 0, 0); + // Switch GL state machine to use named attr + gl.enableVertexAttribArray(attr); +} + +function acquire_uniform(gl, name) { + // Acquire a reference to named attr + var ret = gl.getUniformLocation(gl.program, name); + if (!ret) { + console.log(`Failed to get the storage location of ${name}`); + return -1; + } + return ret; +} \ No newline at end of file