port to OOP
This commit is contained in:
parent
7e8b1ad477
commit
e33936a86b
15 changed files with 918 additions and 158 deletions
|
@ -1,12 +1,14 @@
|
|||
import { main } from "./lib/platform.js";
|
||||
import { Shader } from "./lib/shader.js";
|
||||
import { BasicPlane } from "./lib/basic-plane.js";
|
||||
import { App } from "./lib/app.js";
|
||||
|
||||
main({ fov: 20 }, (gl, core) => {
|
||||
const shader = new Shader(gl, core)
|
||||
.attach(
|
||||
gl.VERTEX_SHADER,
|
||||
`
|
||||
const app = new App({ fov: 20 });
|
||||
const gl = app.gl;
|
||||
|
||||
const shader = new Shader(app)
|
||||
.attach(
|
||||
gl.VERTEX_SHADER,
|
||||
`
|
||||
attribute vec4 aVertexPosition;
|
||||
attribute vec2 aTextureCoord;
|
||||
|
||||
|
@ -20,10 +22,10 @@ main({ fov: 20 }, (gl, core) => {
|
|||
vTextureCoord = aTextureCoord;
|
||||
}
|
||||
`
|
||||
)
|
||||
.attach(
|
||||
gl.FRAGMENT_SHADER,
|
||||
`
|
||||
)
|
||||
.attach(
|
||||
gl.FRAGMENT_SHADER,
|
||||
`
|
||||
uniform lowp float uTime;
|
||||
uniform lowp float uSinTime;
|
||||
uniform lowp float uCosTime;
|
||||
|
@ -38,22 +40,10 @@ main({ fov: 20 }, (gl, core) => {
|
|||
gl_FragColor = clamp(gl_FragColor, 0.0, 1.0);
|
||||
}
|
||||
`
|
||||
)
|
||||
.link();
|
||||
)
|
||||
.link();
|
||||
|
||||
const plane = new BasicPlane(gl, core);
|
||||
plane.attachShader(shader);
|
||||
const plane = new BasicPlane(app);
|
||||
plane.attachShader(shader);
|
||||
|
||||
const render = () => {
|
||||
core.clear();
|
||||
plane.draw2D();
|
||||
|
||||
if (gl.getError() !== gl.NO_ERROR) {
|
||||
throw new Error("WebGL error");
|
||||
}
|
||||
|
||||
requestAnimationFrame(render);
|
||||
};
|
||||
|
||||
requestAnimationFrame(render);
|
||||
});
|
||||
app.loop();
|
||||
|
|
92
html/lib/app.js
Normal file
92
html/lib/app.js
Normal file
|
@ -0,0 +1,92 @@
|
|||
export class App {
|
||||
constructor(
|
||||
config = {
|
||||
fov: 45,
|
||||
}
|
||||
) {
|
||||
this.registry = {
|
||||
onStart: [],
|
||||
onUpdate: [],
|
||||
onBeforeUpdate: [],
|
||||
};
|
||||
|
||||
this.config = config;
|
||||
this.canvas = document.querySelector("canvas");
|
||||
this.canvas.width = window.innerWidth;
|
||||
this.canvas.height = window.innerHeight;
|
||||
this.gl = this.canvas.getContext("webgl");
|
||||
|
||||
if (this.gl === null) {
|
||||
document.querySelector(
|
||||
"main"
|
||||
).innerHTML = `<div><i>your browser didn't let me set up webgl</i></div>`;
|
||||
throw new Error(
|
||||
"Unable to initialize WebGL. Your browser or machine may not support it."
|
||||
);
|
||||
}
|
||||
|
||||
const gl = this.gl;
|
||||
|
||||
const fieldOfView = (this.config.fov * Math.PI) / 180; // in radians
|
||||
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
|
||||
const zNear = 0.1;
|
||||
const zFar = 100.0;
|
||||
const projectionMatrix = glMatrix.mat4.create();
|
||||
glMatrix.mat4.perspective(
|
||||
projectionMatrix,
|
||||
fieldOfView,
|
||||
aspect,
|
||||
zNear,
|
||||
zFar
|
||||
);
|
||||
|
||||
const modelViewMatrix = glMatrix.mat4.create();
|
||||
glMatrix.mat4.translate(
|
||||
modelViewMatrix,
|
||||
modelViewMatrix,
|
||||
[-0.0, 0.0, -6.0]
|
||||
);
|
||||
|
||||
this.projectionMatrix = projectionMatrix;
|
||||
this.modelViewMatrix = modelViewMatrix;
|
||||
|
||||
this.clear();
|
||||
this.onBeforeUpdate(() => this.clear());
|
||||
}
|
||||
|
||||
clear() {
|
||||
const gl = this.gl;
|
||||
|
||||
gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
|
||||
gl.clearDepth(1.0); // Clear everything
|
||||
gl.enable(gl.DEPTH_TEST); // Enable depth testing
|
||||
gl.depthFunc(gl.LEQUAL); // Near things obscure far things
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
onStart(fn) {
|
||||
this.registry.onStart.push(fn);
|
||||
}
|
||||
|
||||
onUpdate(fn) {
|
||||
this.registry.onUpdate.push(fn);
|
||||
}
|
||||
|
||||
onBeforeUpdate(fn) {
|
||||
this.registry.onBeforeUpdate.push(fn);
|
||||
}
|
||||
|
||||
start() {
|
||||
this.registry.onStart.forEach((fn) => fn(this.gl, this));
|
||||
}
|
||||
|
||||
update() {
|
||||
this.registry.onBeforeUpdate.forEach((fn) => fn(this.gl, this));
|
||||
this.registry.onUpdate.forEach((fn) => fn(this.gl, this));
|
||||
}
|
||||
|
||||
loop() {
|
||||
this.update();
|
||||
requestAnimationFrame(() => this.loop());
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
export class BasicPlane {
|
||||
constructor(gl, core) {
|
||||
this.gl = gl;
|
||||
this.core = core;
|
||||
import { Object } from "./object.js";
|
||||
|
||||
export class BasicPlane extends Object {
|
||||
constructor(app) {
|
||||
super(app);
|
||||
|
||||
this.vertexPositions = new Float32Array([
|
||||
-1.0, -1.0, +1.0, -1.0, -1.0, +1.0, +1.0, +1.0,
|
||||
|
@ -10,53 +11,7 @@ export class BasicPlane {
|
|||
this.textureBuffer = this.initBuffer(
|
||||
new Float32Array([0, 0, 1, 0, 0, 1, 1, 1])
|
||||
);
|
||||
}
|
||||
|
||||
initBuffer(data, draw = this.gl.STATIC_DRAW) {
|
||||
const buffer = this.gl.createBuffer();
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
|
||||
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(data), draw);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
attachShader(shader) {
|
||||
this.shader = shader;
|
||||
this.vertexPosition = shader.location("aVertexPosition");
|
||||
this.textureCoord = shader.location("aTextureCoord");
|
||||
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
|
||||
this.gl.vertexAttribPointer(
|
||||
this.vertexPosition,
|
||||
2,
|
||||
this.gl.FLOAT,
|
||||
false,
|
||||
0,
|
||||
0
|
||||
);
|
||||
this.gl.enableVertexAttribArray(this.vertexPosition);
|
||||
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.textureBuffer);
|
||||
this.gl.vertexAttribPointer(
|
||||
this.textureCoord,
|
||||
2,
|
||||
this.gl.FLOAT,
|
||||
false,
|
||||
0,
|
||||
0
|
||||
);
|
||||
this.gl.enableVertexAttribArray(this.textureCoord);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
draw2D() {
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
|
||||
this.shader.activate(this.core.projectionMatrix, this.core.modelViewMatrix);
|
||||
this.gl.drawArrays(
|
||||
this.gl.TRIANGLE_STRIP,
|
||||
0,
|
||||
this.vertexPositions.length / 2
|
||||
);
|
||||
this.app.onUpdate(() => this.draw2D());
|
||||
}
|
||||
}
|
||||
|
|
64
html/lib/object.js
Normal file
64
html/lib/object.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
export class Object {
|
||||
constructor(app) {
|
||||
this.gl = app.gl;
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
initBuffer(data, draw = this.gl.STATIC_DRAW) {
|
||||
const buffer = this.gl.createBuffer();
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
|
||||
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array(data), draw);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
attachShader(shader) {
|
||||
this.shader = shader;
|
||||
this.vertexPosition = shader.location("aVertexPosition");
|
||||
this.textureCoord = shader.location("aTextureCoord");
|
||||
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
|
||||
this.gl.vertexAttribPointer(
|
||||
this.vertexPosition,
|
||||
2,
|
||||
this.gl.FLOAT,
|
||||
false,
|
||||
0,
|
||||
0
|
||||
);
|
||||
this.gl.enableVertexAttribArray(this.vertexPosition);
|
||||
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.textureBuffer);
|
||||
this.gl.vertexAttribPointer(
|
||||
this.textureCoord,
|
||||
2,
|
||||
this.gl.FLOAT,
|
||||
false,
|
||||
0,
|
||||
0
|
||||
);
|
||||
this.gl.enableVertexAttribArray(this.textureCoord);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
draw2D() {
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
|
||||
this.shader.activate(this.app.projectionMatrix, this.app.modelViewMatrix);
|
||||
this.gl.drawArrays(
|
||||
this.gl.TRIANGLE_STRIP,
|
||||
0,
|
||||
this.vertexPositions.length / 2
|
||||
);
|
||||
}
|
||||
|
||||
draw3D() {
|
||||
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
|
||||
this.shader.activate(this.app.projectionMatrix, this.app.modelViewMatrix);
|
||||
this.gl.drawArrays(
|
||||
this.gl.TRIANGLE_STRIP,
|
||||
0,
|
||||
this.vertexPositions.length / 3
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
export const clear = (gl) => {};
|
||||
|
||||
export const main = (config = { fov: 45 }, next = () => {}) => {
|
||||
const canvas = document.querySelector("canvas");
|
||||
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
|
||||
// Initialize the GL context
|
||||
const gl = canvas.getContext("webgl");
|
||||
|
||||
// Only continue if WebGL is available and working
|
||||
if (gl === null) {
|
||||
document.querySelector(
|
||||
"main"
|
||||
).innerHTML = `<div><i>your browser didn't let me set up webgl</i></div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const core = renderingCore(gl, config);
|
||||
core.clear();
|
||||
|
||||
next(gl, core);
|
||||
};
|
||||
|
||||
const renderingCore = (gl, config = {}) => {
|
||||
const fieldOfView = (config.fov * Math.PI) / 180; // in radians
|
||||
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
|
||||
const zNear = 0.1;
|
||||
const zFar = 100.0;
|
||||
const projectionMatrix = glMatrix.mat4.create();
|
||||
glMatrix.mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);
|
||||
|
||||
const modelViewMatrix = glMatrix.mat4.create();
|
||||
glMatrix.mat4.translate(modelViewMatrix, modelViewMatrix, [-0.0, 0.0, -6.0]);
|
||||
|
||||
return {
|
||||
projectionMatrix,
|
||||
modelViewMatrix,
|
||||
clear() {
|
||||
gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque
|
||||
gl.clearDepth(1.0); // Clear everything
|
||||
gl.enable(gl.DEPTH_TEST); // Enable depth testing
|
||||
gl.depthFunc(gl.LEQUAL); // Near things obscure far things
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const glMatrix = window.glMatrix;
|
|
@ -1,8 +1,8 @@
|
|||
export class Shader {
|
||||
constructor(gl, core) {
|
||||
this.gl = gl;
|
||||
this.core = core;
|
||||
this.program = gl.createProgram();
|
||||
constructor(app) {
|
||||
this.gl = app.gl;
|
||||
this.app = app;
|
||||
this.program = this.gl.createProgram();
|
||||
this.startTime = Date.now();
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue