diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/components/configuration.js | 9 | ||||
| -rw-r--r-- | lib/components/radius.js | 9 | ||||
| -rw-r--r-- | lib/components/triple_amplitude.js | 12 | ||||
| -rw-r--r-- | lib/components/triple_frequency.js | 6 | ||||
| -rw-r--r-- | lib/components/up.js | 12 | ||||
| -rw-r--r-- | lib/config.js | 1 | ||||
| -rw-r--r-- | lib/factories/curves.js | 2 | ||||
| -rw-r--r-- | lib/factories/global.js | 33 | ||||
| -rw-r--r-- | lib/factories/ui.js | 28 | ||||
| -rw-r--r-- | lib/main.js | 34 | ||||
| -rw-r--r-- | lib/nodes/ample.js | 7 | ||||
| -rw-r--r-- | lib/nodes/cameras.js | 15 | ||||
| -rw-r--r-- | lib/nodes/configurable.js | 7 | ||||
| -rw-r--r-- | lib/nodes/frequent.js | 7 | ||||
| -rw-r--r-- | lib/nodes/lissajous_curve.js | 4 | ||||
| -rw-r--r-- | lib/systems/amplitude_adjuster.js | 64 | ||||
| -rw-r--r-- | lib/systems/camera_adjuster.js | 74 | ||||
| -rw-r--r-- | lib/systems/camera_rotator.js | 49 | ||||
| -rw-r--r-- | lib/systems/frequency_adjuster.js | 64 | ||||
| -rw-r--r-- | lib/systems/global_adjuster.js | 57 | ||||
| -rw-r--r-- | lib/systems/lissajous_position_updater.js | 13 | ||||
| -rw-r--r-- | lib/systems/webgl_renderer.js | 167 | ||||
| -rw-r--r-- | lib/webgl_utils.js | 12 |
23 files changed, 641 insertions, 45 deletions
diff --git a/lib/components/configuration.js b/lib/components/configuration.js new file mode 100644 index 0000000..ddb4a27 --- /dev/null +++ b/lib/components/configuration.js @@ -0,0 +1,9 @@ +import { Component } from '@serpentity/serpentity'; + +export default class Configuration extends Component { + constructor(config) { + + super(config); + this.lineLength = this.lineLength || 1000; + } +}; diff --git a/lib/components/radius.js b/lib/components/radius.js new file mode 100644 index 0000000..2aa29a8 --- /dev/null +++ b/lib/components/radius.js @@ -0,0 +1,9 @@ +import { Component } from '@serpentity/serpentity'; + +export default class Radius extends Component { + constructor(config) { + + super(config); + this.radius = this.radius || 5; + } +}; diff --git a/lib/components/triple_amplitude.js b/lib/components/triple_amplitude.js new file mode 100644 index 0000000..376c321 --- /dev/null +++ b/lib/components/triple_amplitude.js @@ -0,0 +1,12 @@ +import { Component } from '@serpentity/serpentity'; + +export default class TripleAmplitude extends Component { + constructor(config) { + + super(config); + + this.a = this.a || Math.random(); + this.b = this.b || Math.random(); + this.c = this.c || Math.random(); + } +}; diff --git a/lib/components/triple_frequency.js b/lib/components/triple_frequency.js index aa768e3..1f118b9 100644 --- a/lib/components/triple_frequency.js +++ b/lib/components/triple_frequency.js @@ -5,8 +5,8 @@ export default class TripleFrequency extends Component { super(config); - this.a = Math.random(); - this.b = Math.random(); - this.c = Math.random(); + this.a = this.a || Math.random(); + this.b = this.b || Math.random(); + this.c = this.c || Math.random(); } }; diff --git a/lib/components/up.js b/lib/components/up.js new file mode 100644 index 0000000..f28cc20 --- /dev/null +++ b/lib/components/up.js @@ -0,0 +1,12 @@ +import { Component } from '@serpentity/serpentity'; + +export default class Up extends Component { + constructor(config) { + + super(config); + + this.x = this.x || 0; + this.y = this.y || 1; + this.z = this.z || 0; + } +}; diff --git a/lib/config.js b/lib/config.js index bb8e11e..e8fa3c9 100644 --- a/lib/config.js +++ b/lib/config.js @@ -1,3 +1,4 @@ export const canvasId = 'lissajous'; +export const settingsId = 'settings'; export const fps = 30; diff --git a/lib/factories/curves.js b/lib/factories/curves.js index d9f0f47..99bc588 100644 --- a/lib/factories/curves.js +++ b/lib/factories/curves.js @@ -1,6 +1,7 @@ import { Entity } from '@serpentity/serpentity'; import Position from '@serpentity/components.position'; import TripleFrequency from '../components/triple_frequency'; +import TripleAmplitude from '../components/triple_amplitude'; import Color from '../components/color'; export function lissajousCurve() { @@ -8,6 +9,7 @@ export function lissajousCurve() { const entity = new Entity(); entity.addComponent(new Position()); entity.addComponent(new TripleFrequency()); + entity.addComponent(new TripleAmplitude()); entity.addComponent(new Color()); return entity; diff --git a/lib/factories/global.js b/lib/factories/global.js new file mode 100644 index 0000000..c601bdb --- /dev/null +++ b/lib/factories/global.js @@ -0,0 +1,33 @@ +import { Entity } from '@serpentity/serpentity'; +import Position from '@serpentity/components.position'; +import EulerAngle from '@serpentity/components.euler_angle'; +import Velocity from '@serpentity/components.velocity'; +import Radius from '../components/radius'; +import Up from '../components/up'; +import Configuration from '../components/configuration'; + +export function configuration() { + + const entity = new Entity(); + entity.addComponent(new Configuration()); + + return entity; +} + +export function camera() { + + const entity = new Entity(); + entity.addComponent(new Position()); + entity.addComponent(new EulerAngle()); + entity.addComponent(new Velocity({ + x: 0, + y: Math.PI / 180, + z: 0, + })); + entity.addComponent(new Radius({ + radius: 5 + })); + entity.addComponent(new Up()); + + return entity; +} diff --git a/lib/factories/ui.js b/lib/factories/ui.js new file mode 100644 index 0000000..27ff6eb --- /dev/null +++ b/lib/factories/ui.js @@ -0,0 +1,28 @@ +export function settingsContainer({id, label, level=2}) { + + const container = document.createElement('div'); + container.id = id; + container.innerHTML = `<h${level}>${label}</h${level}>`; + return container; +}; + +export function slider({min, max, step, get, set, label = '', className}) { + + const sliderContainer = document.createElement('div'); + sliderContainer.classList.add('slider'); + sliderContainer.classList.add(className); + const labelElement = document.createElement('label'); + labelElement.innerHTML = label; + const slider = document.createElement('input'); + slider.type = 'range'; + slider.min = min; + slider.max = max; + slider.step = step; + slider.value = get().toString(); + + slider.addEventListener('input', () => set(slider.value)); + + sliderContainer.appendChild(labelElement); + sliderContainer.appendChild(slider); + return sliderContainer; +} diff --git a/lib/main.js b/lib/main.js index 6a2ea8f..6018957 100644 --- a/lib/main.js +++ b/lib/main.js @@ -1,8 +1,18 @@ import Serpentity from '@serpentity/serpentity'; +import { canvasId, settingsId, fps } from './config'; + +// Systems +import CameraRotator from './systems/camera_rotator'; import WebGLRenderer from './systems/webgl_renderer'; import LissajousPositionUpdater from './systems/lissajous_position_updater'; +import CameraAdjuster from './systems/camera_adjuster'; +import FrequencyAdjuster from './systems/frequency_adjuster'; +import AmplitudeAdjuster from './systems/amplitude_adjuster'; +import GlobalAdjuster from './systems/global_adjuster'; + +// Factories import { lissajousCurve } from './factories/curves'; -import { canvasId, fps } from './config'; +import { camera, configuration } from './factories/global'; const internals = { @@ -16,12 +26,26 @@ const internals = { // Create entities const engine = new Serpentity(); - // Add Systems - engine.addSystem(new LissajousPositionUpdater(canvasId)); - engine.addSystem(new WebGLRenderer(canvasId)); - // Add Entities + engine.addEntity(camera()); engine.addEntity(lissajousCurve()); + engine.addEntity(configuration()); + + // Select elements + const canvas = document.getElementById(canvasId); + const settings = document.getElementById(settingsId); + + // Add Systems + engine.addSystem(new CameraRotator()); + engine.addSystem(new LissajousPositionUpdater()); + engine.addSystem(new WebGLRenderer(canvas)); + + // IMPROVEMENT NOTE: I believe adjusters can be generalized further. + // We could potentially have a factory for this. + engine.addSystem(new GlobalAdjuster(settings)); + engine.addSystem(new CameraAdjuster(settings)); + engine.addSystem(new FrequencyAdjuster(settings)); + engine.addSystem(new AmplitudeAdjuster(settings)); internals.engine = engine; }, diff --git a/lib/nodes/ample.js b/lib/nodes/ample.js new file mode 100644 index 0000000..e48d250 --- /dev/null +++ b/lib/nodes/ample.js @@ -0,0 +1,7 @@ +import TripleAmplitude from '../components/triple_amplitude'; +import { Node } from '@serpentity/serpentity'; + +export default class Ample extends Node {}; +Ample.types = { + amplitude: TripleAmplitude +} diff --git a/lib/nodes/cameras.js b/lib/nodes/cameras.js new file mode 100644 index 0000000..56072d3 --- /dev/null +++ b/lib/nodes/cameras.js @@ -0,0 +1,15 @@ +import Position from '@serpentity/components.position'; +import EulerAngle from '@serpentity/components.euler_angle'; +import Velocity from '@serpentity/components.velocity'; +import Radius from '../components/radius'; +import Up from '../components/up'; +import { Node } from '@serpentity/serpentity'; + +export default class Cameras extends Node {}; +Cameras.types = { + position: Position, + angle: EulerAngle, + velocity: Velocity, + radius: Radius, + up: Up +} diff --git a/lib/nodes/configurable.js b/lib/nodes/configurable.js new file mode 100644 index 0000000..650f131 --- /dev/null +++ b/lib/nodes/configurable.js @@ -0,0 +1,7 @@ +import Configuration from '../components/configuration'; +import { Node } from '@serpentity/serpentity'; + +export default class Configurable extends Node {}; +Configurable.types = { + configuration: Configuration, +} diff --git a/lib/nodes/frequent.js b/lib/nodes/frequent.js new file mode 100644 index 0000000..de8de92 --- /dev/null +++ b/lib/nodes/frequent.js @@ -0,0 +1,7 @@ +import TripleFrequency from '../components/triple_frequency'; +import { Node } from '@serpentity/serpentity'; + +export default class Frequent extends Node {}; +Frequent.types = { + frequency: TripleFrequency +} diff --git a/lib/nodes/lissajous_curve.js b/lib/nodes/lissajous_curve.js index 402aea6..55179e8 100644 --- a/lib/nodes/lissajous_curve.js +++ b/lib/nodes/lissajous_curve.js @@ -1,9 +1,11 @@ import Position from '@serpentity/components.position'; import TripleFrequency from '../components/triple_frequency'; +import TripleAmplitude from '../components/triple_amplitude'; import { Node } from '@serpentity/serpentity'; export default class LissajousCurve extends Node {}; LissajousCurve.types = { position: Position, - frequency: TripleFrequency + frequency: TripleFrequency, + amplitude: TripleAmplitude } diff --git a/lib/systems/amplitude_adjuster.js b/lib/systems/amplitude_adjuster.js new file mode 100644 index 0000000..71f7277 --- /dev/null +++ b/lib/systems/amplitude_adjuster.js @@ -0,0 +1,64 @@ +import { System } from '@serpentity/serpentity'; +import Ample from '../nodes/ample'; +import { settingsContainer, slider } from '../factories/ui'; + +const internals = { + symbols: { + a: '𝛢', + b: '𝛣', + c: '𝛧' + } +}; + +export default class AmplitudeAdjuster extends System { + + constructor(container) { + + super(); + this.container = container; + } + + added(engine){ + + this.nodes = engine.getNodes(Ample); + this.adjusterContainer = settingsContainer({ + id: 'amplitude-adjuster', + label: 'Amplitude' + }); + + let i = 0; + for (const node of this.nodes) { + const nodeElement = settingsContainer({ + id: `amplitude-adjuster-${i}`, + label: `ɣ${i + 1}`, + level: 3 + }); + + ['a', 'b', 'c'].forEach(key => { + nodeElement.appendChild(slider({ + min: '0', + max: '1', + step: '0.01', + label: internals.symbols[key], + className: `amplitude`, + get: () => node.amplitude[key].toString(), + set: (value) => (node.amplitude[key] = parseFloat(value)) + })); + }); + + this.adjusterContainer.appendChild(nodeElement); + ++i; + } + + this.container.appendChild(this.adjusterContainer); + } + + removed(){ + + this.container.removeChild(this.adjusterContainer); + delete this.adjusterContainer; + delete this.nodes; + } + + update(){} +}; diff --git a/lib/systems/camera_adjuster.js b/lib/systems/camera_adjuster.js new file mode 100644 index 0000000..3b6ea41 --- /dev/null +++ b/lib/systems/camera_adjuster.js @@ -0,0 +1,74 @@ +import { System } from '@serpentity/serpentity'; +import Cameras from '../nodes/cameras'; +import { settingsContainer, slider } from '../factories/ui'; + +const internals = { + symbols: { + x: '𝜃', + y: '𝜓', + z: '𝜙' + } +}; + +export default class CameraAdjuster extends System { + + constructor(container) { + + super(); + this.container = container; + } + + added(engine){ + + this.nodes = engine.getNodes(Cameras); + this.adjusterContainer = settingsContainer({ + id: 'camera-adjuster', + label: 'Camera' + }) + + let i = 0; + for (const node of this.nodes) { + const nodeElement = settingsContainer({ + id: `camera-adjuster-${i}`, + label: `C${i + 1}`, + level: 3 + }); + + nodeElement.appendChild(slider({ + min: '2', + max: '10', + step: '0.1', + label: '𝑟', + className: 'radius', + get: () => node.radius.radius.toString(), + set: (value) => (node.radius.radius = parseFloat(value)) + })); + + ['x', 'y', 'z'].forEach(key => { + nodeElement.appendChild(slider({ + min: '0', + max: '0.5', + step: '0.001', + label: internals.symbols[key], + className: `rotation-${key}`, + get: () => node.velocity[key].toString(), + set: (value) => (node.velocity[key] = parseFloat(value)) + })); + }); + + this.adjusterContainer.appendChild(nodeElement); + ++i; + } + + this.container.appendChild(this.adjusterContainer); + } + + removed(){ + + this.container.removeChild(this.adjusterContainer); + delete this.adjusterContainer; + delete this.nodes; + } + + update(){} +}; diff --git a/lib/systems/camera_rotator.js b/lib/systems/camera_rotator.js new file mode 100644 index 0000000..3520f71 --- /dev/null +++ b/lib/systems/camera_rotator.js @@ -0,0 +1,49 @@ +import { mat4, vec3 } from 'gl-matrix'; +import { System } from '@serpentity/serpentity'; +import Cameras from '../nodes/cameras'; + +export default class CameraRotator extends System { + + constructor() { + + super(); + } + + added(engine){ + + this.cameras = engine.getNodes(Cameras); + } + + removed(){ + + delete this.cameras; + } + + update(dt){ + + for (const camera of this.cameras) { + + let rotationMatrix = mat4.create(); + mat4.rotateY(rotationMatrix, rotationMatrix, camera.angle.yaw); + mat4.rotateX(rotationMatrix, rotationMatrix, camera.angle.pitch); + mat4.rotateZ(rotationMatrix, rotationMatrix, camera.angle.roll); + + let eye = vec3.fromValues(0, 0, camera.radius.radius); + vec3.transformMat4(eye, eye, rotationMatrix); + + camera.position.x = eye[0]; + camera.position.y = eye[1]; + camera.position.z = eye[2]; + + let up = vec3.fromValues(0, 1, 0); + vec3.transformMat4(up, up, rotationMatrix); + camera.up.x = up[0]; + camera.up.y = up[1]; + camera.up.z = up[2]; + + camera.angle.pitch = (camera.angle.pitch + camera.velocity.x * dt / 100 + 2 * Math.PI) % (2 * Math.PI); + camera.angle.yaw = (camera.angle.yaw + camera.velocity.y * dt / 100 + 2 * Math.PI) % (2 * Math.PI); + camera.angle.roll = (camera.angle.roll + camera.velocity.z * dt / 100 + 2 * Math.PI) % (2 * Math.PI); + } + } +}; diff --git a/lib/systems/frequency_adjuster.js b/lib/systems/frequency_adjuster.js new file mode 100644 index 0000000..6aa11d4 --- /dev/null +++ b/lib/systems/frequency_adjuster.js @@ -0,0 +1,64 @@ +import { System } from '@serpentity/serpentity'; +import Frequent from '../nodes/frequent'; +import { settingsContainer, slider } from '../factories/ui'; + +const internals = { + symbols: { + a: '𝛼', + b: '𝛽', + c: '𝜁' + } +}; + +export default class FrequencyAdjuster extends System { + + constructor(container) { + + super(); + this.container = container; + } + + added(engine){ + + this.nodes = engine.getNodes(Frequent); + this.adjusterContainer = settingsContainer({ + id: 'frequency-adjuster', + label: 'Frequency' + }) + + let i = 0; + for (const node of this.nodes) { + const nodeElement = settingsContainer({ + id: `frequency-adjuster-${i}`, + label: `ɣ${i + 1}`, + level: 3 + }); + + ['a', 'b', 'c'].forEach(key => { + nodeElement.appendChild(slider({ + min: '0', + max: '1', + step: '0.01', + label: internals.symbols[key], + className: `frequency`, + get: () => node.frequency[key].toString(), + set: (value) => (node.frequency[key] = parseFloat(value)) + })); + }); + + this.adjusterContainer.appendChild(nodeElement); + ++i; + } + + this.container.appendChild(this.adjusterContainer); + } + + removed(){ + + this.container.removeChild(this.adjusterContainer); + delete this.adjusterContainer; + delete this.nodes; + } + + update(){} +}; diff --git a/lib/systems/global_adjuster.js b/lib/systems/global_adjuster.js new file mode 100644 index 0000000..7f6df91 --- /dev/null +++ b/lib/systems/global_adjuster.js @@ -0,0 +1,57 @@ +import { System } from '@serpentity/serpentity'; +import Frequent from '../nodes/configurable'; +import { settingsContainer, slider } from '../factories/ui'; + +export default class GlobalAdjuster extends System { + + constructor(container) { + + super(); + this.container = container; + } + + added(engine){ + + this.nodes = engine.getNodes(Frequent); + const container = document.getElementById('settings'); + this.adjusterContainer = settingsContainer({ + id: 'global-adjuster', + label: 'Global' + }); + + let i = 0; + for (const node of this.nodes) { + const nodeElement = settingsContainer({ + id: `global-adjuster-${i}`, + label: 'Line', + level: 3 + }); + + nodeElement.appendChild(slider({ + min: '5', + max: '2000', + step: '1', + label: '𝜆', + className: 'lineLength', + get: () => node.configuration.lineLength.toString(), + set: (value) => (node.configuration.lineLength = parseFloat(value)) + })); + + this.adjusterContainer.appendChild(nodeElement); + ++i; + } + + this.container.appendChild(this.adjusterContainer); + } + + removed(){ + + this.container.removeChild(this.adjusterContainer); + delete this.adjusterContainer; + delete this.nodes; + } + + update(){} +}; + + diff --git a/lib/systems/lissajous_position_updater.js b/lib/systems/lissajous_position_updater.js index 0f5792d..202ddc7 100644 --- a/lib/systems/lissajous_position_updater.js +++ b/lib/systems/lissajous_position_updater.js @@ -2,7 +2,7 @@ import { System } from '@serpentity/serpentity'; import LissajousCurve from '../nodes/lissajous_curve'; const internals = { - kAmplitude: 0.8, + kAmplitude: 1, kPeriod: Math.PI * 12000000 }; @@ -21,8 +21,8 @@ export default class WebGLRenderer extends System { removed(){ - this.curves = undefined; - this.time = undefined; + delete this.curves; + delete this.time; } update(dt){ @@ -30,11 +30,10 @@ export default class WebGLRenderer extends System { this.time = (this.time + dt / 100) % internals.kPeriod; for (const curve of this.curves) { - curve.position.x = this._getPosition(internals.kAmplitude, curve.frequency.a, this.time, 0); - curve.position.y = this._getPosition(internals.kAmplitude, curve.frequency.b, this.time, 0); - curve.position.z = this._getPosition(internals.kAmplitude, curve.frequency.c, this.time, 0); + curve.position.x = this._getPosition(curve.amplitude.a, curve.frequency.a, this.time, 0); + curve.position.y = this._getPosition(curve.amplitude.b, curve.frequency.b, this.time, 0); + curve.position.z = this._getPosition(curve.amplitude.c, curve.frequency.c, this.time, 0); } - console.log('UP'); } _getPosition(amplitude, frequency, time, phaseShift) { diff --git a/lib/systems/webgl_renderer.js b/lib/systems/webgl_renderer.js index 8535fde..3a92552 100644 --- a/lib/systems/webgl_renderer.js +++ b/lib/systems/webgl_renderer.js @@ -1,16 +1,34 @@ +import { mat4, vec3 } from 'gl-matrix'; import { System } from '@serpentity/serpentity'; import Drawable from '../nodes/drawable'; +import Configurable from '../nodes/configurable'; +import Cameras from '../nodes/cameras'; import { initializeShaderProgram, initializeBuffers } from '../webgl_utils'; const internals = { - kWidthRatio: 2.76, + kDefaultLineLength: 1000, + kCameraRadius: 5, + kCameraAngularVelocity: Math.PI / 180, + kFieldOfView: 45, // degrees + kNearLimit: 0.1, + kFarLimit: 100, + kWidthRatio: 1.5, kHeightRatio: 1, - kTargetVerticalResolution: 32 + Math.round(Math.random() * 1024), + kTargetVerticalResolution: 1024, kVertexShader: ` - attribute vec3 aVertexPosition; + attribute vec4 aVertexPosition; + attribute vec4 aColor; + + varying vec4 vColor; + + uniform mat4 uViewMatrix; + uniform mat4 uProjectionMatrix; + void main() { - gl_Position = vec4(aVertexPosition.xy, 0.0, 1.0); + + gl_Position = uProjectionMatrix * uViewMatrix * aVertexPosition; + vColor = aColor; gl_PointSize = 10.0; // Set the point size } `, @@ -18,25 +36,27 @@ const internals = { kFragmentShader: ` precision mediump float; - uniform vec4 uColor; + varying vec4 vColor; + void main() { - gl_FragColor = uColor; + + gl_FragColor = vColor; } ` }; export default class WebGLRenderer extends System { - constructor(canvasId) { + constructor(canvas) { super(); - this.canvasId = canvasId; + this.canvas = canvas; } added(engine){ // Set up canvas - const canvas = document.getElementById(this.canvasId); + const { canvas } = this; window.addEventListener('resize', () => this._resizeCanvas(canvas)); // Set up WebGL @@ -45,6 +65,12 @@ export default class WebGLRenderer extends System { }); this.gl = gl; + gl.clearColor(0.05882, 0.14902, 0.12157, 1); + gl.enable(gl.DEPTH_TEST); + gl.depthFunc(gl.LEQUAL); + + this.colorBuffer = gl.createBuffer(); + const shaderProgram = initializeShaderProgram( gl, internals.kVertexShader, @@ -54,10 +80,12 @@ export default class WebGLRenderer extends System { this.programInfo = { program: shaderProgram, attribLocations: { - vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition') + vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'), + vertexColor: gl.getAttribLocation(shaderProgram, 'aColor') }, uniformLocations: { - color: gl.getUniformLocation(shaderProgram, 'uColor') + projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), + viewMatrix: gl.getUniformLocation(shaderProgram, 'uViewMatrix') } }; @@ -65,11 +93,23 @@ export default class WebGLRenderer extends System { this._resizeCanvas(canvas); this.points = engine.getNodes(Drawable); + this.positions = []; + this.colors = []; + + this.configurations = engine.getNodes(Configurable); + this.cameras = engine.getNodes(Cameras); } removed(engine){ - this.points = undefined; + delete this.gl; + delete this.points; + delete this.colorBuffer; + delete this.buffers; + delete this.positions; + delete this.colors; + delete this.configurations; + delete this.cameras; } update(){ @@ -78,31 +118,100 @@ export default class WebGLRenderer extends System { gl.useProgram(programInfo.program); - { - const color = [1, 1, 1, 1]; - gl.uniform4fv(programInfo.uniformLocations.color, color); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + const fieldOfView = internals.kFieldOfView * Math.PI / 180; + const aspectRatio = internals.kWidthRatio / internals.kHeightRatio; + const projectionMatrix = mat4.create(); + + mat4.perspective( + projectionMatrix, + fieldOfView, + aspectRatio, + internals.kNearLimit, + internals.kFarLimit + ); + + gl.uniformMatrix4fv( + programInfo.uniformLocations.projectionMatrix, + false, + projectionMatrix + ); + + // We only support one camera for now. + const camera = this.cameras.nodes[0]; + if (camera != undefined) { + const eye = vec3.fromValues(camera.position.x, camera.position.y, camera.position.z); + const center = vec3.fromValues(0, 0, 0); + const up = vec3.fromValues(camera.up.x, camera.up.y, camera.up.z); + const viewMatrix = mat4.create(); + mat4.lookAt(viewMatrix, eye, center, up); + gl.uniformMatrix4fv( + programInfo.uniformLocations.viewMatrix, + false, + viewMatrix + ); } - const positions = []; + let i = 0; for (const point of this.points) { - positions.push(point.position.x, point.position.y, point.position.z); - positions.push( + this.positions[i] = this.positions[i] || []; + this.positions[i].push(point.position.x, point.position.y, point.position.z, 1); + this.positions[i].push( point.position.prevX || point.position.x, point.position.prevY || point.position.y, - point.position.prevZ || point.position.z + point.position.prevZ || point.position.z, + 1 ); point.position.prevX = point.position.x; point.position.prevY = point.position.y; point.position.prevZ = point.position.z; + + this.colors[i] = this.colors[i] || []; + this.colors[i].push( + 0.5 + point.position.z / 4 + point.position.x / 4, + 0.5 + point.position.z / 4 + point.position.y / 4, + 0.75 + point.position.z / 4, 1, + 0.5 + point.position.prevZ / 4 + point.position.prevX / 4, + 0.5 + point.position.prevZ / 4 + point.position.prevY / 4, + 0.75 + point.position.prevZ / 4,1); + + ++i; + } + + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + const colors = this.colors.flat(); + gl.bufferData(gl.ARRAY_BUFFER, + new Float32Array(colors), + gl.STATIC_DRAW); + + { + const numberOfComponents = 4; + const type = gl.FLOAT; + const normalize = false; + const stride = 0; + const offset = 0; + + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + gl.vertexAttribPointer( + programInfo.attribLocations.vertexColor, + numberOfComponents, + type, + normalize, + stride, + offset + ); + gl.enableVertexAttribArray(programInfo.attribLocations.vertexColor); } gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position); + const positions = this.positions.flat(); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); { - const numberOfComponents = 3; + const numberOfComponents = 4; const type = gl.FLOAT; const normalize = false; const stride = 0; @@ -122,20 +231,20 @@ export default class WebGLRenderer extends System { { gl.lineWidth(2); - gl.drawArrays(gl.LINES, 0, this.points.nodes.length * 2); + gl.drawArrays(gl.LINES, 0, positions.length / 4); } + + this._cullLines(); } _resizeCanvas(canvas) { - console.log('Resizing Canvas'); let width = window.innerWidth; let height = Math.round(width * internals.kHeightRatio / internals.kWidthRatio); if (window.innerHeight < height) { height = window.innerHeight; width = Math.round(height * internals.kWidthRatio / internals.kHeightRatio); - console.log(width, height); } canvas.style.width = `${width}px`; @@ -146,4 +255,16 @@ export default class WebGLRenderer extends System { this.gl.viewport(0, 0, canvas.width, canvas.height); } + + _cullLines() { + const lineLength = this.configurations.nodes[0]?.configuration.lineLength || internals.kDefaultLineLength; + + for (const [i, position] of Object.entries(this.positions)) { + this.positions[i] = position.slice(-lineLength * 8); + } + + for (const [i, color] of Object.entries(this.colors)) { + this.colors[i] = color.slice(-lineLength * 8); + } + } }; diff --git a/lib/webgl_utils.js b/lib/webgl_utils.js index 1386bf7..42bd8b6 100644 --- a/lib/webgl_utils.js +++ b/lib/webgl_utils.js @@ -25,14 +25,14 @@ export function initializeShaderProgram(gl, vertexShaderSource, fragmentShaderSo */ export function initializeBuffers(gl) { - const positionBuffer = gl.createBuffer(); + const positionBuffer = gl.createBuffer(); - gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); + gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); - return { - position: positionBuffer - }; - } + return { + position: positionBuffer + }; +} function loadShader(gl, type, source) { |