regl-shape
Version:
2D shape shader for regl
155 lines (154 loc) • 7.28 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JoinStyle = void 0;
const array_bounds_1 = __importDefault(require("array-bounds"));
const array_normalize_1 = __importDefault(require("array-normalize"));
const color_normalize_1 = __importDefault(require("color-normalize"));
const earcut_1 = __importDefault(require("earcut"));
const shaders_1 = require("./shaders");
const update_dash_texture_1 = require("./update-dash-texture");
const update_color_buffer_1 = require("./update-color-buffer");
var JoinStyle;
(function (JoinStyle) {
JoinStyle["Bevel"] = "bevel";
JoinStyle["Round"] = "round";
JoinStyle["Rect"] = "rect";
})(JoinStyle = exports.JoinStyle || (exports.JoinStyle = {}));
function default_1(regl) {
const shaders = shaders_1.createShaders(regl);
let shapeCount = 0;
return {
createShape(points, initialPartialProps) {
const id = shapeCount;
shapeCount++;
const normPoints = new Float64Array(points.length);
const pointsData = new Float64Array(points.length + 6);
const pointsDataFloat32 = new Float32Array(pointsData.length);
const pointsDataFloat32Fract = new Float32Array(pointsData.length);
const colorData = new Uint8Array(2 * points.length + 4);
const colorBuffer = regl.buffer({
usage: "dynamic",
type: "uint8",
data: colorData,
});
const positionBuffer = regl.buffer({
usage: "dynamic",
type: "float",
data: pointsDataFloat32,
});
const positionFractBuffer = regl.buffer({
usage: "dynamic",
type: "float",
data: pointsDataFloat32Fract,
});
const dashTexture = regl.texture({
channels: 1,
data: new Uint8Array([255]),
width: 1,
height: 1,
mag: "linear",
min: "linear",
});
return (partialProps) => {
const props = Object.assign(Object.assign({ count: Math.floor(points.length / 2), color: "white", fill: null, thickness: 1, dashes: null, join: JoinStyle.Bevel, miterLimit: 1, close: false, opacity: 1, overlay: false, range: [-1, -1, 1, 1], viewport: {
x: 0,
y: 0,
width: regl._gl.drawingBufferWidth,
height: regl._gl.drawingBufferHeight,
}, depth: -0.01 * id }, initialPartialProps), partialProps);
let { count, color, close, join, range, dashes, fill } = props;
// update position buffers
const flatCount = 2 * count;
const bounds = array_bounds_1.default(points.length > flatCount ? points.slice(0, flatCount) : points, 2);
normPoints.set(points);
array_normalize_1.default(normPoints, 2, bounds);
const startIsEnd = points[0] === points[flatCount - 2] &&
points[1] === points[flatCount - 1];
// rotate first segment join
if (close) {
if (startIsEnd) {
pointsData[0] = normPoints[flatCount - 4];
pointsData[1] = normPoints[flatCount - 3];
}
else {
pointsData[0] = normPoints[flatCount - 2];
pointsData[1] = normPoints[flatCount - 1];
}
}
else {
pointsData[0] = normPoints[0];
pointsData[1] = normPoints[1];
}
pointsData.set(normPoints, 2);
// add last segment
if (close) {
// ignore coinciding start/end
if (startIsEnd) {
pointsData[flatCount + 2] = normPoints[2];
pointsData[flatCount + 3] = normPoints[3];
count--;
}
else {
pointsData[flatCount + 2] = normPoints[0];
pointsData[flatCount + 3] = normPoints[1];
pointsData[flatCount + 4] = normPoints[2];
pointsData[flatCount + 5] = normPoints[3];
}
}
// add stub
else {
pointsData[flatCount + 2] = normPoints[flatCount - 2];
pointsData[flatCount + 3] = normPoints[flatCount - 1];
pointsData[flatCount + 4] = normPoints[flatCount - 2];
pointsData[flatCount + 5] = normPoints[flatCount - 1];
}
pointsDataFloat32.set(pointsData);
for (let i = 0; i < flatCount; i++)
pointsDataFloat32Fract[i] = pointsData[i] - pointsDataFloat32[i];
positionBuffer.subdata(pointsDataFloat32);
positionFractBuffer.subdata(pointsDataFloat32Fract);
const boundsW = bounds[2] - bounds[0];
const boundsH = bounds[3] - bounds[1];
const rangeW = range[2] - range[0];
const rangeH = range[3] - range[1];
const scale = [boundsW / rangeW, boundsH / rangeH];
const translate = [
-range[0] / rangeW + bounds[0] / rangeW || 0,
-range[1] / rangeH + bounds[1] / rangeH || 0,
];
const scale32 = new Float32Array(scale);
const scaleFract = [scale[0] - scale32[0], scale[1] - scale32[1]];
const translate32 = new Float32Array(translate);
const translateFract = [
translate[0] - translate32[0],
translate[1] - translate32[1],
];
const dashLength = dashes
? update_dash_texture_1.updateDashTextureAndGetLength(dashTexture, dashes)
: 1;
if (color)
update_color_buffer_1.updateColorBuffer(colorBuffer, colorData, color, count);
const renderProps = Object.assign(Object.assign({}, props), { translate,
translateFract,
scale,
scaleFract,
colorBuffer,
positionBuffer,
positionFractBuffer,
dashLength,
dashTexture, triangles: fill ? earcut_1.default(points) : null, fillColor: fill ? color_normalize_1.default(fill, "uint8") : null });
regl._refresh();
if (fill)
shaders.fill(renderProps);
if (join === JoinStyle.Rect)
shaders.rect(renderProps);
else
shaders.miter(renderProps);
};
},
};
}
exports.default = default_1;