@flare-engine/render 0.4.8 → 0.4.10
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.d.mts +44 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.d.ts +44 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +46 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +14 -5
package/dist/index.mjs
CHANGED
|
@@ -782,12 +782,21 @@ function flashIntensity(effect) {
|
|
|
782
782
|
// src/frame-renderer.ts
|
|
783
783
|
/** See the dev-flag note at the top of this file. */
|
|
784
784
|
const G = globalThis;
|
|
785
|
+
/** `SpriteDrawCommand.rotation` is radians; `DrawSurfaceLike.rotate` takes degrees. */
|
|
786
|
+
const RAD_TO_DEG = 180 / Math.PI;
|
|
785
787
|
const BLEND_SRC_OVER = 3;
|
|
786
788
|
const BLEND_SRC_IN = 5;
|
|
787
789
|
/** Skia BlendMode.SrcATop — r = s·da + d·(1−sa): keeps the art's alpha, lerps colour by the filter's alpha. */
|
|
788
790
|
const BLEND_SRC_ATOP = 9;
|
|
789
791
|
/** Skia BlendMode.Plus — additive: dst = clamp(src + dst). */
|
|
790
792
|
const BLEND_PLUS = 12;
|
|
793
|
+
/** Shared empty result for `compilePostFxPasses`, so a chain-free frame allocates nothing. */
|
|
794
|
+
const EMPTY_COMPILED_PASSES = [];
|
|
795
|
+
/** The two sampling objects `setImageSampling` hands to the surface — shared, never rebuilt. */
|
|
796
|
+
const SAMPLING_NEAREST = { filter: 0 };
|
|
797
|
+
const SAMPLING_LINEAR = { filter: 1 };
|
|
798
|
+
/** Skia MipmapMode.None — the stretch path never mipmaps. */
|
|
799
|
+
const MIPMAP_NONE = 0;
|
|
791
800
|
const OUTLINE_OFFSETS = [
|
|
792
801
|
[1, 0],
|
|
793
802
|
[-1, 0],
|
|
@@ -846,6 +855,7 @@ function createFrameRenderer(Skia) {
|
|
|
846
855
|
const stretchDstRects = [];
|
|
847
856
|
let stretchPaint = null;
|
|
848
857
|
const zoneBgRects = [];
|
|
858
|
+
const imageSampling = /* @__PURE__ */ new WeakMap();
|
|
849
859
|
let _cachedSrcSlice = null;
|
|
850
860
|
let _cachedSrcSliceLen = 0;
|
|
851
861
|
let _cachedXformSlice = null;
|
|
@@ -893,6 +903,17 @@ function createFrameRenderer(Skia) {
|
|
|
893
903
|
_loggedOnce.add(msg);
|
|
894
904
|
console.warn(`[postfx] ${msg}`);
|
|
895
905
|
}
|
|
906
|
+
function compilePostFxPasses(runtime, chain, width, height) {
|
|
907
|
+
const rt = runtime ?? _boundRuntime;
|
|
908
|
+
const ch = chain ?? _boundChain;
|
|
909
|
+
if (rt === null || !rt.supported) return EMPTY_COMPILED_PASSES;
|
|
910
|
+
if (rt.buildPass === void 0) {
|
|
911
|
+
logOnce("buildPostFxPasses: runtime.supported but buildPass absent — no passes");
|
|
912
|
+
return EMPTY_COMPILED_PASSES;
|
|
913
|
+
}
|
|
914
|
+
if (ch === null) return EMPTY_COMPILED_PASSES;
|
|
915
|
+
return rt.buildPass(ch, width, height);
|
|
916
|
+
}
|
|
896
917
|
const canvas = {
|
|
897
918
|
save: () => current?.save() ?? 0,
|
|
898
919
|
restore: () => {
|
|
@@ -1201,21 +1222,19 @@ function createFrameRenderer(Skia) {
|
|
|
1201
1222
|
mountainHillsPaint.setShader(mountainHillsEffect.makeShader(mountainHillsUniforms));
|
|
1202
1223
|
return mountainHillsPaint;
|
|
1203
1224
|
}
|
|
1204
|
-
function drawOutlined(cvs, image, commands, n, effect, alpha) {
|
|
1225
|
+
function drawOutlined(cvs, image, commands, n, effect, alpha, sampling) {
|
|
1205
1226
|
const paint = applyOutlinePaint(effect);
|
|
1206
1227
|
paint.setAlphaf(alpha);
|
|
1207
1228
|
const srcs = getCachedSrcSlice(n);
|
|
1208
1229
|
for (let k = 0; k < OUTLINE_OFFSETS.length; k++) {
|
|
1209
1230
|
const offset = OUTLINE_OFFSETS[k];
|
|
1210
1231
|
fillXforms(commands, n, offset[0] * effect.width, offset[1] * effect.width);
|
|
1211
|
-
|
|
1212
|
-
cvs.drawAtlas(image, srcs, dsts, paint);
|
|
1232
|
+
drawAtlasSampled(cvs, image, srcs, getCachedXformSlice(n), paint, sampling);
|
|
1213
1233
|
}
|
|
1214
1234
|
paint.setAlphaf(1);
|
|
1215
1235
|
defaultPaint.setAlphaf(alpha);
|
|
1216
1236
|
fillXforms(commands, n, 0, 0);
|
|
1217
|
-
|
|
1218
|
-
cvs.drawAtlas(image, srcs, mainDsts, defaultPaint);
|
|
1237
|
+
drawAtlasSampled(cvs, image, srcs, getCachedXformSlice(n), defaultPaint, sampling);
|
|
1219
1238
|
defaultPaint.setAlphaf(1);
|
|
1220
1239
|
}
|
|
1221
1240
|
function resolveEffectPaint(effect) {
|
|
@@ -1259,6 +1278,7 @@ function createFrameRenderer(Skia) {
|
|
|
1259
1278
|
const blendAdditive = cmd0.blend === "additive";
|
|
1260
1279
|
const flipX = cmd0.flipX;
|
|
1261
1280
|
const flipY = cmd0.flipY;
|
|
1281
|
+
const sampling = imageSampling.get(image);
|
|
1262
1282
|
currentSpriteW = cmd0.dstW;
|
|
1263
1283
|
currentSpriteH = cmd0.dstH;
|
|
1264
1284
|
if (effect?.type === "roofs-city" || effect?.type === "forest-canopy" || effect?.type === "river-wave" || effect?.type === "moon-crater" || effect?.type === "cave-interior" || effect?.type === "mountain-hills") {
|
|
@@ -1292,12 +1312,13 @@ function createFrameRenderer(Skia) {
|
|
|
1292
1312
|
const cx = cmd.dstX + cmd.dstW * .5;
|
|
1293
1313
|
const cy = cmd.dstY + cmd.dstH * .5;
|
|
1294
1314
|
current.save();
|
|
1315
|
+
if (cmd.rotation !== 0) current.rotate(cmd.rotation * RAD_TO_DEG, cmd.dstX + cmd.anchorX * cmd.dstW, cmd.dstY + cmd.anchorY * cmd.dstH);
|
|
1295
1316
|
current.translate(cx, cy);
|
|
1296
1317
|
current.scale(cmd.flipX ? -1 : 1, cmd.flipY ? -1 : 1);
|
|
1297
1318
|
current.translate(-cx, -cy);
|
|
1298
|
-
current
|
|
1319
|
+
drawImageRectSampled(current, image, srcR, dstR, sPaint, sampling);
|
|
1299
1320
|
current.restore();
|
|
1300
|
-
} else current
|
|
1321
|
+
} else drawImageRectSampled(current, image, srcR, dstR, sPaint, sampling);
|
|
1301
1322
|
}
|
|
1302
1323
|
sPaint.setAlphaf(1);
|
|
1303
1324
|
if (blendAdditive) sPaint.setBlendMode?.(BLEND_SRC_OVER);
|
|
@@ -1310,7 +1331,7 @@ function createFrameRenderer(Skia) {
|
|
|
1310
1331
|
outlinePaint?.setBlendMode?.(BLEND_PLUS);
|
|
1311
1332
|
defaultPaint.setBlendMode?.(BLEND_PLUS);
|
|
1312
1333
|
}
|
|
1313
|
-
drawOutlined(current, image, commands, n, effect, alpha);
|
|
1334
|
+
drawOutlined(current, image, commands, n, effect, alpha, sampling);
|
|
1314
1335
|
if (blendAdditive) {
|
|
1315
1336
|
outlinePaint?.setBlendMode?.(BLEND_SRC_OVER);
|
|
1316
1337
|
defaultPaint.setBlendMode?.(BLEND_SRC_OVER);
|
|
@@ -1323,10 +1344,15 @@ function createFrameRenderer(Skia) {
|
|
|
1323
1344
|
const paint = effect === void 0 ? defaultPaint : resolveEffectPaint(effect);
|
|
1324
1345
|
if (blendAdditive) paint.setBlendMode?.(BLEND_PLUS);
|
|
1325
1346
|
paint.setAlphaf(alpha);
|
|
1326
|
-
current
|
|
1347
|
+
drawAtlasSampled(current, image, srcs, dsts, paint, sampling);
|
|
1327
1348
|
paint.setAlphaf(1);
|
|
1328
1349
|
if (blendAdditive) paint.setBlendMode?.(BLEND_SRC_OVER);
|
|
1329
1350
|
},
|
|
1351
|
+
setImageSampling(image, sampling) {
|
|
1352
|
+
if (sampling === "nearest") imageSampling.set(image, SAMPLING_NEAREST);
|
|
1353
|
+
else if (sampling === "linear") imageSampling.set(image, SAMPLING_LINEAR);
|
|
1354
|
+
else throw new RangeError(`setImageSampling: unknown sampling '${String(sampling)}' (expected 'nearest' or 'linear')`);
|
|
1355
|
+
},
|
|
1330
1356
|
setPostFxBinding(runtime, chain) {
|
|
1331
1357
|
_boundRuntime = runtime;
|
|
1332
1358
|
_boundChain = chain;
|
|
@@ -1334,16 +1360,9 @@ function createFrameRenderer(Skia) {
|
|
|
1334
1360
|
hasPostFxBinding() {
|
|
1335
1361
|
return _boundRuntime !== null && !!_boundRuntime.supported && _boundRuntime.buildPass !== void 0 && _boundChain !== null;
|
|
1336
1362
|
},
|
|
1363
|
+
compilePostFxPasses,
|
|
1337
1364
|
buildPostFxPasses(runtime, chain, width, height) {
|
|
1338
|
-
const
|
|
1339
|
-
const ch = chain ?? _boundChain;
|
|
1340
|
-
if (rt === null || !rt.supported) return [];
|
|
1341
|
-
if (rt.buildPass === void 0) {
|
|
1342
|
-
logOnce("buildPostFxPasses: runtime.supported but buildPass absent — no passes");
|
|
1343
|
-
return [];
|
|
1344
|
-
}
|
|
1345
|
-
if (ch === null) return [];
|
|
1346
|
-
const passes = rt.buildPass(ch, width, height);
|
|
1365
|
+
const passes = compilePostFxPasses(runtime, chain, width, height);
|
|
1347
1366
|
if (passes.length === 0) return [];
|
|
1348
1367
|
const out = [];
|
|
1349
1368
|
for (const pass of passes) {
|
|
@@ -1404,6 +1423,15 @@ function getXformCounters() {
|
|
|
1404
1423
|
unrotated: _xformUnrotatedCount
|
|
1405
1424
|
};
|
|
1406
1425
|
}
|
|
1426
|
+
/** Without a sampling setting this is exactly the 4-argument call the surface always received. */
|
|
1427
|
+
function drawAtlasSampled(cvs, image, srcs, dsts, paint, sampling) {
|
|
1428
|
+
if (sampling === void 0) cvs.drawAtlas(image, srcs, dsts, paint);
|
|
1429
|
+
else cvs.drawAtlas(image, srcs, dsts, paint, void 0, void 0, sampling);
|
|
1430
|
+
}
|
|
1431
|
+
function drawImageRectSampled(cvs, image, src, dst, paint, sampling) {
|
|
1432
|
+
if (sampling === void 0 || cvs.drawImageRectOptions === void 0) cvs.drawImageRect(image, src, dst, paint);
|
|
1433
|
+
else cvs.drawImageRectOptions(image, src, dst, sampling.filter, MIPMAP_NONE, paint);
|
|
1434
|
+
}
|
|
1407
1435
|
function writeColor(out, color, alphaMul) {
|
|
1408
1436
|
out[0] = color.r;
|
|
1409
1437
|
out[1] = color.g;
|