@tolokoban/tgd
Version:
ToloGameDev library for WebGL2
196 lines • 14.7 kB
JavaScript
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";
/**
* @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, factory, { roundness = 3, minRadius = 0, } = {}) {
super();
this.context = context;
this.minRadius = 0;
this.radiusMultiplier = 1;
this.radiusConstant = 1;
this.radiusSwitch = 0;
this.light = 1;
this.shiftZ = 0;
this.minRadius = minRadius;
if (roundness > 125) {
throw new Error("[TgdPainterSegments] Max roundness is 125!");
}
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(["#f00", "#0f0", "#00f"]));
const prg = new TgdProgram(context.gl, {
vert: VERT,
frag: FRAG,
});
this.prg = prg;
const { capsule, elements } = makeCapsule(roundness);
const instance = factory.makeDataset();
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, } = this;
const { gl, camera } = context;
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);
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 = [];
}
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
* @param Buv
* @param radiusMultiplierInfluenceA
* @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++;
}
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;
}
}
/**
* The capsule is a 2D shape (x,y) that will be uses
* 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,
1, 0, 0,
-1, 0, 0,
0, 0, 1,
1, 0, 1,
-1, 0, 1,
];
// 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;
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);
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);
elements.push(3, elementIndex, oldIndexB);
oldIndexB = elementIndex;
elementIndex++;
}
elements.push(0, oldIndexA, 2);
elements.push(3, 5, oldIndexB);
}
const capsule = new TgdDataset({
attOffset: "vec3",
});
capsule.set("attOffset", new Float32Array(offset));
return {
capsule,
elements: new Uint8Array(elements),
};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VnbWVudHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcGFpbnRlci9zZWdtZW50cy9zZWdtZW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sY0FBYyxDQUFBO0FBQ3pDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQTtBQUVqRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sVUFBVSxDQUFBO0FBRXpDLE9BQU8sSUFBSSxNQUFNLGlCQUFpQixDQUFBO0FBQ2xDLE9BQU8sSUFBSSxNQUFNLGlCQUFpQixDQUFBO0FBQ2xDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxjQUFjLENBQUE7QUFDM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGNBQWMsQ0FBQTtBQUN6QyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFzQm5EOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW9CRztBQUNILE1BQU0sT0FBTyxrQkFBbUIsU0FBUSxVQUFVO0lBYzlDLFlBQ3VCLE9BR2xCLEVBQ0QsT0FBdUUsRUFDdkUsRUFDSSxTQUFTLEdBQUcsQ0FBQyxFQUNiLFNBQVMsR0FBRyxDQUFDLE1BQ3VCLEVBQUU7UUFFMUMsS0FBSyxFQUFFLENBQUE7UUFWWSxZQUFPLEdBQVAsT0FBTyxDQUd6QjtRQWhCRSxjQUFTLEdBQVcsQ0FBQyxDQUFBO1FBQ3JCLHFCQUFnQixHQUFHLENBQUMsQ0FBQTtRQUNwQixtQkFBYyxHQUFHLENBQUMsQ0FBQTtRQUNsQixpQkFBWSxHQUFHLENBQUMsQ0FBQTtRQUNoQixVQUFLLEdBQUcsQ0FBQyxDQUFBO1FBQ1QsV0FBTSxHQUFHLENBQUMsQ0FBQTtRQW1CYixJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQTtRQUMxQixJQUFJLFNBQVMsR0FBRyxHQUFHLEVBQUUsQ0FBQztZQUNsQixNQUFNLElBQUksS0FBSyxDQUFDLDRD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