UNPKG

@tolokoban/tgd

Version:

ToloGameDev library for WebGL2

223 lines 18.1 kB
/* eslint-disable unicorn/no-useless-spread */ import { TgdDataset } from "./../../dataset/index.js"; import { TgdPainter } from "./../painter.js"; import { TgdVertexArray } from "./../../vao/index.js"; import FRAG from "./segments.frag"; import VERT from "./segments.vert"; import { TgdTexture2D } from "./../../texture/index.js"; import { TgdProgram } from "./../../program/index.js"; import { tgdCanvasCreatePalette } from "./../../utils/index.js"; import { TgdVec3 } from "./../../math/index.js"; /** * @example * ``` * const factory = new TgdPainterSegmentsData() * factory.add( * [0, 0, 0, .2], * [1, 0, 0, .1], * ) * factory.add( * [0, 0, 0, .2], * [0, 1, 0, .1], * ) * factory.add( * [0, 0, 0, .2], * [0, 0, 1, .1], * ) * const segments = new TgdPainterSegments( * segment, factory * ) * ``` */ export class TgdPainterSegments extends TgdPainter { constructor(context, options) { super(); this.context = context; this.minRadius = 0; this.radiusMultiplier = 1; this.radiusConstant = 1; this.radiusSwitch = 0; this.light = 1; this.shiftZ = 0; this.contrast = 0.3; this.specularIntensity = 0.4; this.specularExponent = 30; const { roundness = 3, minRadius = 0, makeDataset } = options; this.minRadius = minRadius; if (roundness > 127) { throw new Error("[TgdPainterSegments] Max roundness is 127!"); } if (roundness < 0) { throw new Error("[TgdPainterSegments] Min roundness is 0!"); } this.colorTexture = new TgdTexture2D(context) .setParams({ magFilter: "NEAREST", minFilter: "NEAREST", wrapR: "CLAMP_TO_EDGE", wrapS: "CLAMP_TO_EDGE", wrapT: "CLAMP_TO_EDGE", }) .loadBitmap(tgdCanvasCreatePalette(["#f44", "#4f4", "#44f"])); const prg = new TgdProgram(context.gl, { vert: VERT, frag: FRAG, }); this.prg = prg; const { capsule, elements } = makeCapsule(roundness); const instance = makeDataset(); // instance.debug() this.vao = new TgdVertexArray(context.gl, prg, [capsule, instance], elements); this.vertexCount = elements.length; this.instanceCount = instance.count; } delete() { this.vao.delete(); } paint(_time, _delay) { const { context, prg, vao, colorTexture, vertexCount, instanceCount, light, radiusMultiplier, radiusConstant, radiusSwitch, shiftZ, contrast, specularIntensity, specularExponent, } = this; const { gl, camera } = context; gl.disable(gl.DITHER); prg.use(); const minRadius = (this.minRadius * camera.spaceHeightAtTarget) / (camera.zoom * camera.screenHeight); prg.uniform1f("uniMinRadius", minRadius); prg.uniform1f("uniLight", light); prg.uniform1f("uniShiftZ", shiftZ); prg.uniform1f("uniRadiusMultiplier", radiusMultiplier); prg.uniform1f("uniRadiusConstant", radiusConstant); prg.uniform1f("uniRadiusSwitch", radiusSwitch); prg.uniform1f("uniContrast", contrast); prg.uniform1f("uniSpecularIntensity", specularIntensity); prg.uniform1f("uniSpecularExponent", specularExponent); colorTexture.activate(0, prg, "uniTexture"); prg.uniformMatrix4fv("uniModelViewMatrix", camera.matrixModelView); prg.uniformMatrix4fv("uniProjectionMatrix", camera.matrixProjection); vao.bind(); gl.drawElementsInstanced(gl.TRIANGLES, vertexCount, gl.UNSIGNED_BYTE, 0, instanceCount); } } export class TgdPainterSegmentsData { constructor() { this._count = 0; this.attAxyzr = []; this.attAuv = []; this.attAinfluence = []; this.attBxyzr = []; this.attBuv = []; this.attBinfluence = []; this.makeDataset = () => { const dataset = new TgdDataset({ attAxyzr: "vec4", attAuv: "vec2", attAinfluence: "float", attBxyzr: "vec4", attBuv: "vec2", attBinfluence: "float", }, { divisor: 1, }); dataset.set("attAxyzr", new Float32Array(this.attAxyzr)); dataset.set("attAuv", new Float32Array(this.attAuv)); dataset.set("attAinfluence", new Float32Array(this.attAinfluence)); dataset.set("attBxyzr", new Float32Array(this.attBxyzr)); dataset.set("attBuv", new Float32Array(this.attBuv)); dataset.set("attBinfluence", new Float32Array(this.attBinfluence)); return dataset; }; } get count() { return this._count; } /** * @param Axyzr (x,y,z) and radius of point A. * @param Bxyzr (x,y,z) and radius of point B. * @param Auv Texture coordinates for point A. * @param Buv Texture coordinates for point B. * @param radiusMultiplierInfluenceA If you put 0, the radius won't change regardless to the currently applied radius multiplicator. * @param radiusMultiplierInfluenceB */ add(Axyzr, Bxyzr, Auv = [0, 0], Buv = [0, 0], radiusMultiplierInfluenceA = 1, radiusMultiplierInfluenceB = 1) { this.attAxyzr.push(...Axyzr); this.attAuv.push(...Auv); this.attAinfluence.push(radiusMultiplierInfluenceA); this.attBxyzr.push(...Bxyzr); this.attBuv.push(...Buv); this.attBinfluence.push(radiusMultiplierInfluenceB); this._count++; } } /** * The capsule is a 2D shape (x,y) that will be used * as a pattern for the segment. * The segment will expand this template along Y axis. * The tip pointing toward +Y is called A. * The tip pointing toward -Y is called B. * The z coodinates indicates to which tip the point * is attached: 0 for A and 1 for B. */ function makeCapsule(roundness) { // prettier-ignore const offset = [ ...[0, 0, 0], // 0 ...[1, 0, 0], // 1 ...[-1, 0, 0], // 2 ...[0, 0, 1], // 3 ...[1, 0, 1], // 4 ...[-1, 0, 1], // 5 ]; // prettier-ignore const normal = [ ...[0, 0, 1], // 0 ...[1, 0, 0], // 1 ...[-1, 0, 0], // 2 ...[0, 0, 1], // 3 ...[1, 0, 0], // 4 ...[-1, 0, 0], // 5 ]; // prettier-ignore const elements = [ 0, 3, 1, 3, 4, 1, 0, 2, 5, 3, 0, 5, ]; if (roundness > 0) { let oldIndexA = 1; let oldIndexB = 4; let elementIndex = 6; // Temporary variable to prevent multiple new() calls. const n = new TgdVec3(); for (let roundnessStep = 0; roundnessStep < roundness; roundnessStep++) { const ang = (Math.PI * (roundnessStep + 1)) / (roundness + 1); const x = Math.cos(ang); const y = Math.sin(ang); // We set z to 0 because it's related to tip A. offset.push(x, y, 0); n.from([x, 0, 1 - Math.abs(x)]); //.normalize() normal.push(n.x, n.y, n.z); elements.push(0, oldIndexA, elementIndex); oldIndexA = elementIndex; elementIndex++; // We set z to 1 because it's related to tip B. offset.push(x, -y, 1); n.from([x, 0, 1 - Math.abs(x)]).normalize(); normal.push(n.x, n.y, n.z); elements.push(3, elementIndex, oldIndexB); oldIndexB = elementIndex; elementIndex++; } elements.push(0, oldIndexA, 2, 3, 5, oldIndexB); } const capsule = new TgdDataset({ attOffset: "vec3", attNormal: "vec3", }); capsule.set("attOffset", new Float32Array(offset)); capsule.set("attNormal", new Float32Array(normal)); return { capsule, elements: new Uint8Array(elements), }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VnbWVudHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcGFpbnRlci9zZWdtZW50cy5iYWNrdXAvc2VnbWVudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsOENBQThDO0FBQzlDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxjQUFjLENBQUE7QUFDekMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHNCQUFzQixDQUFBO0FBRWpELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxVQUFVLENBQUE7QUFFekMsT0FBTyxJQUFJLE1BQU0saUJBQWlCLENBQUE7QUFDbEMsT0FBTyxJQUFJLE1BQU0saUJBQWlCLENBQUE7QUFDbEMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUMzQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sY0FBYyxDQUFBO0FBQ3pDLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLFlBQVksQ0FBQTtBQUVuRCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sV0FBVyxDQUFBO0FBcUJuQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FvQkc7QUFDSCxNQUFNLE9BQU8sa0JBQW1CLFNBQVEsVUFBVTtJQWlCOUMsWUFDdUIsT0FHbEIsRUFDRCxPQUVDO1FBRUQsS0FBSyxFQUFFLENBQUE7UUFSWSxZQUFPLEdBQVAsT0FBTyxDQUd6QjtRQW5CRSxjQUFTLEdBQVcsQ0FBQyxDQUFBO1FBQ3JCLHFCQUFnQixHQUFHLENBQUMsQ0FBQTtRQUNwQixtQkFBYyxHQUFHLENBQUMsQ0FBQTtRQUNsQixpQkFBWSxHQUFHLENBQUMsQ0FBQTtRQUNoQixVQUFLLEdBQUcsQ0FBQyxDQUFBO1FBQ1QsV0FBTSxHQUFHLENBQUMsQ0FBQTtRQUNWLGFBQVEsR0FBRyxHQUFHLENBQUE7UUFDZCxzQkFBaUIsR0FBRyxHQUFHLENBQUE7UUFDdkIscUJBQWdCLEdBQUcsRUFBRSxDQUFBO1FBaUJ4QixNQUFNLEVBQUUs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