import { Vec4 } from "./common.js"; export function fullscreenCanvas(gfx, id) { const canvas = document.getElementById(id); canvas.width = window.innerWidth; canvas.height = window.innerHeight; gfx.ctx.viewport(0, 0, canvas.width, canvas.height); } function createShader(ctx, type, source) { var shader = ctx.createShader(type); if (!shader) { throw new Error("Couldn't create shader: " + type); } ctx.shaderSource(shader, source); ctx.compileShader(shader); var success = ctx.getShaderParameter(shader, ctx.COMPILE_STATUS); if (!success) { console.log(ctx.getShaderInfoLog(shader)); ctx.deleteShader(shader); throw new Error("Couldn't compile shader: " + type); } return shader; } function createProgram(ctx, vertexShaderSource, fragmentShaderSource) { var program = ctx.createProgram(); if (vertexShaderSource !== null) { const vs = createShader(ctx, ctx.VERTEX_SHADER, vertexShaderSource); ctx.attachShader(program, vs); } if (fragmentShaderSource !== null) { const fs = createShader(ctx, ctx.FRAGMENT_SHADER, fragmentShaderSource); ctx.attachShader(program, fs); } ctx.linkProgram(program); var success = ctx.getProgramParameter(program, ctx.LINK_STATUS); if (!success) { console.log(ctx.getProgramInfoLog(program)); ctx.deleteProgram(program); throw new Error("Failed to create program!"); } return program; } export class Graphics { ctx; program; attribs = new Map(); uniforms = new Map(); vao; constructor(ctx, vs, fs) { this.ctx = ctx; this.program = createProgram(ctx, vs, fs); this.vao = ctx.createVertexArray(); ctx.bindVertexArray(this.vao); ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.useProgram(this.program); } clear(r, g, b, a) { this.ctx.clearColor(r, g, b, a); this.ctx.clear(this.ctx.COLOR_BUFFER_BIT); } createAttribute(name) { const attrib = new Attribute(this.ctx, this.program, name); this.attribs.set(name, attrib); return attrib; } getAttribute(name) { const attrib = this.attribs.get(name); if (attrib === undefined) throw new Error("Tried to get uninitialized attribute: " + name); return attrib; } createUniform(name) { const loc = this.ctx.getUniformLocation(this.program, name); if (loc === null) throw new Error("Couldn't get location for uniform: " + name); this.uniforms.set(name, loc); } getUniform(name) { const loc = this.uniforms.get(name); if (loc === undefined) throw new Error("Tried to get uninitialized uniform: " + name); return loc; } } export class Attribute { loc; buffer; // TODO: maybe use undefined as default value? size = 0; type = 0; normalized = false; stride = 0; offset = 0; constructor(ctx, program, name) { this.loc = ctx.getAttribLocation(program, name); this.buffer = ctx.createBuffer(); } format(size, type, normalized, stride, offset) { this.size = size; this.type = type; this.normalized = normalized; this.stride = stride; this.offset = offset; } data(ctx, data, usage) { ctx.enableVertexAttribArray(this.loc); ctx.bindBuffer(ctx.ARRAY_BUFFER, this.buffer); ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(data), usage); ctx.vertexAttribPointer(this.loc, this.size, this.type, this.normalized, this.stride, this.offset); } } export class Texture { tex; constructor(tex) { this.tex = tex; } static async load(ctx, path) { let image = await loadTexture(path); let tex = ctx.createTexture(); ctx.bindTexture(ctx.TEXTURE_2D, tex); ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_NEAREST); ctx.generateMipmap(ctx.TEXTURE_2D); ctx.bindTexture(ctx.TEXTURE_2D, null); return new Texture(tex); } bind(gfx) { gfx.ctx.uniform1i(gfx.getUniform("u_isTex"), 1); gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, this.tex); } unbind(gfx) { gfx.ctx.bindTexture(gfx.ctx.TEXTURE_2D, null); gfx.ctx.uniform1i(gfx.getUniform("u_isTex"), 0); } } async function loadTexture(path) { return new Promise(resolve => { const img = new Image(); img.addEventListener("load", () => { resolve(img); }); img.src = path; }); } export class Camera { dt = 0; position; movement; constructor(position) { this.position = position; this.movement = new Vec4(0, 0, 0, 0); } update(dt) { this.dt = dt; let newPosition = this.movement.multScalarNew(this.dt); this.position.x += (newPosition.x + newPosition.y) / 2; this.position.y += newPosition.z + newPosition.w; } }