1306 lines
44 KiB
JavaScript
1306 lines
44 KiB
JavaScript
function _defineProperty(obj, key, value) {if (key in obj) {Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });} else {obj[key] = value;}return obj;}function _classPrivateFieldSet(receiver, privateMap, value) {var descriptor = privateMap.get(receiver);if (!descriptor) {throw new TypeError("attempted to set private field on non-instance");}if (descriptor.set) {descriptor.set.call(receiver, value);} else {if (!descriptor.writable) {throw new TypeError("attempted to set read only private field");}descriptor.value = value;}return value;}function _classPrivateFieldGet(receiver, privateMap) {var descriptor = privateMap.get(receiver);if (!descriptor) {throw new TypeError("attempted to get private field on non-instance");}if (descriptor.get) {return descriptor.get.call(receiver);}return descriptor.value;}function _classStaticPrivateFieldSpecGet(receiver, classConstructor, descriptor) {if (receiver !== classConstructor) {throw new TypeError("Private static access of wrong provenance");}if (descriptor.get) {return descriptor.get.call(receiver);}return descriptor.value;}import { Vec2, Vec3, Mat2, Mat3, Mat4, Quat } from 'https://cdn.skypack.dev/wtc-math';
|
|
|
|
import gifJs from 'https://cdn.skypack.dev/gif.js';
|
|
|
|
console.clear();
|
|
|
|
// Determine whether a number is a power of 2
|
|
function powerOf2(v) {
|
|
return v && !(v & v - 1);
|
|
}
|
|
// Return the next greatest power of 2
|
|
function nextPow2(v) {
|
|
v--;
|
|
v |= v >> 1;
|
|
v |= v >> 2;
|
|
v |= v >> 4;
|
|
v |= v >> 8;
|
|
v |= v >> 16;
|
|
v++;
|
|
return v;
|
|
}
|
|
// Update a provided image to the nearest power of 2 in size.
|
|
const pow2Image = c => {
|
|
const newWidth = powerOf2(c.width) ? c.width : nextPow2(c.width);
|
|
const newHeight = powerOf2(c.height) ? c.height : nextPow2(c.height);
|
|
const _c = document.createElement('canvas');
|
|
const ctx = _c.getContext('2d');
|
|
_c.width = newWidth;
|
|
_c.height = newHeight;
|
|
ctx.drawImage(c, 0, 0, newWidth, newHeight);
|
|
return _c;
|
|
};
|
|
const asyncImageLoad = function (img, src) {
|
|
return new Promise((resolve, reject) => {
|
|
img.onload = () => resolve(img);
|
|
img.onerror = reject;
|
|
img.src = src;
|
|
});
|
|
};
|
|
const glEnumToString = function () {
|
|
const haveEnumsForType = {};
|
|
const enums = {};
|
|
|
|
function addEnums(gl) {
|
|
const type = gl.constructor.name;
|
|
if (!haveEnumsForType[type]) {
|
|
for (const key in gl) {
|
|
if (typeof gl[key] === 'number') {
|
|
const existing = enums[gl[key]];
|
|
enums[gl[key]] = existing ? `${existing} | ${key}` : key;
|
|
}
|
|
}
|
|
haveEnumsForType[type] = true;
|
|
}
|
|
}
|
|
|
|
return function glEnumToString(gl, value) {
|
|
addEnums(gl);
|
|
return enums[value] || (typeof value === 'number' ? `0x${value.toString(16)}` : value);
|
|
};
|
|
}();
|
|
const addExtensions = ctx => {
|
|
// Set up the extensions
|
|
ctx.getExtension('OES_standard_derivatives');
|
|
ctx.getExtension('EXT_shader_texture_lod');
|
|
ctx.getExtension('OES_texture_float');
|
|
ctx.getExtension('WEBGL_color_buffer_float');
|
|
ctx.getExtension('OES_texture_float_linear');
|
|
ctx.getExtension('EXT_color_buffer_float');
|
|
};
|
|
function createContext(c, opt_attribs, params) {
|
|
const ctx = c.getContext("webgl", params) || this._el.getContext("experimental-webgl", params);
|
|
|
|
addExtensions(ctx);
|
|
|
|
return ctx;
|
|
}
|
|
|
|
const quatToMat4 = q => {
|
|
if (q.array) q = q.array; // This just transforms a provided vector into to an array.
|
|
|
|
if (q instanceof Array && q.length >= 4) {
|
|
const [x, y, z, w] = q;
|
|
const [x2, y2, z2] = q.map(x => x * 2.);
|
|
|
|
const xx = x * x2,
|
|
yx = y * x2,
|
|
yy = y * y2,
|
|
zx = z * x2,
|
|
zy = z * y2,
|
|
zz = z * z2,
|
|
wx = w * x2,
|
|
wy = w * y2,
|
|
wz = w * z2;
|
|
|
|
return new Mat4(
|
|
1 - yy - zz, yx - wz, zx + wy, 0,
|
|
yx + wz, 1 - xx - zz, zy - wx, 0,
|
|
zx - wy, zy + wx, 1 - xx - yy, 0,
|
|
0, 0, 0, 1);
|
|
|
|
}
|
|
};var _blending = new WeakMap();var _blendingEnabled = new WeakMap();var _buffers = new WeakMap();
|
|
|
|
class Renderer {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(canvas, options) {_defineProperty(this, "isWebgl2", false);_blending.set(this, { writable: true, value: void 0 });_blendingEnabled.set(this, { writable: true, value: false });_buffers.set(this, { writable: true, value: [] });
|
|
options = Object.assign({}, _classStaticPrivateFieldSpecGet(Renderer, Renderer, _defaultOptions), options);
|
|
this.width = options.width;
|
|
this.height = options.height;
|
|
this.pxRatio = options.pxRatio;
|
|
this.clearing = options.clearing;
|
|
this.depthTesting = options.depthTesting;
|
|
this.canvas = canvas || document.createElement('canvas');
|
|
this.canvas.width = this.width * this.pxRatio;
|
|
this.canvas.height = this.height * this.pxRatio;
|
|
this.premultipliedAlpha = options.premultipliedAlpha;
|
|
|
|
this.ctx = this.canvas.getContext("webgl", options) || this.canvas.getContext("experimental-webgl", options);
|
|
|
|
this.ctx.viewportWidth = this.canvas.width;
|
|
this.ctx.viewportHeight = this.canvas.height;
|
|
|
|
this.uniformResolution = new Uniform(this.ctx, 'resolution', Uniform.TYPE_V2, [this.canvas.width, this.canvas.height]);
|
|
|
|
this.addExtensions();
|
|
}
|
|
resize(w, h, ratio) {
|
|
this.width = w;
|
|
this.height = h;
|
|
this.pxRatio = ratio || this.pxRatio;
|
|
this.canvas.width = this.width * this.pxRatio;
|
|
this.canvas.height = this.height * this.pxRatio;
|
|
|
|
this.ctx.viewportWidth = this.canvas.width;
|
|
this.ctx.viewportHeight = this.canvas.height;
|
|
|
|
this.uniformResolution = new Uniform(this.ctx, 'resolution', Uniform.TYPE_V2, [this.canvas.width, this.canvas.height]);
|
|
}
|
|
setViewport(dimensions) {
|
|
let w = this.width * this.pxRatio;
|
|
let h = this.height * this.pxRatio;
|
|
if (dimensions) {
|
|
w = dimensions[0];
|
|
h = dimensions[1];
|
|
}
|
|
this.ctx.viewport(0, 0, w, h);
|
|
this.uniformResolution = new Uniform(this.ctx, 'resolution', Uniform.TYPE_V2, [w, h]);
|
|
}
|
|
addExtensions() {
|
|
this.ctx.getExtension('OES_standard_derivatives');
|
|
this.ctx.getExtension('EXT_shader_texture_lod');
|
|
this.ctx.getExtension('OES_texture_float');
|
|
this.ctx.getExtension('WEBGL_color_buffer_float');
|
|
this.ctx.getExtension('OES_texture_float_linear');
|
|
this.ctx.getExtension('EXT_color_buffer_float');
|
|
}
|
|
linkBuffer(buffer) {
|
|
let hasBuffer = false;
|
|
_classPrivateFieldGet(this, _buffers).forEach(b => {
|
|
if (buffer === b) hasBuffer = true;
|
|
});
|
|
if (!hasBuffer) {
|
|
this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, buffer.buffer);
|
|
this.ctx.bufferData(
|
|
this.ctx.ARRAY_BUFFER,
|
|
buffer.data,
|
|
buffer.drawType);
|
|
}
|
|
buffer.link(this.currentProgram.program);
|
|
}
|
|
setupProgram(program, buffers, attributes, uniforms) {
|
|
this.currentProgram = program;
|
|
this.ctx.useProgram(program.program);
|
|
|
|
this.premultiplied = program.premultiplied;
|
|
|
|
this.depthTesting = program.depthTesting;
|
|
|
|
|
|
if (program.blending === Program.BLENDING_NORMAL && program.transparent === false) {
|
|
this.blending = Program.BLENDING_OFF;
|
|
} else {
|
|
this.blending = program.blending;
|
|
}
|
|
|
|
this.clearColour = program.clearColour;
|
|
const a = this.clearColour[3];
|
|
// console.log('prem', this.premultipliedAlpha)
|
|
if (this.premultipliedAlpha) this.clearColour = this.clearColour.map((c, i) => c * a);
|
|
|
|
this.ctx.clearColor(...this.clearColour);
|
|
|
|
// TODO: Unlink unused buffers during this setup phase as well.
|
|
buffers.forEach(buffer => {
|
|
this.linkBuffer(buffer);
|
|
});
|
|
|
|
// this.ctx.enable(ctx.DEPTH_TEST);
|
|
if (this.depthTesting) this.ctx.enable(ctx.DEPTH_TEST);else
|
|
this.ctx.disable(ctx.DEPTH_TEST);
|
|
|
|
uniforms.forEach(uniform => {
|
|
uniform.bind(program.program);
|
|
});
|
|
this.uniformResolution.bind(program.program);
|
|
}
|
|
render(points, buffer) {
|
|
this.ctx.bindFramebuffer(this.ctx.FRAMEBUFFER, (buffer === null || buffer === void 0 ? void 0 : buffer.fb) || null);
|
|
if (this.clearing) {
|
|
this.ctx.clear(this.ctx.COLOR_BUFFER_BIT);
|
|
|
|
if (this.depthTesting) this.ctx.clear(this.ctx.DEPTH_BUFFER_BIT);
|
|
}
|
|
switch (this.currentProgram.renderType) {
|
|
case Program.RENDER_TRIANGLES:
|
|
this.ctx.drawArrays(this.ctx.TRIANGLES, 0, points);
|
|
break;
|
|
case Program.RENDER_STRIP:
|
|
this.ctx.drawArrays(this.ctx.TRIANGLE_STRIP, 0, points);
|
|
break;
|
|
case Program.RENDER_LINES:
|
|
this.ctx.drawArrays(this.ctx.LINE_STRIP, 0, points);
|
|
break;
|
|
case Program.RENDER_LINELOOP:
|
|
this.ctx.drawArrays(this.ctx.LINE_LOOP, 0, points);
|
|
break;
|
|
case Program.RENDER_POINTS:
|
|
this.ctx.drawArrays(this.ctx.POINTS, 0, points);
|
|
break;}
|
|
|
|
|
|
}
|
|
|
|
/* SETTERS AND GETTERS */
|
|
get blending() {
|
|
return _classPrivateFieldGet(this, _blending) || Program.BLENDING_NORMAL;
|
|
}
|
|
set blending(blending) {
|
|
|
|
if (blending === Renderer.BLENDING_DEBUG) {
|
|
|
|
if (!this.breakLog) {
|
|
console.log(blending, Renderer.BLENDING_OFF, this.premultiplied);
|
|
this.breakLog = true;
|
|
}
|
|
_classPrivateFieldSet(this, _blending, blending);
|
|
this.ctx.enable(this.ctx.BLEND);
|
|
this.ctx.blendFuncSeparate(this.ctx.ONE, this.ctx.ONE_MINUS_SRC_ALPHA, this.ctx.ONE, this.ctx.ONE_MINUS_SRC_ALPHA);
|
|
return;
|
|
}
|
|
|
|
_classPrivateFieldSet(this, _blending, blending);
|
|
if (blending === Renderer.BLENDING_OFF) {
|
|
this.ctx.disable(this.ctx.BLEND);
|
|
_classPrivateFieldSet(this, _blendingEnabled, false);
|
|
return;
|
|
}
|
|
if (_classPrivateFieldGet(this, _blendingEnabled) === false) {
|
|
this.ctx.enable(this.ctx.BLEND);
|
|
// this.ctx.alphaFunc(this.ctx.GL_GREATER, 0.5);
|
|
// this.ctx.enable(this.ctx.GL_ALPHA_TEST);
|
|
_classPrivateFieldSet(this, _blendingEnabled, true);
|
|
}
|
|
|
|
if (this.premultiplied) {
|
|
switch (this.blending) {
|
|
case Renderer.BLENDING_NORMAL:
|
|
this.ctx.blendFuncSeparate(this.ctx.ONE, this.ctx.ONE_MINUS_SRC_ALPHA, this.ctx.ONE, this.ctx.ONE_MINUS_SRC_ALPHA);
|
|
break;
|
|
case Renderer.BLENDING_ADDITIVE:
|
|
this.ctx.blendFunc(this.ctx.ONE, this.ctx.ONE);
|
|
break;
|
|
case Renderer.BLENDING_SUBTRACTIVE:
|
|
this.ctx.blendFuncSeparate(this.ctx.ZERO, this.ctx.ZERO, this.ctx.ONE_MINUS_SRC_COLOR, this.ctx.ONE_MINUS_SRC_ALPHA);
|
|
break;
|
|
case Renderer.BLENDING_MULTIPLY:
|
|
this.ctx.blendFuncSeparate(this.ctx.ZERO, this.ctx.SRC_COLOR, this.ctx.ZERO, this.ctx.SRC_ALPHA);
|
|
break;}
|
|
|
|
} else {
|
|
switch (this.blending) {
|
|
case Renderer.BLENDING_NORMAL:
|
|
this.ctx.blendFuncSeparate(this.ctx.SRC_ALPHA, this.ctx.ONE_MINUS_SRC_ALPHA, this.ctx.ONE, this.ctx.ONE_MINUS_SRC_ALPHA);
|
|
break;
|
|
case Renderer.BLENDING_ADDITIVE:
|
|
this.ctx.blendFunc(this.ctx.SRC_ALPHA, this.ctx.ONE);
|
|
break;
|
|
case Renderer.BLENDING_SUBTRACTIVE:
|
|
this.ctx.blendFunc(this.ctx.ZERO, this.ctx.ONE_MINUS_SRC_COLOR);
|
|
break;
|
|
case Renderer.BLENDING_MULTIPLY:
|
|
this.ctx.blendFunc(this.ctx.ZERO, this.ctx.SRC_COLOR);
|
|
break;}
|
|
|
|
}
|
|
}}var _defaultOptions = { writable: true, value: { width: 512, height: 512, pxRatio: Math.min(window.devicePixelRatio, 2), clearing: true, depthTesting: true, premultipliedAlpha: true } };_defineProperty(Renderer, "BLENDING_DEBUG", -1);_defineProperty(Renderer, "BLENDING_NORMAL", 1);_defineProperty(Renderer, "BLENDING_ADDITIVE", 2);_defineProperty(Renderer, "BLENDING_SUBTRACTIVE", 4);_defineProperty(Renderer, "BLENDING_MULTIPLY", 8);_defineProperty(Renderer, "BLENDING_OFF", 16);
|
|
|
|
class Buffer {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(ctx, data, options) {
|
|
this.ctx = ctx;
|
|
this.name = name;
|
|
options = Object.assign({}, _classStaticPrivateFieldSpecGet(Buffer, Buffer, _defaults), options);
|
|
this.attributes = options.attributes.map(a => Object.assign({}, _classStaticPrivateFieldSpecGet(Buffer, Buffer, _defaultAttribute), a));
|
|
|
|
this.normalized = options.normalized;
|
|
this.drawType = options.drawType;
|
|
this.type = options.type;
|
|
if (data instanceof Array) data = new Float32Array(data);
|
|
this.data = data;
|
|
this.buffer = ctx.createBuffer();
|
|
}
|
|
|
|
link(program, hasBuffer = false) {
|
|
let location = this.ctx.getAttribLocation(program, `a_${this.name}`);
|
|
|
|
this.attributes.forEach(attribute => {
|
|
const location = this.ctx.getAttribLocation(program, `a_${attribute.name}`);
|
|
this.ctx.vertexAttribPointer(location, attribute.numComponents, this.type, this.normalized, attribute.stride, attribute.offset);
|
|
this.ctx.enableVertexAttribArray(location);
|
|
});
|
|
}
|
|
|
|
get length() {
|
|
return this.data.length;
|
|
}}var _defaultAttribute = { writable: true, value: { numComponents: 2, offset: 0, stride: 0 } };var _defaults = { writable: true, value: { attributes: [{ name: 'position' }], normalized: false, drawType: window.WebGLRenderingContext.STATIC_DRAW, type: window.WebGLRenderingContext.FLOAT } };var _vShader = new WeakMap();var _fShader = new WeakMap();var _p = new WeakMap();var _renderType = new WeakMap();
|
|
|
|
class Program {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(ctx, vertexShaderSource, fragmentShaderSource, options = {}) {_vShader.set(this, { writable: true, value: void 0 });_fShader.set(this, { writable: true, value: void 0 });_p.set(this, { writable: true, value: void 0 });_renderType.set(this, { writable: true, value: void 0 });
|
|
options = Object.assign({}, _classStaticPrivateFieldSpecGet(Program, Program, _defaultOptions2), options);
|
|
|
|
this.ctx = ctx;
|
|
|
|
this.renderType = options.renderType;
|
|
|
|
this.clearColour = options.clearColour;
|
|
this.blending = options.blending;
|
|
this.premultiplied = options.premultiplied;
|
|
this.transparent = options.transparent;
|
|
this.depthTesting = options.depthTesting;
|
|
|
|
// Create the shaders
|
|
this.vShader = Program.createShaderOfType(this.ctx, this.ctx.VERTEX_SHADER, vertexShaderSource);
|
|
this.fShader = Program.createShaderOfType(this.ctx, this.ctx.FRAGMENT_SHADER, fragmentShaderSource);
|
|
|
|
// Create the program and link the shaders
|
|
_classPrivateFieldSet(this, _p, this.ctx.createProgram());
|
|
this.ctx.attachShader(_classPrivateFieldGet(this, _p), this.vShader);
|
|
this.ctx.attachShader(_classPrivateFieldGet(this, _p), this.fShader);
|
|
|
|
this.ctx.linkProgram(_classPrivateFieldGet(this, _p));
|
|
|
|
// Check the result of linking
|
|
var linked = this.ctx.getProgramParameter(_classPrivateFieldGet(this, _p), this.ctx.LINK_STATUS);
|
|
if (!linked) {
|
|
var error = this.ctx.getProgramInfoLog(_classPrivateFieldGet(this, _p));
|
|
console.log('Failed to link program: ' + error);
|
|
this.ctx.deleteProgram(_classPrivateFieldGet(this, _p));
|
|
this.ctx.deleteShader(this.fShader);
|
|
this.ctx.deleteShader(this.vShader);
|
|
}
|
|
}
|
|
|
|
get program() {
|
|
return _classPrivateFieldGet(this, _p);
|
|
}
|
|
|
|
/* SETTERS AND GETTERS */
|
|
|
|
set renderType(value) {
|
|
if ([
|
|
Program.RENDER_TRIANGLES,
|
|
Program.RENDER_STRIP,
|
|
Program.RENDER_LINES,
|
|
Program.RENDER_LINELOOP,
|
|
Program.RENDER_POINTS].
|
|
indexOf(value) > -1) _classPrivateFieldSet(this, _renderType, value);
|
|
}
|
|
get renderType() {
|
|
return _classPrivateFieldGet(this, _renderType);
|
|
}
|
|
|
|
/**
|
|
* Static Methods
|
|
*/
|
|
|
|
/**
|
|
* Create a shader of a given type given a context, type and source.
|
|
*
|
|
* @static
|
|
* @param {WebGLContext} ctx The context under which to create the shader
|
|
* @param {WebGLShaderType} type The shader type, vertex or fragment
|
|
* @param {string} source The shader source.
|
|
* @return {WebGLShader} The created shader
|
|
*/
|
|
static createShaderOfType(ctx, type, source) {
|
|
const shader = ctx.createShader(type);
|
|
ctx.shaderSource(shader, source);
|
|
ctx.compileShader(shader);
|
|
|
|
// Check the compile status
|
|
const compiled = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS);
|
|
if (!compiled) {
|
|
// Something went wrong during compilation; get the error
|
|
const lastError = ctx.getShaderInfoLog(shader);
|
|
console.error(`${Program.addLineNumbersWithError(source, lastError)}\nError compiling ${glEnumToString(ctx, type)}: ${lastError}`);
|
|
ctx.deleteShader(shader);
|
|
return null;
|
|
}
|
|
|
|
return shader;
|
|
}
|
|
static addLineNumbersWithError(src, log = '') {
|
|
console.log(src);
|
|
const errorRE = /ERROR:\s*\d+:(\d+)/gi;
|
|
// Note: Error message formats are not defined by any spec so this may or may not work.
|
|
const matches = [...log.matchAll(errorRE)];
|
|
const lineNoToErrorMap = new Map(matches.map((m, ndx) => {
|
|
const lineNo = parseInt(m[1]);
|
|
const next = matches[ndx + 1];
|
|
const end = next ? next.index : log.length;
|
|
const msg = log.substring(m.index, end);
|
|
return [lineNo - 1, msg];
|
|
}));
|
|
return src.split('\n').map((line, lineNo) => {
|
|
const err = lineNoToErrorMap.get(lineNo);
|
|
return `${lineNo + 1}: ${line}${err ? `\n\n^^^ ${err}` : ''}`;
|
|
}).join('\n');
|
|
}}_defineProperty(Program, "RENDER_TRIANGLES", 0);_defineProperty(Program, "RENDER_STRIP", 1);_defineProperty(Program, "RENDER_LINES", 2);_defineProperty(Program, "RENDER_LINELOOP", 4);_defineProperty(Program, "RENDER_POINTS", 8);var _defaultOptions2 = { writable: true, value: { renderType: Program.RENDER_TRIANGLES, clearColour: [1.0, 1.0, 1.0, 1.0], blending: Renderer.BLENDING_OFF, premultiplied: true, transparent: false, depthTesting: true } };var _prefix = new WeakMap();
|
|
|
|
class Uniform {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(ctx, name, type, value) {_prefix.set(this, { writable: true, value: 'u' });
|
|
this.ctx = ctx;
|
|
this.name = name;
|
|
this.type = type;
|
|
this.value = value;
|
|
}
|
|
|
|
prebind() {
|
|
|
|
}
|
|
|
|
bind(program) {
|
|
this.prebind(program);
|
|
const location = this.ctx.getUniformLocation(program, `${_classPrivateFieldGet(this, _prefix)}_${this.name}`);
|
|
switch (this.type) {
|
|
case Uniform.TYPE_INT:
|
|
if (!isNaN(this.value)) this.ctx.uniform1i(location, this.value);
|
|
break;
|
|
case Uniform.TYPE_FLOAT:
|
|
if (!isNaN(this.value)) this.ctx.uniform1f(location, this.value);
|
|
break;
|
|
case Uniform.TYPE_V2:
|
|
if (this.value instanceof Array && this.value.length === 2.) this.ctx.uniform2fv(location, this.value);
|
|
break;
|
|
case Uniform.TYPE_V3:
|
|
if (this.value instanceof Array && this.value.length === 3.) this.ctx.uniform3fv(location, this.value);
|
|
break;
|
|
case Uniform.TYPE_V4:
|
|
if (this.value instanceof Array && this.value.length === 4.) this.ctx.uniform4fv(location, this.value);
|
|
break;
|
|
case Uniform.TYPE_BOOL:
|
|
if (!isNaN(this.value)) this.ctx.uniform1i(location, this.value);
|
|
break;
|
|
case Uniform.TYPE_M2:
|
|
if (this.value instanceof Array && this.value.length === 4.) this.ctx.uniformMatrix2fv(location, false, this.value);
|
|
case Uniform.TYPE_M3:
|
|
if (this.value instanceof Array && this.value.length === 9.) this.ctx.uniformMatrix3fv(location, false, this.value);
|
|
case Uniform.TYPE_M4:
|
|
if (this.value instanceof Array && this.value.length === 16.) this.ctx.uniformMatrix4fv(location, false, this.value);
|
|
break;}
|
|
|
|
}}_defineProperty(Uniform, "TYPE_INT", 0);_defineProperty(Uniform, "TYPE_FLOAT", 1);_defineProperty(Uniform, "TYPE_V2", 2);_defineProperty(Uniform, "TYPE_V3", 3);_defineProperty(Uniform, "TYPE_V4", 4);_defineProperty(Uniform, "TYPE_BOOL", 5);_defineProperty(Uniform, "TYPE_M2", 6);_defineProperty(Uniform, "TYPE_M3", 7);_defineProperty(Uniform, "TYPE_M4", 8);var _prefix2 = new WeakMap();
|
|
|
|
class Texture extends Uniform {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(ctx, name, options) {
|
|
super(ctx, name, 0, null);_prefix2.set(this, { writable: true, value: 's' });
|
|
options = Object.assign({}, _classStaticPrivateFieldSpecGet(Texture, Texture, _defaultOptions3), options);
|
|
this.textureType = options.textureType;
|
|
this.minFilter = options.minFilter;
|
|
this.magFilter = options.magFilter;
|
|
this.makePowerOf2 = options.makePowerOf2;
|
|
this.generateMipMap = options.generateMipMap;
|
|
this.url = options.url;
|
|
this.data = options.data;
|
|
this.value = Texture.masteri++;
|
|
this.textureTarget = options.textureTarget;
|
|
}
|
|
async preload() {
|
|
const store = {};
|
|
|
|
const img = new Image();
|
|
img.crossOrigin = "anonymous";
|
|
|
|
await asyncImageLoad(img, this.url);
|
|
|
|
if (this.makePowerOf2) this.image = pow2Image(img);else
|
|
this.image = img;
|
|
|
|
// this.loadTexture(gl, n, store);
|
|
return this;
|
|
}
|
|
|
|
prebind(program) {
|
|
// Just an initialisation optimisation here.
|
|
// Hopefully this works
|
|
if (this.currentProgram === program) return;
|
|
this.currentProgram = program;
|
|
|
|
if (this.textureTarget == window.WebGLRenderingContext.TEXTURE_CUBE_MAP) {
|
|
this.ctx.activeTexture(this.ctx.TEXTURE0 + this.value);
|
|
// Create a texture.
|
|
var tex = this.ctx.createTexture();
|
|
this.ctx.bindTexture(this.ctx.TEXTURE_CUBE_MAP, tex);
|
|
this.data.forEach(faceInfo => {
|
|
const { target, img } = faceInfo;
|
|
|
|
// Upload the canvas to the cubemap face.
|
|
const level = 0;
|
|
const internalFormat = this.ctx.RGBA;
|
|
const format = this.ctx.RGBA;
|
|
const type = this.ctx.UNSIGNED_BYTE;
|
|
this.ctx.texImage2D(target, level, internalFormat, format, type, img);
|
|
});
|
|
this.ctx.generateMipmap(this.ctx.TEXTURE_CUBE_MAP);
|
|
this.ctx.texParameteri(this.ctx.TEXTURE_CUBE_MAP, this.ctx.TEXTURE_MIN_FILTER, this.ctx.LINEAR_MIPMAP_LINEAR);
|
|
return;
|
|
}
|
|
|
|
if (!this.image && !this.data) return;
|
|
|
|
if (!window.log || window.log < 3) {
|
|
window.log = window.log ? window.log + 1 : 1;
|
|
console.log('ss');
|
|
}
|
|
|
|
this.ctx.activeTexture(this.ctx.TEXTURE0 + this.value);
|
|
|
|
const texture = this.ctx.createTexture(); // Create the texture object
|
|
|
|
// this.ctx.pixelStorei(this.ctx.UNPACK_FLIP_Y_WEBGL, true);
|
|
this.ctx.bindTexture(this.textureTarget, texture);
|
|
|
|
if (this.textureTarget == window.WebGLRenderingContext.TEXTURE_2D) {
|
|
// Set the parameters based on the passed type
|
|
// In WebGL images are wrapped by default, so we don't need to check for that
|
|
if (this.textureType === Texture.IMAGETYPE_MIRROR) {
|
|
this.ctx.texParameteri(this.textureTarget, this.ctx.TEXTURE_WRAP_S, this.ctx.MIRRORED_REPEAT);
|
|
this.ctx.texParameteri(this.textureTarget, this.ctx.TEXTURE_WRAP_T, this.ctx.MIRRORED_REPEAT);
|
|
} else if (this.textureType === Texture.IMAGETYPE_REGULAR) {
|
|
this.ctx.texParameteri(this.textureTarget, this.ctx.TEXTURE_WRAP_S, this.ctx.CLAMP_TO_EDGE);
|
|
this.ctx.texParameteri(this.textureTarget, this.ctx.TEXTURE_WRAP_T, this.ctx.CLAMP_TO_EDGE);
|
|
}
|
|
|
|
this.ctx.texParameteri(this.textureTarget, this.ctx.TEXTURE_MIN_FILTER, this.minFilter);
|
|
this.ctx.texParameteri(this.textureTarget, this.ctx.TEXTURE_MAG_FILTER, this.magFilter);
|
|
|
|
// Upload the image into the texture.
|
|
if (this.data) {
|
|
this.ctx.texImage2D(this.textureTarget, 0, this.ctx.RGBA, this.ctx.RGBA, this.ctx.UNSIGNED_BYTE, this.data);
|
|
} else {
|
|
this.ctx.texImage2D(this.textureTarget, 0, this.ctx.RGBA, this.ctx.RGBA, this.ctx.UNSIGNED_BYTE, this.image);
|
|
}
|
|
}
|
|
|
|
|
|
if (!window.log1 || window.log1 < 3) {
|
|
window.log1 = window.log1 ? window.log1 + 1 : 1;
|
|
console.log(this.textureTarget, this.ctx.TEXTURE_CUBE_MAP);
|
|
}
|
|
|
|
if (this.generateMipMap) this.ctx.generateMipmap(this.textureTarget);
|
|
}}var _defaultOptions3 = { writable: true, value: { textureType: 0, minFilter: window.WebGLRenderingContext.LINEAR, magFilter: window.WebGLRenderingContext.LINEAR, makePowerOf2: false, generateMipMap: false, textureTarget: window.WebGLRenderingContext.TEXTURE_2D } };_defineProperty(Texture, "masteri", 0);_defineProperty(Texture, "IMAGETYPE_REGULAR", 0);_defineProperty(Texture, "IMAGETYPE_TILE", 1);_defineProperty(Texture, "IMAGETYPE_MIRROR", 2);var _fb = new WeakMap();var _fb2 = new WeakMap();var _activeFB = new WeakMap();var _name = new WeakMap();var _width = new WeakMap();var _height = new WeakMap();var _pxRatio = new WeakMap();var _tiling = new WeakMap();var _texdepth = new WeakMap();var _data = new WeakMap();
|
|
|
|
class FrameBuffer {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(renderer, name, options) {_fb.set(this, { writable: true, value: void 0 });_fb2.set(this, { writable: true, value: void 0 });_activeFB.set(this, { writable: true, value: void 0 });_name.set(this, { writable: true, value: void 0 });_width.set(this, { writable: true, value: void 0 });_height.set(this, { writable: true, value: void 0 });_pxRatio.set(this, { writable: true, value: void 0 });_tiling.set(this, { writable: true, value: Texture.IMAGETYPE_REGULAR });_texdepth.set(this, { writable: true, value: FrameBuffer.TEXTYPE_HALF_FLOAT_OES });_data.set(this, { writable: true, value: void 0 });
|
|
options = Object.assign({}, _classStaticPrivateFieldSpecGet(FrameBuffer, FrameBuffer, _defaultOptions4), options);
|
|
|
|
this.width = options.width;
|
|
this.height = options.height;
|
|
this.pxRatio = options.pxRatio;
|
|
this.tiling = options.tiling;
|
|
this.texdepth = options.texdepth;
|
|
this.depthTesting = options.depthTesting;
|
|
|
|
_classPrivateFieldSet(this, _name, name);
|
|
this.value = Texture.masteri++;
|
|
|
|
this.ctx = renderer.ctx;
|
|
this.renderer = renderer;
|
|
|
|
this.data = options.data;
|
|
|
|
_classPrivateFieldSet(this, _fb, this.createFrameBuffer());
|
|
_classPrivateFieldSet(this, _fb2, this.createFrameBuffer());
|
|
_classPrivateFieldSet(this, _activeFB, _classPrivateFieldGet(this, _fb));
|
|
}
|
|
resize(width, height) {
|
|
this.width = width;
|
|
this.height = height;
|
|
_classPrivateFieldSet(this, _fb, this.createFrameBuffer());
|
|
_classPrivateFieldSet(this, _fb2, this.createFrameBuffer());
|
|
_classPrivateFieldSet(this, _activeFB, _classPrivateFieldGet(this, _fb));
|
|
}
|
|
createFrameBuffer() {
|
|
const targetTexture = this.ctx.createTexture();
|
|
this.ctx.bindTexture(this.ctx.TEXTURE_2D, targetTexture);
|
|
{
|
|
// define size and format of level 0
|
|
const level = 0;
|
|
let internalFormat = this.ctx.RGBA;
|
|
const border = 0;
|
|
let format = this.ctx.RGBA;
|
|
let t;
|
|
if (this.texdepth === FrameBuffer.TEXTYPE_FLOAT) {
|
|
const e = this.ctx.getExtension('OES_texture_float');
|
|
t = this.ctx.FLOAT;
|
|
// internalFormat = this.ctx.FLOAT;
|
|
// format = this.ctx.FLOAT;
|
|
} else if (this.texdepth & FrameBuffer.TEXTYPE_HALF_FLOAT_OES) {
|
|
// t = gl.renderer.isWebgl2 ? e.HALF_FLOAT : e.HALF_FLOAT_OES;
|
|
// gl.renderer.extensions['OES_texture_half_float'] ? gl.renderer.extensions['OES_texture_half_float'].HALF_FLOAT_OES :
|
|
// gl.UNSIGNED_BYTE;
|
|
const e = this.ctx.getExtension('OES_texture_half_float');
|
|
t = this.renderer.isWebgl2 ? this.ctx.HALF_FLOAT : e.HALF_FLOAT_OES;
|
|
// format = gl.RGBA;
|
|
if (this.renderer.isWebgl2) {
|
|
internalFormat = this.ctx.RGBA16F;
|
|
}
|
|
// internalFormat = gl.RGB32F;
|
|
// format = gl.RGB32F;
|
|
// window.gl = gl
|
|
// t = e.HALF_FLOAT_OES;
|
|
} else {
|
|
t = this.ctx.UNSIGNED_BYTE;
|
|
}
|
|
const type = t;
|
|
const data = this.data;
|
|
this.ctx.texImage2D(this.ctx.TEXTURE_2D, level, internalFormat,
|
|
this.width * this.pxRatio, this.height * this.pxRatio, border,
|
|
format, type, data);
|
|
// gl.generateMipmap(gl.TEXTURE_2D);
|
|
|
|
// set the filtering so we don't need mips
|
|
this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_MIN_FILTER, this.ctx.NEAREST);
|
|
this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_MAG_FILTER, this.ctx.NEAREST);
|
|
|
|
// Set the parameters based on the passed type
|
|
if (this.tiling === Texture.IMAGETYPE_TILE) {
|
|
this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_WRAP_S, this.ctx.REPEAT);
|
|
this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_WRAP_T, this.ctx.REPEAT);
|
|
} else if (this.tiling === Texture.IMAGETYPE_MIRROR) {
|
|
this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_WRAP_S, this.ctx.MIRRORED_REPEAT);
|
|
this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_WRAP_T, this.ctx.MIRRORED_REPEAT);
|
|
} else if (this.tiling === Texture.IMAGETYPE_REGULAR) {
|
|
this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_WRAP_S, this.ctx.CLAMP_TO_EDGE);
|
|
this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_WRAP_T, this.ctx.CLAMP_TO_EDGE);
|
|
}
|
|
}
|
|
|
|
// Create and bind the framebuffer
|
|
const fb = this.ctx.createFramebuffer();
|
|
this.ctx.bindFramebuffer(this.ctx.FRAMEBUFFER, fb);
|
|
|
|
if (this.depthTesting) {
|
|
var ext = this.ctx.getExtension('WEBGL_depth_texture');
|
|
let depth = this.ctx.createTexture();
|
|
this.ctx.bindTexture(this.ctx.TEXTURE_2D, depth);
|
|
this.ctx.texImage2D(
|
|
this.ctx.TEXTURE_2D, 0, this.ctx.DEPTH_COMPONENT, this.width * this.pxRatio, this.height * this.pxRatio, 0, this.ctx.DEPTH_COMPONENT, this.ctx.UNSIGNED_SHORT, null);
|
|
this.ctx.framebufferTexture2D(this.ctx.FRAMEBUFFER, this.ctx.DEPTH_ATTACHMENT, this.ctx.TEXTURE_2D, depth, 0);
|
|
}
|
|
|
|
// attach the texture as the first color attachment
|
|
const attachmentPoint = this.ctx.COLOR_ATTACHMENT0;
|
|
const level = 0;
|
|
this.ctx.framebufferTexture2D(
|
|
this.ctx.FRAMEBUFFER,
|
|
attachmentPoint,
|
|
this.ctx.TEXTURE_2D,
|
|
targetTexture,
|
|
level);
|
|
|
|
return {
|
|
fb: fb,
|
|
frameTexture: targetTexture };
|
|
|
|
}
|
|
bind() {
|
|
// find the active texture based on the index
|
|
let uniform = this.ctx.getUniformLocation(this.renderer.currentProgram.program, `b_${_classPrivateFieldGet(this, _name)}`);
|
|
|
|
// Set the texture unit to the uniform
|
|
this.ctx.uniform1i(uniform, this.value);
|
|
this.ctx.activeTexture(this.ctx.TEXTURE0 + this.value);
|
|
// Bind the texture
|
|
this.ctx.bindTexture(this.ctx.TEXTURE_2D, _classPrivateFieldGet(this, _activeFB).frameTexture);
|
|
}
|
|
render(n) {
|
|
this.bind();
|
|
|
|
// Finally, ping-pong the texture
|
|
_classPrivateFieldSet(this, _activeFB, _classPrivateFieldGet(this, _activeFB) === _classPrivateFieldGet(this, _fb) ? _classPrivateFieldGet(this, _fb2) : _classPrivateFieldGet(this, _fb));
|
|
|
|
// this.renderer.render(n, this.#activeFB);
|
|
this.renderer.render(n, _classPrivateFieldGet(this, _activeFB), [this.width, this.height]);
|
|
}
|
|
|
|
set data(value) {
|
|
if (value instanceof Float32Array) _classPrivateFieldSet(this, _data, value);
|
|
}
|
|
get data() {
|
|
return _classPrivateFieldGet(this, _data) || null;
|
|
}
|
|
set width(value) {
|
|
if (value > 0) _classPrivateFieldSet(this, _width, value);
|
|
}
|
|
get width() {
|
|
return _classPrivateFieldGet(this, _width) || 1;
|
|
}
|
|
set height(value) {
|
|
if (value > 0) _classPrivateFieldSet(this, _height, value);
|
|
}
|
|
get height() {
|
|
return _classPrivateFieldGet(this, _height) || 1;
|
|
}
|
|
set pxRatio(value) {
|
|
if (value > 0) _classPrivateFieldSet(this, _pxRatio, value);
|
|
}
|
|
get pxRatio() {
|
|
return _classPrivateFieldGet(this, _pxRatio) || 1;
|
|
}
|
|
set tiling(value) {
|
|
if ([Texture.IMAGETYPE_REGULAR, Texture.IMAGETYPE_TILE, Texture.IMAGETYPE_MIRROR].indexOf(value) > -1) _classPrivateFieldSet(this, _tiling, value);
|
|
}
|
|
get tiling() {
|
|
return _classPrivateFieldGet(this, _tiling);
|
|
}
|
|
set texdepth(value) {
|
|
if ([FrameBuffer.TEXTYPE_FLOAT, FrameBuffer.TEXTYPE_UNSIGNED_BYTE, FrameBuffer.TEXTYPE_HALF_FLOAT_OES].indexOf(value) > -1) _classPrivateFieldSet(this, _texdepth, value);
|
|
}
|
|
get texdepth() {
|
|
return _classPrivateFieldGet(this, _texdepth);
|
|
}}var _defaultOptions4 = { writable: true, value: { width: 512, height: 512, pxRatio: Math.min(window.devicePixelRatio, 2), tiling: Texture.IMAGETYPE_REGULAR, texdepth: FrameBuffer.TEXTYPE_HALF_FLOAT_OES, data: null, depthTesting: false } };_defineProperty(FrameBuffer, "TEXTYPE_FLOAT", 0);_defineProperty(FrameBuffer, "TEXTYPE_UNSIGNED_BYTE", 1);_defineProperty(FrameBuffer, "TEXTYPE_HALF_FLOAT_OES", 2);var _fov = new WeakMap();var _aspect = new WeakMap();var _near = new WeakMap();var _far = new WeakMap();var _pos = new WeakMap();var _target = new WeakMap();var _up = new WeakMap();var _updateDebounce = new WeakMap();var _model = new WeakMap();var _view = new WeakMap();var _proj = new WeakMap();var _MVP = new WeakMap();var _u_model = new WeakMap();var _u_view = new WeakMap();var _u_proj = new WeakMap();var _u_MVP = new WeakMap();var _q = new WeakMap();var _name2 = new WeakMap();
|
|
|
|
class Camera {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(renderer, name, options) {_fov.set(this, { writable: true, value: void 0 });_aspect.set(this, { writable: true, value: void 0 });_near.set(this, { writable: true, value: void 0 });_far.set(this, { writable: true, value: void 0 });_pos.set(this, { writable: true, value: void 0 });_target.set(this, { writable: true, value: void 0 });_up.set(this, { writable: true, value: void 0 });_updateDebounce.set(this, { writable: true, value: void 0 });_model.set(this, { writable: true, value: void 0 });_view.set(this, { writable: true, value: void 0 });_proj.set(this, { writable: true, value: void 0 });_MVP.set(this, { writable: true, value: void 0 });_u_model.set(this, { writable: true, value: void 0 });_u_view.set(this, { writable: true, value: void 0 });_u_proj.set(this, { writable: true, value: void 0 });_u_MVP.set(this, { writable: true, value: void 0 });_q.set(this, { writable: true, value: void 0 });_name2.set(this, { writable: true, value: void 0 });
|
|
options = Object.assign({}, _classStaticPrivateFieldSpecGet(Camera, Camera, _defaultOptions5), options);
|
|
|
|
this.renderer = renderer;
|
|
this.ctx = renderer.ctx;
|
|
|
|
this.fov = options.fov;
|
|
this.aspect = options.aspect;
|
|
this.near = options.near;
|
|
this.far = options.far;
|
|
this.pos = options.pos;
|
|
this.target = options.target;
|
|
this.up = options.up;
|
|
|
|
this.q = new Quat();
|
|
|
|
this.name = name;
|
|
|
|
this.update(true);
|
|
}
|
|
set q(value) {
|
|
if (value instanceof Quat) {
|
|
_classPrivateFieldSet(this, _q, value);
|
|
_classPrivateFieldSet(this, _model, quatToMat4(_classPrivateFieldGet(this, _q)));
|
|
_classPrivateFieldSet(this, _u_model, new Uniform(this.ctx, 'm_model', Uniform.TYPE_M4, _classPrivateFieldGet(this, _model).array));
|
|
}
|
|
}
|
|
get q() {
|
|
return _classPrivateFieldGet(this, _q) || new Quat();
|
|
}
|
|
update(nt = false) {
|
|
clearTimeout(_classPrivateFieldGet(this, _updateDebounce));
|
|
// this.#updateDebounce = setTimeout(() => {
|
|
_classPrivateFieldSet(this, _model, new Mat4());
|
|
_classPrivateFieldSet(this, _view, Mat4.lookAt(this.pos, this.target, this.up));
|
|
_classPrivateFieldSet(this, _proj, Mat4.perspective(this.fov, this.aspect, this.near, this.far));
|
|
_classPrivateFieldSet(this, _MVP, _classPrivateFieldGet(this, _proj).multiplyNew(_classPrivateFieldGet(this, _view)).multiply(_classPrivateFieldGet(this, _model)));
|
|
|
|
_classPrivateFieldSet(this, _u_view, new Uniform(this.ctx, 'm_view', Uniform.TYPE_M4, _classPrivateFieldGet(this, _view).array));
|
|
_classPrivateFieldSet(this, _u_proj, new Uniform(this.ctx, 'm_proj', Uniform.TYPE_M4, _classPrivateFieldGet(this, _proj).array));
|
|
_classPrivateFieldSet(this, _u_MVP, new Uniform(this.ctx, 'm_MVP', Uniform.TYPE_M4, _classPrivateFieldGet(this, _MVP).array));
|
|
|
|
this.setup = true;
|
|
// }, nt ? 0 : 50);
|
|
}
|
|
|
|
set name(value) {
|
|
if (typeof value === 'string') _classPrivateFieldSet(this, _name2, value);
|
|
}
|
|
get name() {
|
|
return _classPrivateFieldGet(this, _name2) || 'camera';
|
|
}
|
|
set fov(value) {
|
|
if (!isNaN(value)) _classPrivateFieldSet(this, _fov, value);
|
|
}
|
|
get fov() {
|
|
return _classPrivateFieldGet(this, _fov);
|
|
}
|
|
set aspect(value) {
|
|
if (!isNaN(value)) _classPrivateFieldSet(this, _aspect, value);
|
|
}
|
|
get aspect() {
|
|
return _classPrivateFieldGet(this, _aspect);
|
|
}
|
|
set near(value) {
|
|
if (!isNaN(value)) _classPrivateFieldSet(this, _near, value);
|
|
}
|
|
get near() {
|
|
return _classPrivateFieldGet(this, _near);
|
|
}
|
|
set far(value) {
|
|
if (!isNaN(value)) _classPrivateFieldSet(this, _far, value);
|
|
}
|
|
get far() {
|
|
return _classPrivateFieldGet(this, _far);
|
|
}
|
|
set pos(value) {
|
|
if (value instanceof Vec3) _classPrivateFieldSet(this, _pos, value);
|
|
}
|
|
get pos() {
|
|
return _classPrivateFieldGet(this, _pos);
|
|
}
|
|
set target(value) {
|
|
if (value instanceof Vec3) _classPrivateFieldSet(this, _target, value);
|
|
}
|
|
get target() {
|
|
return _classPrivateFieldGet(this, _target);
|
|
}
|
|
set up(value) {
|
|
if (value instanceof Vec3) _classPrivateFieldSet(this, _up, value);
|
|
}
|
|
get up() {
|
|
return _classPrivateFieldGet(this, _up);
|
|
}
|
|
get u_model() {
|
|
return _classPrivateFieldGet(this, _u_model);
|
|
}
|
|
get u_view() {
|
|
return _classPrivateFieldGet(this, _u_view);
|
|
}
|
|
get u_proj() {
|
|
return _classPrivateFieldGet(this, _u_proj);
|
|
}
|
|
get u_MVP() {
|
|
return _classPrivateFieldGet(this, _u_MVP);
|
|
}
|
|
get uniforms() {
|
|
return [this.u_model, this.u_view, this.u_proj, this.u_MVP];
|
|
}}var _defaultOptions5 = { writable: true, value: { fov: 30 * Math.PI / 180, aspect: window.innerWidth / window.innerHeight, near: .5, far: 100, pos: new Vec3(3, 1, -5), target: new Vec3(0, 0, 0), up: new Vec3(0, 1, 0) } };
|
|
|
|
|
|
const dimensions = [window.innerWidth, window.innerHeight];
|
|
|
|
const canvas = document.createElement('canvas');
|
|
document.body.appendChild(canvas);
|
|
|
|
const renderer = new Renderer(canvas, { width: dimensions[0], height: dimensions[1], alpha: false, premultipliedAlpha: true, preserveDrawingBuffer: true });
|
|
const ctx = renderer.ctx;
|
|
|
|
let drawing = new Float32Array([-1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0]);
|
|
|
|
const drawBuffer = new Buffer(ctx, drawing);
|
|
|
|
const vertexShader_buffer = document.getElementById('vertexShader_buffer').innerText;
|
|
|
|
const programMain = new Program(ctx, vertexShader_buffer, document.getElementById('fragmentShader_under').innerText, {
|
|
clearColour: [.15, .15, 0.25, 1.],
|
|
renderType: Program.RENDER_STRIP });
|
|
|
|
|
|
const time = new Uniform(ctx, 'time', Uniform.TYPE_FLOAT, 100);
|
|
const uDelta = new Uniform(ctx, 'delta', Uniform.TYPE_FLOAT, 100);
|
|
const mouse = new Uniform(ctx, 'mouse', Uniform.TYPE_V2, [0., 0.]);
|
|
|
|
// const noise = new Texture(ctx, 'noise', {
|
|
// textureType: Texture.IMAGETYPE_TILE,
|
|
// url: 'https://assets.codepen.io/982762/noise.png'
|
|
// });
|
|
|
|
// Load all our textures. We only initiate the instance once all images are loaded.
|
|
const loadedTextures = {};
|
|
const textures = [
|
|
{
|
|
name: 'noise',
|
|
url: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/982762/noise.png',
|
|
type: Texture.IMAGETYPE_TILE,
|
|
img: null },
|
|
{
|
|
name: 'cube_NEGATIVE_Z',
|
|
url: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/982762/miramar_bk.jpg',
|
|
img: null,
|
|
defer: true },
|
|
{
|
|
name: 'cube_NEGATIVE_X',
|
|
url: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/982762/miramar_lf.jpg',
|
|
img: null,
|
|
defer: true },
|
|
{
|
|
name: 'cube_POSITIVE_Z',
|
|
url: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/982762/miramar_ft.jpg',
|
|
img: null,
|
|
defer: true },
|
|
{
|
|
name: 'cube_NEGATIVE_Y',
|
|
url: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/982762/miramar_dn.jpg',
|
|
img: null,
|
|
defer: true },
|
|
{
|
|
name: 'cube_POSITIVE_Y',
|
|
url: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/982762/miramar_up.jpg',
|
|
img: null,
|
|
defer: true },
|
|
{
|
|
name: 'cube_POSITIVE_X',
|
|
url: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/982762/miramar_rt.jpg',
|
|
img: null,
|
|
defer: true }];
|
|
|
|
|
|
const loadImage = function (imageObject) {
|
|
let img = document.createElement('img');
|
|
img.crossOrigin = "anonymous";
|
|
|
|
return new Promise((resolve, reject) => {
|
|
img.addEventListener('load', e => {
|
|
imageObject.img = img;
|
|
resolve(imageObject);
|
|
});
|
|
img.addEventListener('error', e => {
|
|
reject(e);
|
|
});
|
|
img.src = imageObject.url;
|
|
});
|
|
};
|
|
const loadTextures = function (textures) {
|
|
return new Promise((resolve, reject) => {
|
|
const loadTexture = pointer => {
|
|
if (pointer >= textures.length || pointer > 10) {
|
|
resolve(textures);
|
|
return;
|
|
};
|
|
const imageObject = textures[pointer];
|
|
|
|
const p = loadImage(imageObject);
|
|
p.then(
|
|
result => {
|
|
if (!result.defer) {
|
|
// twodWebGL.addTexture(result.name, result.type, result.img);
|
|
loadedTextures[result.name] = new Texture(ctx, result.name, {
|
|
textureType: result.type,
|
|
data: result.img });
|
|
|
|
}
|
|
},
|
|
error => {
|
|
console.log('error', error);
|
|
}).finally(e => {
|
|
loadTexture(pointer + 1);
|
|
});
|
|
};
|
|
loadTexture(0);
|
|
});
|
|
|
|
};
|
|
|
|
loadTextures(textures).then(
|
|
result => {
|
|
|
|
const gl = renderer.ctx;
|
|
|
|
|
|
const faceInfos = [
|
|
{ target: gl.TEXTURE_CUBE_MAP_POSITIVE_X },
|
|
{ target: gl.TEXTURE_CUBE_MAP_NEGATIVE_X },
|
|
{ target: gl.TEXTURE_CUBE_MAP_POSITIVE_Y },
|
|
{ target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Y },
|
|
{ target: gl.TEXTURE_CUBE_MAP_POSITIVE_Z },
|
|
{ target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Z }];
|
|
|
|
|
|
textures.forEach(tex => {
|
|
if (tex.name === 'cube_POSITIVE_X') {
|
|
faceInfos[4].img = tex.img;
|
|
} else if (tex.name === 'cube_NEGATIVE_X') {
|
|
faceInfos[5].img = tex.img;
|
|
} else if (tex.name === 'cube_POSITIVE_Y') {
|
|
faceInfos[3].img = tex.img;
|
|
} else if (tex.name === 'cube_NEGATIVE_Y') {
|
|
faceInfos[2].img = tex.img;
|
|
} else if (tex.name === 'cube_POSITIVE_Z') {
|
|
faceInfos[0].img = tex.img;
|
|
} else if (tex.name === 'cube_NEGATIVE_Z') {
|
|
faceInfos[1].img = tex.img;
|
|
}
|
|
});
|
|
|
|
console.log(faceInfos);
|
|
|
|
loadedTextures['env'] = new Texture(ctx, 'environment', {
|
|
textureType: result.type,
|
|
data: faceInfos,
|
|
textureTarget: gl.TEXTURE_CUBE_MAP,
|
|
generateMipMap: true });
|
|
|
|
|
|
requestAnimationFrame(run);
|
|
|
|
// gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
|
|
// gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
|
|
// twodWebGL.pushTexture('cube_env', texture, faceInfos, gl.TEXTURE_CUBE_MAP, false);
|
|
|
|
// twodWebGL.initTextures();
|
|
// // twodWebGL.render();
|
|
// twodWebGL.running = true;
|
|
},
|
|
error => {
|
|
console.log('error');
|
|
});
|
|
|
|
|
|
// noise.preload().then((n) => {
|
|
// requestAnimationFrame(run);
|
|
// });
|
|
|
|
let pointerdown = false;
|
|
let lastPos = new Vec2();
|
|
window.addEventListener('pointerdown', e => {
|
|
pointerdown = true;
|
|
lastPos = new Vec2(e.x, e.y);
|
|
});
|
|
window.addEventListener('pointerup', e => {
|
|
pointerdown = false;
|
|
});
|
|
window.addEventListener('pointermove', e => {
|
|
if (pointerdown) {
|
|
let newPos = new Vec2(e.x, e.y);
|
|
mouse.value = newPos.array;
|
|
}
|
|
});
|
|
|
|
let playing = true;
|
|
const setPlaying = value => {
|
|
playing = value;
|
|
};
|
|
|
|
let autoTransitionTimer = 0;
|
|
let timeToTransition = 0;
|
|
const setupValues = i => {
|
|
dimensions[0] = window.innerWidth;
|
|
dimensions[1] = window.innerHeight;
|
|
|
|
time.value = -10000;
|
|
};
|
|
|
|
setupValues(0);
|
|
|
|
let timeout;
|
|
window.addEventListener('resize', () => {
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(() => {
|
|
dimensions[0] = window.innerWidth;
|
|
dimensions[1] = window.innerHeight;
|
|
renderer.resize(dimensions[0], dimensions[1]);
|
|
}, 100);
|
|
});
|
|
|
|
const cam = new Uniform(renderer.ctx, 'cam', Uniform.TYPE_V2, [0, 0.]);
|
|
let pointermoving = false;
|
|
let pointerTimeout;
|
|
window.addEventListener('pointerdown', e => {
|
|
pointerdown = true;
|
|
pointerTimeout = setTimeout(() => {
|
|
pointermoving = true;
|
|
}, 200);
|
|
lastPos = new Vec2(e.x, e.y);
|
|
});
|
|
window.addEventListener('pointerup', e => {
|
|
pointerdown = false;
|
|
pointermoving = false;
|
|
clearTimeout(pointerTimeout);
|
|
});
|
|
window.addEventListener('pointermove', e => {
|
|
if (pointerdown) {
|
|
let newPos = new Vec2(e.x, e.y);
|
|
let diff = newPos.clone().subtract(lastPos);
|
|
lastPos = newPos.clone();
|
|
cam.value[0] -= diff.x * -.01;
|
|
cam.value[1] -= diff.y * -.01;
|
|
}
|
|
});
|
|
|
|
const opx = renderer.pxRatio;
|
|
let then = 0;
|
|
// let framenum = 0;
|
|
// let framesPerFrame = 10;
|
|
// let gif = new gifJs({
|
|
// workers: 2,
|
|
// quality: 10
|
|
// });
|
|
// gif.on('finished', function(blob) {
|
|
// console.log('ss')
|
|
// window.open(URL.createObjectURL(blob));
|
|
// });
|
|
|
|
// const offscreenCanvas = document.createElement("canvas");
|
|
// offscreenCanvas.className = 'osc';
|
|
// offscreenCanvas.width = canvas.width;
|
|
// offscreenCanvas.height = canvas.height;
|
|
// const osctx = offscreenCanvas.getContext("2d");
|
|
// document.body.appendChild(offscreenCanvas);
|
|
|
|
let gifDone = false;
|
|
const run = delta => {
|
|
|
|
// if(framenum < 10 * framesPerFrame) {
|
|
// if(framenum % framesPerFrame == 0) {
|
|
// // gif.addFrame(canvas, {delay: 100});
|
|
|
|
// osctx.drawImage(canvas,0,0);
|
|
|
|
// gif.addFrame(offscreenCanvas, {copy: true, delay: 100});
|
|
// // gif.addFrame(ctx, {copy: true});
|
|
// }
|
|
// framenum++;
|
|
// } else if(gifDone === false) {
|
|
// console.log(framenum)
|
|
|
|
// gif.render();
|
|
|
|
// window.gif = gif;
|
|
|
|
// gifDone = true;
|
|
// }
|
|
|
|
let now = Date.now() / 1000;
|
|
let _delta = now - then;
|
|
then = now;
|
|
|
|
if (_delta > 1000) {
|
|
requestAnimationFrame(run);
|
|
return;
|
|
}
|
|
|
|
if (playing) {
|
|
|
|
uDelta.value = Math.min(_delta, 0.5);
|
|
time.value += _delta;
|
|
|
|
// console.log(loadedTextures.noise.value);
|
|
// console.log(loadedTextures.env.value);
|
|
|
|
renderer.setViewport();
|
|
renderer.setupProgram(programMain, [drawBuffer], [], [time, mouse, loadedTextures.noise, loadedTextures.env, cam]);
|
|
renderer.render(4);
|
|
// console.log(loadedTextures)
|
|
|
|
|
|
requestAnimationFrame(run);
|
|
}
|
|
}; |