cubeforge 0.4.6 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +140 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2225,6 +2225,88 @@ function createWhiteTexture(gl) {
|
|
|
2225
2225
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
2226
2226
|
return tex;
|
|
2227
2227
|
}
|
|
2228
|
+
var SHAPE_TEX_SIZE = 128;
|
|
2229
|
+
function drawShapeOnCanvas(ctx, shape, w, h, borderRadius, starPoints, starInnerRadius) {
|
|
2230
|
+
const cx = w / 2;
|
|
2231
|
+
const cy = h / 2;
|
|
2232
|
+
switch (shape) {
|
|
2233
|
+
case "circle": {
|
|
2234
|
+
const r = Math.min(w, h) / 2;
|
|
2235
|
+
ctx.beginPath();
|
|
2236
|
+
ctx.arc(cx, cy, r, 0, Math.PI * 2);
|
|
2237
|
+
break;
|
|
2238
|
+
}
|
|
2239
|
+
case "ellipse": {
|
|
2240
|
+
ctx.beginPath();
|
|
2241
|
+
ctx.ellipse(cx, cy, w / 2, h / 2, 0, 0, Math.PI * 2);
|
|
2242
|
+
break;
|
|
2243
|
+
}
|
|
2244
|
+
case "roundedRect": {
|
|
2245
|
+
const r = Math.min(borderRadius, w / 2, h / 2);
|
|
2246
|
+
ctx.beginPath();
|
|
2247
|
+
ctx.roundRect(0, 0, w, h, r);
|
|
2248
|
+
break;
|
|
2249
|
+
}
|
|
2250
|
+
case "triangle": {
|
|
2251
|
+
ctx.beginPath();
|
|
2252
|
+
ctx.moveTo(cx, 0);
|
|
2253
|
+
ctx.lineTo(w, h);
|
|
2254
|
+
ctx.lineTo(0, h);
|
|
2255
|
+
ctx.closePath();
|
|
2256
|
+
break;
|
|
2257
|
+
}
|
|
2258
|
+
case "pentagon": {
|
|
2259
|
+
drawRegularPolygonPath(ctx, cx, cy, Math.min(w, h) / 2, 5);
|
|
2260
|
+
break;
|
|
2261
|
+
}
|
|
2262
|
+
case "hexagon": {
|
|
2263
|
+
drawRegularPolygonPath(ctx, cx, cy, Math.min(w, h) / 2, 6);
|
|
2264
|
+
break;
|
|
2265
|
+
}
|
|
2266
|
+
case "star": {
|
|
2267
|
+
drawStarPath(ctx, cx, cy, Math.min(w, h) / 2, starPoints, starInnerRadius);
|
|
2268
|
+
break;
|
|
2269
|
+
}
|
|
2270
|
+
default: {
|
|
2271
|
+
ctx.beginPath();
|
|
2272
|
+
ctx.rect(0, 0, w, h);
|
|
2273
|
+
break;
|
|
2274
|
+
}
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
function drawRegularPolygonPath(ctx, cx, cy, r, sides) {
|
|
2278
|
+
ctx.beginPath();
|
|
2279
|
+
for (let i = 0; i < sides; i++) {
|
|
2280
|
+
const angle = i * 2 * Math.PI / sides - Math.PI / 2;
|
|
2281
|
+
const px = cx + r * Math.cos(angle);
|
|
2282
|
+
const py = cy + r * Math.sin(angle);
|
|
2283
|
+
if (i === 0) ctx.moveTo(px, py);
|
|
2284
|
+
else ctx.lineTo(px, py);
|
|
2285
|
+
}
|
|
2286
|
+
ctx.closePath();
|
|
2287
|
+
}
|
|
2288
|
+
function drawStarPath(ctx, cx, cy, r, points, innerRatio) {
|
|
2289
|
+
const inner = r * innerRatio;
|
|
2290
|
+
ctx.beginPath();
|
|
2291
|
+
for (let i = 0; i < points * 2; i++) {
|
|
2292
|
+
const angle = i * Math.PI / points - Math.PI / 2;
|
|
2293
|
+
const radius = i % 2 === 0 ? r : inner;
|
|
2294
|
+
const px = cx + radius * Math.cos(angle);
|
|
2295
|
+
const py = cy + radius * Math.sin(angle);
|
|
2296
|
+
if (i === 0) ctx.moveTo(px, py);
|
|
2297
|
+
else ctx.lineTo(px, py);
|
|
2298
|
+
}
|
|
2299
|
+
ctx.closePath();
|
|
2300
|
+
}
|
|
2301
|
+
function getShapeKey(sprite) {
|
|
2302
|
+
const shape = sprite.shape ?? "rect";
|
|
2303
|
+
if (shape === "rect" && !sprite.borderRadius && !sprite.strokeColor) return "";
|
|
2304
|
+
const br = shape === "roundedRect" ? sprite.borderRadius ?? 0 : 0;
|
|
2305
|
+
const sp = shape === "star" ? sprite.starPoints ?? 5 : 0;
|
|
2306
|
+
const sir = shape === "star" ? sprite.starInnerRadius ?? 0.4 : 0;
|
|
2307
|
+
const stroke = sprite.strokeColor && (sprite.strokeWidth ?? 0) > 0 ? `|s:${sprite.strokeColor}:${sprite.strokeWidth}` : "";
|
|
2308
|
+
return `__shape__:${shape}:${br}:${sp}:${sir}${stroke}`;
|
|
2309
|
+
}
|
|
2228
2310
|
function getSamplingKey(sampling) {
|
|
2229
2311
|
if (!sampling) return "";
|
|
2230
2312
|
if (typeof sampling === "string") return sampling;
|
|
@@ -2235,6 +2317,8 @@ function getTextureKey(sprite) {
|
|
|
2235
2317
|
const samplingKey = getSamplingKey(sprite.sampling);
|
|
2236
2318
|
const suffix = samplingKey ? `:s=${samplingKey}` : "";
|
|
2237
2319
|
if (src) return sprite.tileX || sprite.tileY ? `${src}:repeat${suffix}` : `${src}${suffix}`;
|
|
2320
|
+
const shapeKey = getShapeKey(sprite);
|
|
2321
|
+
if (shapeKey) return shapeKey;
|
|
2238
2322
|
return `__color__:${sprite.color}${suffix}`;
|
|
2239
2323
|
}
|
|
2240
2324
|
function getUVRect(sprite) {
|
|
@@ -2385,6 +2469,8 @@ var RenderSystem = class {
|
|
|
2385
2469
|
textureCache = /* @__PURE__ */ new Map();
|
|
2386
2470
|
/** Insertion-order key list for LRU-style eviction. */
|
|
2387
2471
|
textureCacheKeys = [];
|
|
2472
|
+
// ── Shape texture cache ─────────────────────────────────────────────────
|
|
2473
|
+
shapeTextures = /* @__PURE__ */ new Map();
|
|
2388
2474
|
// ── Render layer manager ────────────────────────────────────────────────
|
|
2389
2475
|
layers = createRenderLayerManager();
|
|
2390
2476
|
// ── Texture sampling ────────────────────────────────────────────────────
|
|
@@ -2542,6 +2628,43 @@ var RenderSystem = class {
|
|
|
2542
2628
|
this.textureCacheKeys.push(key);
|
|
2543
2629
|
return entry;
|
|
2544
2630
|
}
|
|
2631
|
+
// ── Shape texture generation ──────────────────────────────────────────────
|
|
2632
|
+
getOrCreateShapeTexture(sprite) {
|
|
2633
|
+
const key = getShapeKey(sprite);
|
|
2634
|
+
const cached = this.shapeTextures.get(key);
|
|
2635
|
+
if (cached) return cached;
|
|
2636
|
+
const size = SHAPE_TEX_SIZE;
|
|
2637
|
+
const offscreen = document.createElement("canvas");
|
|
2638
|
+
offscreen.width = size;
|
|
2639
|
+
offscreen.height = size;
|
|
2640
|
+
const ctx2d = offscreen.getContext("2d");
|
|
2641
|
+
drawShapeOnCanvas(
|
|
2642
|
+
ctx2d,
|
|
2643
|
+
sprite.shape ?? "rect",
|
|
2644
|
+
size,
|
|
2645
|
+
size,
|
|
2646
|
+
(sprite.borderRadius ?? 0) / Math.max(sprite.width, sprite.height) * size,
|
|
2647
|
+
sprite.starPoints ?? 5,
|
|
2648
|
+
sprite.starInnerRadius ?? 0.4
|
|
2649
|
+
);
|
|
2650
|
+
ctx2d.fillStyle = "#ffffff";
|
|
2651
|
+
ctx2d.fill();
|
|
2652
|
+
if (sprite.strokeColor && (sprite.strokeWidth ?? 0) > 0) {
|
|
2653
|
+
ctx2d.strokeStyle = "#ffffff";
|
|
2654
|
+
ctx2d.lineWidth = (sprite.strokeWidth ?? 0) / Math.max(sprite.width, sprite.height) * size;
|
|
2655
|
+
ctx2d.stroke();
|
|
2656
|
+
}
|
|
2657
|
+
const gl = this.gl;
|
|
2658
|
+
const tex = gl.createTexture();
|
|
2659
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
2660
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, offscreen);
|
|
2661
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
2662
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
2663
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
2664
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
2665
|
+
this.shapeTextures.set(key, tex);
|
|
2666
|
+
return tex;
|
|
2667
|
+
}
|
|
2545
2668
|
// ── Texture sampling helper ────────────────────────────────────────────────
|
|
2546
2669
|
/** Apply min/mag filter params to the currently bound texture. */
|
|
2547
2670
|
applySampling(spriteSampling) {
|
|
@@ -2570,12 +2693,20 @@ var RenderSystem = class {
|
|
|
2570
2693
|
}
|
|
2571
2694
|
}
|
|
2572
2695
|
// ── Instanced draw call ────────────────────────────────────────────────────
|
|
2573
|
-
flush(count, textureKey, sampling, blendMode) {
|
|
2696
|
+
flush(count, textureKey, sampling, blendMode, shapeSpriteRef) {
|
|
2574
2697
|
if (count === 0) return;
|
|
2575
2698
|
const { gl } = this;
|
|
2576
2699
|
if (blendMode && blendMode !== "normal") this.applyBlendMode(blendMode);
|
|
2577
2700
|
const isColor = textureKey.startsWith("__color__");
|
|
2578
|
-
const
|
|
2701
|
+
const isShape = textureKey.startsWith("__shape__");
|
|
2702
|
+
let tex;
|
|
2703
|
+
if (isShape && shapeSpriteRef) {
|
|
2704
|
+
tex = this.getOrCreateShapeTexture(shapeSpriteRef);
|
|
2705
|
+
} else if (isColor) {
|
|
2706
|
+
tex = this.whiteTexture;
|
|
2707
|
+
} else {
|
|
2708
|
+
tex = this.loadTexture(textureKey);
|
|
2709
|
+
}
|
|
2579
2710
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
2580
2711
|
this.applySampling(sampling);
|
|
2581
2712
|
gl.uniform1i(this.uUseTexture, isColor ? 0 : 1);
|
|
@@ -2816,9 +2947,10 @@ var RenderSystem = class {
|
|
|
2816
2947
|
let batchKey = "";
|
|
2817
2948
|
let batchSampling;
|
|
2818
2949
|
let batchBlendMode = "normal";
|
|
2950
|
+
let batchShapeRef;
|
|
2819
2951
|
for (let i = 0; i <= renderables.length; i++) {
|
|
2820
2952
|
if (i === renderables.length) {
|
|
2821
|
-
this.flush(batchCount, batchKey, batchSampling, batchBlendMode);
|
|
2953
|
+
this.flush(batchCount, batchKey, batchSampling, batchBlendMode, batchShapeRef);
|
|
2822
2954
|
break;
|
|
2823
2955
|
}
|
|
2824
2956
|
const id = renderables[i];
|
|
@@ -2869,12 +3001,14 @@ var RenderSystem = class {
|
|
|
2869
3001
|
const key = getTextureKey(sprite);
|
|
2870
3002
|
const spriteBlend = sprite.blendMode ?? "normal";
|
|
2871
3003
|
if ((key !== batchKey || spriteBlend !== batchBlendMode) && batchCount > 0 || batchCount >= MAX_INSTANCES) {
|
|
2872
|
-
this.flush(batchCount, batchKey, batchSampling, batchBlendMode);
|
|
3004
|
+
this.flush(batchCount, batchKey, batchSampling, batchBlendMode, batchShapeRef);
|
|
2873
3005
|
batchCount = 0;
|
|
2874
3006
|
}
|
|
2875
3007
|
batchKey = key;
|
|
2876
3008
|
batchSampling = sprite.sampling;
|
|
2877
3009
|
batchBlendMode = spriteBlend;
|
|
3010
|
+
if (key.startsWith("__shape__")) batchShapeRef = sprite;
|
|
3011
|
+
else batchShapeRef = void 0;
|
|
2878
3012
|
const ss = world.getComponent(id, "SquashStretch");
|
|
2879
3013
|
const scaleXMod = ss ? ss.currentScaleX : 1;
|
|
2880
3014
|
const scaleYMod = ss ? ss.currentScaleY : 1;
|
|
@@ -2917,11 +3051,12 @@ var RenderSystem = class {
|
|
|
2917
3051
|
if (!text.visible) continue;
|
|
2918
3052
|
const entry = this.getOrCreateTextTexture(text);
|
|
2919
3053
|
if (!entry) continue;
|
|
2920
|
-
this.flush(batchCount, batchKey, batchSampling, batchBlendMode);
|
|
3054
|
+
this.flush(batchCount, batchKey, batchSampling, batchBlendMode, batchShapeRef);
|
|
2921
3055
|
batchCount = 0;
|
|
2922
3056
|
batchKey = "";
|
|
2923
3057
|
batchSampling = void 0;
|
|
2924
3058
|
batchBlendMode = "normal";
|
|
3059
|
+
batchShapeRef = void 0;
|
|
2925
3060
|
this.writeInstance(
|
|
2926
3061
|
0,
|
|
2927
3062
|
transform.x + text.offsetX,
|