@nodecraft/rendermite 1.0.7 → 1.1.1
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/assets/README.md +6 -2
- package/assets/builtin/renderchest/models/item/trident.json +372 -0
- package/assets/builtin-legacy/renderchest/models/item/trident.json +372 -0
- package/assets/mod-models/README.md +130 -0
- package/assets/mod-models/ad_astra/models/item/tier_1_rocket.json +4559 -0
- package/assets/mod-models/ad_astra/models/item/tier_1_rover.json +6021 -0
- package/assets/mod-models/ad_astra/models/item/tier_2_rocket.json +6832 -0
- package/assets/mod-models/ad_astra/models/item/tier_3_rocket.json +8522 -0
- package/assets/mod-models/ad_astra/models/item/tier_4_rocket.json +7498 -0
- package/assets/mod-models/botania/models/item/avatar.json +574 -0
- package/assets/mod-models/botania/models/item/bellows.json +423 -0
- package/assets/mod-models/botania/models/item/brewery.json +894 -0
- package/assets/mod-models/botania/models/item/corporea_index.json +349 -0
- package/assets/mod-models/botania/models/item/gaia_pylon.json +1057 -0
- package/assets/mod-models/botania/models/item/hourglass.json +502 -0
- package/assets/mod-models/botania/models/item/mana_pylon.json +741 -0
- package/assets/mod-models/botania/models/item/natura_pylon.json +1057 -0
- package/assets/mod-models/botania/models/item/teru_teru_bozu.json +347 -0
- package/assets/mod-models/mekanism/models/item/atomic_disassembler.json +1391 -0
- package/assets/mod-models/mekanism/models/item/flamethrower.json +1926 -0
- package/assets/mod-models/mekanism/models/item/free_runners.json +595 -0
- package/assets/mod-models/mekanism/models/item/jetpack.json +1767 -0
- package/assets/mod-models/mekanism/models/item/scuba_mask.json +2305 -0
- package/assets/mod-models/mekanism/models/item/scuba_tank.json +833 -0
- package/assets/mod-tints/README.md +19 -0
- package/assets/mod-tints/mysticalagriculture/items/absorption_i_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/absorption_ii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/absorption_iii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/absorption_iv_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/absorption_v_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/attack_aoe_i_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/attack_aoe_ii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/attack_aoe_iii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/blindness_resistance_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/fire_resistance_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/flight_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/haste_i_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/haste_ii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/haste_iii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/health_boost_i_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/health_boost_ii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/health_boost_iii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/health_boost_iv_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/health_boost_v_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/hunger_resistance_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/jump_boost_i_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/jump_boost_ii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/jump_boost_iii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/luck_i_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/luck_ii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/luck_iii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/mining_aoe_i_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/mining_aoe_ii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/mining_aoe_iii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/mining_aoe_iv_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/mining_fatigue_resistance_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/nausea_resistance_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/night_vision_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/pathing_aoe_i_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/pathing_aoe_ii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/pathing_aoe_iii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/pathing_aoe_iv_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/poison_resistance_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/slow_falling_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/slowness_resistance_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/speed_i_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/speed_ii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/speed_iii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/step_assist_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/strength_i_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/strength_ii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/strength_iii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/tilling_aoe_i_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/tilling_aoe_ii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/tilling_aoe_iii_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/tilling_aoe_iv_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/water_breathing_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/weakness_resistance_augment.json +16 -0
- package/assets/mod-tints/mysticalagriculture/items/wither_resistance_augment.json +16 -0
- package/dist/atlas/registry.js +1 -1
- package/dist/blend-8lnfxtLe.d.ts +79 -0
- package/dist/blend-KXMclcHk.js +199 -0
- package/dist/blockstate-CdstnW2-.js +104 -0
- package/dist/{builtin-caYjESh0.js → builtin-WkWjATeh.js} +5 -1
- package/dist/builtin.d.ts +3 -1
- package/dist/builtin.js +2 -2
- package/dist/cli.js +5 -3
- package/dist/{compose-lWPrB7wh.js → compose-BGsNFR12.js} +1 -1
- package/dist/{definition-3MBm8ar_.js → definition-ColsvWrH.js} +20 -1
- package/dist/{definition-BwX6Xxv0.d.ts → definition-ricL7Jqf.d.ts} +2 -0
- package/dist/{discovery-0SM0cTLw.js → discovery-B9aqV_Rz.js} +13 -3
- package/dist/{discovery-wiJBGryo.d.ts → discovery-BPSUtdm4.d.ts} +1 -1
- package/dist/{encode-CaSK8-mi.d.ts → encode-DNcXXvYe.d.ts} +1 -1
- package/dist/{encode-Df_tWzkl.js → encode-LR9wxigC.js} +1 -1
- package/dist/{entity-fallback-D9QTGU9X.js → entity-fallback-BnFMSHS6.js} +180 -10
- package/dist/{face-Cl1O4m2i.js → face-CMJ3b3Ae.js} +44 -18
- package/dist/face-cQ-pVHoe.d.ts +44 -0
- package/dist/{fluid-bucket-D-GpUQjg.js → fluid-bucket-BzoLofB_.js} +7 -2
- package/dist/{geo-DHiWBa-C.js → geo-w9HHIrb5.js} +87 -13
- package/dist/{geometry-uIDha8S4.js → geometry-Bi-Bf5rb.js} +7 -1
- package/dist/{geometry-BSVmKx5b.d.ts → geometry-w0yQbzDZ.d.ts} +5 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.js +10 -10
- package/dist/items/blockstate.d.ts +23 -0
- package/dist/items/blockstate.js +2 -0
- package/dist/items/definition.d.ts +1 -1
- package/dist/items/definition.js +1 -1
- package/dist/items/discovery.d.ts +1 -1
- package/dist/items/discovery.js +1 -1
- package/dist/{loader-D22zZME7.d.ts → loader-DD83d80u.d.ts} +2 -1
- package/dist/{loader-B8NJO7pR.js → loader-DwkA9LR5.js} +267 -15
- package/dist/{loader-CfXMxcEV.js → loader-Lb0ZeILz.js} +19 -7
- package/dist/models/loader.d.ts +1 -1
- package/dist/models/loader.js +1 -1
- package/dist/models/types.d.ts +1 -1
- package/dist/models-BKxGkPS7.js +18 -0
- package/dist/mods/models.d.ts +5 -0
- package/dist/mods/models.js +2 -0
- package/dist/mods/prepare.d.ts +1 -1
- package/dist/mods/prepare.js +1 -1
- package/dist/mods/tints.js +1 -1
- package/dist/output/encode.d.ts +1 -1
- package/dist/output/encode.js +1 -1
- package/dist/{pipeline-HiA3DC71.d.ts → pipeline-Bp6amYz_.d.ts} +17 -5
- package/dist/{pipeline-Da2Kavba.js → pipeline-zu_ZjnNc.js} +85 -21
- package/dist/{prepare-BESRrh6K.js → prepare-D56Z-9cg.js} +7 -2
- package/dist/{prepare-CPxO0kKz.d.ts → prepare-Dce7-HAe.d.ts} +8 -0
- package/dist/{rasterizer-B9ZGJI3-.d.ts → rasterizer-BSQHEhJ-.d.ts} +4 -2
- package/dist/{rasterizer-76qO8TDh.js → rasterizer-DcVJzkxz.js} +13 -5
- package/dist/{registry-B9TcjVbs.js → registry-DS5PZ57l.js} +8 -1
- package/dist/render/blend.d.ts +2 -2
- package/dist/render/blend.js +2 -2
- package/dist/render/compose.d.ts +2 -2
- package/dist/render/compose.js +1 -1
- package/dist/render/entity-fallback.d.ts +19 -5
- package/dist/render/entity-fallback.js +2 -2
- package/dist/render/face.d.ts +2 -2
- package/dist/render/face.js +2 -2
- package/dist/render/fluid-bucket.js +1 -1
- package/dist/render/geo.d.ts +3 -3
- package/dist/render/geo.js +1 -1
- package/dist/render/geometry.d.ts +1 -1
- package/dist/render/geometry.js +1 -1
- package/dist/render/legacy-tints.d.ts +1 -1
- package/dist/render/obj.d.ts +5 -3
- package/dist/render/obj.js +1 -1
- package/dist/render/pipeline.d.ts +1 -1
- package/dist/render/pipeline.js +1 -1
- package/dist/render/rasterizer.d.ts +1 -1
- package/dist/render/rasterizer.js +1 -1
- package/dist/render/renderer.d.ts +1 -1
- package/dist/render/renderer.js +1 -1
- package/dist/render/tints.d.ts +1 -1
- package/dist/render/tints.js +1 -1
- package/dist/{renderer-B20ssjRm.d.ts → renderer-C79EQDSn.d.ts} +3 -3
- package/dist/{renderer-gQW_I7YG.js → renderer-oi1MSF3Y.js} +21 -10
- package/dist/{run-B0qPw3zf.js → run-D87zIGfr.js} +3 -3
- package/dist/{run-CT3VtFqg.d.ts → run-uq8_hUx9.d.ts} +1 -1
- package/dist/run.d.ts +2 -2
- package/dist/run.js +2 -2
- package/dist/textures/loader.js +1 -1
- package/dist/{tints-BtbHegpI.js → tints-3VI_2SNy.js} +107 -1
- package/dist/{tints-B8UJmZMu.js → tints-CebmvjmP.js} +2 -2
- package/dist/{tints-BH9l0ND0.d.ts → tints-Do9Sh3dg.d.ts} +2 -2
- package/dist/{types-COGbtA1t.d.ts → types-DpRSF9Vj.d.ts} +8 -0
- package/dist/workers/render-worker.d.ts +1 -1
- package/dist/workers/render-worker.js +1 -1
- package/package.json +1 -1
- package/dist/blend-CEHoJ7tM.d.ts +0 -37
- package/dist/blend-D0XWgVQr.js +0 -102
- package/dist/face-C49L66sQ.d.ts +0 -30
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
|
|
2
|
+
import { _ as translation, d as rotationY, s as multiply, u as rotationX } from "./vector-CCxLae_T.js";
|
|
3
|
+
//#region src/items/blockstate.ts
|
|
4
|
+
/**
|
|
5
|
+
* Block models for items the game draws through a block-entity item renderer.
|
|
6
|
+
*
|
|
7
|
+
* A `builtin/entity` item model carries no geometry, but for a BlockItem the
|
|
8
|
+
* renderer usually still draws the block first — Mekanism's `MekanismISTER`
|
|
9
|
+
* calls `getBlockModelShaper().getBlockModel(block.defaultBlockState())` and
|
|
10
|
+
* only then adds its own extras. That model is stated in the mod's own
|
|
11
|
+
* blockstate file, so resolving it is following the data rather than guessing at
|
|
12
|
+
* a name: `mekanism:basic_energy_cube` names `mekanism:block/energy_cube/basic`,
|
|
13
|
+
* which no same-name lookup would ever find.
|
|
14
|
+
*
|
|
15
|
+
* The one thing assets cannot state is which state is the *default*, since that
|
|
16
|
+
* lives in the block's Java constructor. `scoreVariant` picks the variant the
|
|
17
|
+
* game would almost always start from, and prefers an unrotated one so an icon
|
|
18
|
+
* is never accidentally turned away from the camera.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Property values a block's default state overwhelmingly uses. Blocks declare
|
|
22
|
+
* their own defaults in code, so this is the one inference here — but a facing
|
|
23
|
+
* block defaults to north far more often than not, and a machine defaults to
|
|
24
|
+
* idle rather than running.
|
|
25
|
+
*/
|
|
26
|
+
const DEFAULT_VALUES = {
|
|
27
|
+
facing: "north",
|
|
28
|
+
active: "false",
|
|
29
|
+
lit: "false",
|
|
30
|
+
powered: "false",
|
|
31
|
+
open: "false",
|
|
32
|
+
half: "lower",
|
|
33
|
+
axis: "y",
|
|
34
|
+
waterlogged: "false"
|
|
35
|
+
};
|
|
36
|
+
/** Higher is more likely to be the state the game shows for a fresh block. */
|
|
37
|
+
function scoreVariant(key, variant) {
|
|
38
|
+
let score = 0;
|
|
39
|
+
if (key === "") score += 4;
|
|
40
|
+
if (!variant.x && !variant.y) score += 2;
|
|
41
|
+
for (const pair of key.split(",")) {
|
|
42
|
+
const [name, value] = pair.split("=", 2);
|
|
43
|
+
if (name && DEFAULT_VALUES[name] === value) score++;
|
|
44
|
+
}
|
|
45
|
+
return score;
|
|
46
|
+
}
|
|
47
|
+
function firstOf(variant) {
|
|
48
|
+
const entry = Array.isArray(variant) ? variant[0] : variant;
|
|
49
|
+
return entry?.model ? entry : null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The block model an item's blockstate names for its default state, or null
|
|
53
|
+
* when the item has no blockstate or it states nothing usable.
|
|
54
|
+
*/
|
|
55
|
+
async function defaultBlockStateModel(resources, id) {
|
|
56
|
+
const locator = ResourceLocator.tryParse(id);
|
|
57
|
+
if (!locator) return null;
|
|
58
|
+
const raw = await resources.getResource("blockstate", locator);
|
|
59
|
+
if (raw === null) return null;
|
|
60
|
+
let json;
|
|
61
|
+
try {
|
|
62
|
+
json = JSON.parse(raw.toString("utf8"));
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
let best = null;
|
|
67
|
+
let bestScore = -1;
|
|
68
|
+
for (const [key, value] of Object.entries(json.variants ?? {})) {
|
|
69
|
+
const variant = firstOf(value);
|
|
70
|
+
if (!variant) continue;
|
|
71
|
+
const score = scoreVariant(key, variant);
|
|
72
|
+
if (score > bestScore) {
|
|
73
|
+
best = variant;
|
|
74
|
+
bestScore = score;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!best) {
|
|
78
|
+
for (const part of json.multipart ?? []) if (part.when === void 0) {
|
|
79
|
+
best = firstOf(part.apply);
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (!best) return null;
|
|
84
|
+
const model = ResourceLocator.tryParse(best.model.includes(":") ? best.model : `${locator.namespace}:${best.model}`);
|
|
85
|
+
return model === null ? null : {
|
|
86
|
+
model,
|
|
87
|
+
xRotation: best.x ?? 0,
|
|
88
|
+
yRotation: best.y ?? 0
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The blockstate's own x/y rotation as an item transform. Vanilla applies these
|
|
93
|
+
* about the block's centre, and the game bakes them into the model before the
|
|
94
|
+
* display transform, so they compose the same way here.
|
|
95
|
+
*/
|
|
96
|
+
function blockStateTransform(state) {
|
|
97
|
+
const toRadians = Math.PI / 180;
|
|
98
|
+
let matrix = translation(.5, .5, .5);
|
|
99
|
+
matrix = multiply(matrix, rotationX(-state.xRotation * toRadians));
|
|
100
|
+
matrix = multiply(matrix, rotationY(-state.yRotation * toRadians));
|
|
101
|
+
return multiply(matrix, translation(-.5, -.5, -.5));
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { defaultBlockStateModel as n, blockStateTransform as t };
|
|
@@ -16,5 +16,9 @@ function bedCompatPath() {
|
|
|
16
16
|
function modTintPackPath() {
|
|
17
17
|
return path.join(assetsRoot, "mod-tints");
|
|
18
18
|
}
|
|
19
|
+
/** Curated geometry for mod items the game draws in code (builtin/entity). */
|
|
20
|
+
function modModelPackPath() {
|
|
21
|
+
return path.join(assetsRoot, "mod-models");
|
|
22
|
+
}
|
|
19
23
|
//#endregion
|
|
20
|
-
export { builtinPackPath as n,
|
|
24
|
+
export { modTintPackPath as i, builtinPackPath as n, modModelPackPath as r, bedCompatPath as t };
|
package/dist/builtin.d.ts
CHANGED
|
@@ -3,5 +3,7 @@ declare function builtinPackPath(era: 'modern' | 'legacy'): string;
|
|
|
3
3
|
declare function bedCompatPath(): string;
|
|
4
4
|
/** Curated tint overrides for mod items that register their colors in code. */
|
|
5
5
|
declare function modTintPackPath(): string;
|
|
6
|
+
/** Curated geometry for mod items the game draws in code (builtin/entity). */
|
|
7
|
+
declare function modModelPackPath(): string;
|
|
6
8
|
//#endregion
|
|
7
|
-
export { bedCompatPath, builtinPackPath, modTintPackPath };
|
|
9
|
+
export { bedCompatPath, builtinPackPath, modModelPackPath, modTintPackPath };
|
package/dist/builtin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as builtinPackPath, r as
|
|
2
|
-
export { bedCompatPath, builtinPackPath, modTintPackPath };
|
|
1
|
+
import { i as modTintPackPath, n as builtinPackPath, r as modModelPackPath, t as bedCompatPath } from "./builtin-WkWjATeh.js";
|
|
2
|
+
export { bedCompatPath, builtinPackPath, modModelPackPath, modTintPackPath };
|
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as builtinPackPath, t as bedCompatPath } from "./builtin-
|
|
2
|
+
import { n as builtinPackPath, t as bedCompatPath } from "./builtin-WkWjATeh.js";
|
|
3
3
|
import { n as LayeredResourceManager, t as FolderResourceManager } from "./manager-CkletR5K.js";
|
|
4
|
-
import {
|
|
4
|
+
import { t as curatedModelOverrides } from "./models-BKxGkPS7.js";
|
|
5
|
+
import { n as harvestTintOverrides, t as curatedTintOverrides } from "./tints-CebmvjmP.js";
|
|
5
6
|
import { t as JarResourceManager } from "./jar-D9z-X7tA.js";
|
|
6
|
-
import { t as run } from "./run-
|
|
7
|
+
import { t as run } from "./run-D87zIGfr.js";
|
|
7
8
|
import { t as downloadClientJar } from "./download-D9aARBFp.js";
|
|
8
9
|
import { a as prepareVersionResources, i as eraForVersion, n as GEOMETRY_DONOR_VERSIONS } from "./prepare-Cc8QZ3j0.js";
|
|
9
10
|
import path from "node:path";
|
|
@@ -166,6 +167,7 @@ if (values.mod?.length) {
|
|
|
166
167
|
const base = new LayeredResourceManager([
|
|
167
168
|
resources,
|
|
168
169
|
curatedTintOverrides(),
|
|
170
|
+
curatedModelOverrides(),
|
|
169
171
|
...values.mod.map((jar) => new JarResourceManager(jar))
|
|
170
172
|
]);
|
|
171
173
|
resources = base;
|
|
@@ -108,9 +108,28 @@ function evaluateItemModel(node, properties = defaultProperties(), parentTransfo
|
|
|
108
108
|
}];
|
|
109
109
|
}
|
|
110
110
|
return [];
|
|
111
|
+
case "neoforge:fluid_container":
|
|
112
|
+
case "forge:fluid_container": {
|
|
113
|
+
const fluid = typeof item.fluid === "string" ? item.fluid : void 0;
|
|
114
|
+
const base = item.textures?.base;
|
|
115
|
+
return [{
|
|
116
|
+
model: typeof base === "string" && base.includes("item/") ? base : "minecraft:item/bucket",
|
|
117
|
+
tints: [],
|
|
118
|
+
transform,
|
|
119
|
+
...fluid && !fluid.endsWith(":empty") && { fluid }
|
|
120
|
+
}];
|
|
121
|
+
}
|
|
111
122
|
case "minecraft:empty":
|
|
112
123
|
case "minecraft:bundle/selected_item": return [];
|
|
113
|
-
default:
|
|
124
|
+
default: {
|
|
125
|
+
const named = typeof item.model === "string" ? item.model : item.base_model;
|
|
126
|
+
if (typeof named === "string") return [{
|
|
127
|
+
model: named,
|
|
128
|
+
tints: Array.isArray(item.tints) ? item.tints : [],
|
|
129
|
+
transform
|
|
130
|
+
}];
|
|
131
|
+
throw new InvalidItemDefinitionError(`Unknown item model type: ${String(item.type)}`);
|
|
132
|
+
}
|
|
114
133
|
}
|
|
115
134
|
}
|
|
116
135
|
//#endregion
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { o as identity } from "./vector-CCxLae_T.js";
|
|
2
|
-
import { o as evaluateItemModel } from "./definition-3MBm8ar_.js";
|
|
3
1
|
import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
|
|
2
|
+
import { o as identity } from "./vector-CCxLae_T.js";
|
|
3
|
+
import { n as InvalidItemDefinitionError, o as evaluateItemModel } from "./definition-ColsvWrH.js";
|
|
4
4
|
//#region src/items/discovery.ts
|
|
5
5
|
/**
|
|
6
6
|
* Era-adaptive item discovery — the piece no single renderchest tag has:
|
|
@@ -78,7 +78,17 @@ async function resolveItem(resources, id, properties) {
|
|
|
78
78
|
throw new ItemResolutionError(`Item definition is not valid JSON: ${id}`);
|
|
79
79
|
}
|
|
80
80
|
if (parsed.model === void 0) throw new ItemResolutionError(`Item definition has no model node: ${id}`);
|
|
81
|
-
|
|
81
|
+
try {
|
|
82
|
+
return evaluateItemModel(parsed.model, properties);
|
|
83
|
+
} catch (err) {
|
|
84
|
+
const conventional = new ResourceLocator(locator.namespace, `item/${locator.path}`);
|
|
85
|
+
if (err instanceof InvalidItemDefinitionError && await resources.hasResource("model", conventional)) return [{
|
|
86
|
+
model: conventional.toString(),
|
|
87
|
+
tints: [],
|
|
88
|
+
transform: identity()
|
|
89
|
+
}];
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
82
92
|
}
|
|
83
93
|
const modelLocator = new ResourceLocator(locator.namespace, `item/${locator.path}`);
|
|
84
94
|
if (await resources.hasResource("model", modelLocator)) return [{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as ResourceManager } from "./manager-Cv1NeFyF.js";
|
|
2
|
-
import { i as ItemRenderInstruction, r as ItemProperties } from "./definition-
|
|
2
|
+
import { i as ItemRenderInstruction, r as ItemProperties } from "./definition-ricL7Jqf.js";
|
|
3
3
|
//#region src/items/discovery.d.ts
|
|
4
4
|
declare class ItemResolutionError extends Error {}
|
|
5
5
|
interface DiscoveredItem {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
|
|
2
|
-
import { i as renderModel } from "./renderer-
|
|
2
|
+
import { i as renderModel } from "./renderer-oi1MSF3Y.js";
|
|
3
3
|
//#region src/render/entity-fallback.ts
|
|
4
4
|
/**
|
|
5
5
|
* Heuristic rendering for mod items that parent `builtin/entity` — chests,
|
|
@@ -64,6 +64,22 @@ async function findChestTexture(resources, namespace, itemName) {
|
|
|
64
64
|
}
|
|
65
65
|
return best;
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* An item's English display name, slugified, or null. Mods do not always put the
|
|
69
|
+
* kind in the id — lootr's Loot Chest is `lootr_inventory` — and the lang file is
|
|
70
|
+
* a statement of what the thing is rather than a guess from its name.
|
|
71
|
+
*/
|
|
72
|
+
async function displayName(resources, locator) {
|
|
73
|
+
const raw = await resources.getResource("lang", new ResourceLocator(locator.namespace, "en_us")).catch(() => null);
|
|
74
|
+
if (!raw) return null;
|
|
75
|
+
try {
|
|
76
|
+
const lang = JSON.parse(raw.toString("utf8"));
|
|
77
|
+
const value = lang[`item.${locator.namespace}.${locator.path}`] ?? lang[`block.${locator.namespace}.${locator.path}`];
|
|
78
|
+
return typeof value === "string" ? value.toLowerCase().replaceAll(/[^a-z\d]+/g, "_") : null;
|
|
79
|
+
} catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
67
83
|
/** Clone a resolved model with one texture variable rebound. */
|
|
68
84
|
function withTexture(model, name, locator) {
|
|
69
85
|
return {
|
|
@@ -99,6 +115,33 @@ const DYE_COLORS = {
|
|
|
99
115
|
black: 1908001
|
|
100
116
|
};
|
|
101
117
|
const DYE_PREFIX = new RegExp(`^(${Object.keys(DYE_COLORS).join("|")})_(.+)$`);
|
|
118
|
+
/** Skin sheet sizes the mobheads pack has base geometry for. */
|
|
119
|
+
const HEAD_LAYOUTS = {
|
|
120
|
+
"64x32": "head_64_32",
|
|
121
|
+
"64x64": "head_64_64",
|
|
122
|
+
"32x32": "head_32_32"
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* The entity sheet for a mob, preferring a file named exactly after it. Sheets
|
|
126
|
+
* live at entity/<mob>.png or entity/<mob>/<mob>.png depending on the mod, and a
|
|
127
|
+
* head only ever wants the base skin — never a blink or armour overlay.
|
|
128
|
+
*/
|
|
129
|
+
async function findMobTexture(resources, namespace, mob) {
|
|
130
|
+
for (const source of [namespace, "minecraft"]) {
|
|
131
|
+
for (const candidate of [`entity/${mob}`, `entity/${mob}/${mob}`]) {
|
|
132
|
+
const locator = new ResourceLocator(source, candidate);
|
|
133
|
+
if (await resources.hasResource("texture", locator)) return locator;
|
|
134
|
+
}
|
|
135
|
+
let best = null;
|
|
136
|
+
for (const locator of await resources.listResources("texture", source)) {
|
|
137
|
+
const leaf = locator.path.split("/").pop();
|
|
138
|
+
if (!locator.path.startsWith("entity/") || leaf !== mob) continue;
|
|
139
|
+
if (best === null || locator.path.length < best.path.length) best = locator;
|
|
140
|
+
}
|
|
141
|
+
if (best) return best;
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
102
145
|
/** Find a full modded bed entity sheet, preferring every distinguishing item-name token. */
|
|
103
146
|
async function findBedTexture(resources, namespace, itemName) {
|
|
104
147
|
const wanted = tokens(itemName).filter((token) => token !== "bed");
|
|
@@ -120,6 +163,37 @@ async function findBedTexture(resources, namespace, itemName) {
|
|
|
120
163
|
}
|
|
121
164
|
return best;
|
|
122
165
|
}
|
|
166
|
+
/** The dye name a `<dye>_<thing>` mod item is prefixed with, or null. */
|
|
167
|
+
function dyeVariantName(id) {
|
|
168
|
+
const locator = ResourceLocator.tryParse(id);
|
|
169
|
+
if (!locator || locator.namespace === "minecraft") return null;
|
|
170
|
+
const name = locator.path.split("/").pop() ?? locator.path;
|
|
171
|
+
return DYE_PREFIX.exec(name)?.[1] ?? null;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* The dye color a `<dye>_<thing>` item name implies, or null. Mods that name
|
|
175
|
+
* variants after dyes sometimes register the matching DyeColor as the tint in
|
|
176
|
+
* client code, where no asset states it (waystones' sharestones call
|
|
177
|
+
* `DyeColor.getTextColor()`), so the name is the only record of it left.
|
|
178
|
+
*
|
|
179
|
+
* Only ever right for variants that SHARE one uncoloured sprite. A mod that
|
|
180
|
+
* draws each colour its own texture is already the right colour, and tinting it
|
|
181
|
+
* again multiplies the dye in — chipped's blue_paper_lantern came out near
|
|
182
|
+
* black. Callers must check the model's textures; see `dyeVariantName`.
|
|
183
|
+
*/
|
|
184
|
+
function dyedVariantTint(id) {
|
|
185
|
+
const locator = ResourceLocator.tryParse(id);
|
|
186
|
+
if (!locator || locator.namespace === "minecraft") return null;
|
|
187
|
+
const name = locator.path.split("/").pop() ?? locator.path;
|
|
188
|
+
const match = DYE_PREFIX.exec(name);
|
|
189
|
+
if (!match) return null;
|
|
190
|
+
const color = DYE_COLORS[match[1]];
|
|
191
|
+
return {
|
|
192
|
+
r: (color >>> 16 & 255) / 255,
|
|
193
|
+
g: (color >>> 8 & 255) / 255,
|
|
194
|
+
b: (color & 255) / 255
|
|
195
|
+
};
|
|
196
|
+
}
|
|
123
197
|
/**
|
|
124
198
|
* Dyed variants of vanilla items whose models mods generate at runtime (quark's
|
|
125
199
|
* `black_frame_empty` parents a block model that exists nowhere on disk): render
|
|
@@ -242,19 +316,28 @@ async function spawnEggTints(id, resources, textures) {
|
|
|
242
316
|
async function renderEntityFallback(id, models, textures, resources, options) {
|
|
243
317
|
const locator = ResourceLocator.parse(id);
|
|
244
318
|
const name = locator.path.split("/").pop() ?? locator.path;
|
|
319
|
+
const searchName = `${name}_${await displayName(resources, locator) ?? ""}`;
|
|
245
320
|
const headMatch = /^(.+?)_(?:head|skull)$/.exec(name);
|
|
246
321
|
if (headMatch) {
|
|
247
|
-
const
|
|
322
|
+
const mob = headMatch[1].replace(/^(?:carved|wall|floor)_/, "");
|
|
323
|
+
const parts = mob.split("_");
|
|
248
324
|
for (let keep = parts.length; keep >= 1 && keep >= parts.length - 2; keep--) try {
|
|
249
325
|
const model = await models.load(`mobheads:item/${parts.slice(0, keep).join("_")}`);
|
|
250
326
|
return await renderModel(model, textures, options);
|
|
251
327
|
} catch {
|
|
252
328
|
continue;
|
|
253
329
|
}
|
|
330
|
+
const sheet = await findMobTexture(resources, locator.namespace, mob);
|
|
331
|
+
const skin = sheet ? await textures.load(sheet).catch(() => null) : null;
|
|
332
|
+
const base = skin ? HEAD_LAYOUTS[`${skin.width}x${skin.height}`] : void 0;
|
|
333
|
+
if (sheet && base) {
|
|
334
|
+
const geometry = await models.load(`mobheads:item/base/${base}`).catch(() => null);
|
|
335
|
+
if (geometry) return renderModel(withTexture(geometry, "texture", sheet), textures, options);
|
|
336
|
+
}
|
|
254
337
|
return null;
|
|
255
338
|
}
|
|
256
|
-
if (
|
|
257
|
-
const variant =
|
|
339
|
+
if (searchName.includes("chest") && !searchName.includes("chestplate") || name.endsWith("_crate")) {
|
|
340
|
+
const variant = searchName.includes("ender") ? "ender" : searchName.includes("trapped") ? "trapped" : "normal";
|
|
258
341
|
const candidates = [[`renderchest:item/chest/${variant === "normal" ? "chest" : `${variant}_chest`}`, null], ["renderchest:item/chest", `minecraft:entity/chest/${variant}`]];
|
|
259
342
|
const modTexture = await findChestTexture(resources, locator.namespace, name);
|
|
260
343
|
for (const [modelPath, defaultTexture] of candidates) try {
|
|
@@ -277,11 +360,12 @@ async function renderEntityFallback(id, models, textures, resources, options) {
|
|
|
277
360
|
return null;
|
|
278
361
|
}
|
|
279
362
|
}
|
|
280
|
-
if (
|
|
281
|
-
const model = await models.load("renderchest:item/shulker_box");
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
363
|
+
if (searchName.includes("shulker") && !searchName.includes("shell")) {
|
|
364
|
+
const model = await models.load("renderchest:item/shulker_box").catch(() => null);
|
|
365
|
+
if (!model) return null;
|
|
366
|
+
const candidate = await findEntityTexture(resources, locator.namespace, name, "shulker");
|
|
367
|
+
const sheet = candidate && await coversSheet(textures, candidate) ? candidate : ResourceLocator.parse("minecraft:entity/shulker/shulker");
|
|
368
|
+
return renderModel(withTexture(model, "texture", sheet), textures, options).catch(() => null);
|
|
285
369
|
}
|
|
286
370
|
if (name.endsWith("banner")) try {
|
|
287
371
|
const model = await models.load("renderchest:item/banner");
|
|
@@ -292,7 +376,93 @@ async function renderEntityFallback(id, models, textures, resources, options) {
|
|
|
292
376
|
} catch {
|
|
293
377
|
return null;
|
|
294
378
|
}
|
|
379
|
+
if (name.includes("shield")) {
|
|
380
|
+
const model = await models.load("renderchest:item/shield").catch(() => null);
|
|
381
|
+
if (!model) return null;
|
|
382
|
+
const sheet = await findShieldTexture(resources, locator.namespace, name);
|
|
383
|
+
return renderModel(sheet ? withTexture(model, "texture", sheet) : model, textures, options);
|
|
384
|
+
}
|
|
385
|
+
if (name === "trident" || name.endsWith("_trident")) {
|
|
386
|
+
const model = await models.load("renderchest:item/trident").catch(() => null);
|
|
387
|
+
if (!model) return null;
|
|
388
|
+
const sheet = await findTridentTexture(resources, locator.namespace, name) ?? ResourceLocator.parse("minecraft:entity/trident");
|
|
389
|
+
return renderModel(withTexture(model, "texture", sheet), textures, {
|
|
390
|
+
...options,
|
|
391
|
+
quality: Math.max(options.quality, 4)
|
|
392
|
+
}).catch(() => null);
|
|
393
|
+
}
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Whether a sheet is a whole skin rather than an overlay. Vanilla's shulker
|
|
398
|
+
* covers 44% of its sheet; a tier trim covers under 5%.
|
|
399
|
+
*/
|
|
400
|
+
async function coversSheet(textures, locator) {
|
|
401
|
+
const texture = await textures.load(locator).catch(() => null);
|
|
402
|
+
if (!texture) return false;
|
|
403
|
+
let opaque = 0;
|
|
404
|
+
for (let offset = 3; offset < texture.data.length; offset += 4) if (texture.data[offset] > 16) opaque++;
|
|
405
|
+
return opaque / (texture.width * texture.height) > .2;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* A mod's entity sheet for a kind, preferring the one its item name points at.
|
|
409
|
+
* Not restricted to `entity/`: lootr files its whole-skin sheets straight under
|
|
410
|
+
* `textures/` (`lootr:shulker`), and the caller gates on coverage anyway.
|
|
411
|
+
*/
|
|
412
|
+
async function findEntityTexture(resources, namespace, itemName, kind) {
|
|
413
|
+
const wanted = tokens(itemName).filter((token) => token !== kind && token !== "box");
|
|
414
|
+
let best = null;
|
|
415
|
+
let bestScore = -1;
|
|
416
|
+
for (const locator of await resources.listResources("texture", namespace)) {
|
|
417
|
+
if (!locator.path.includes(kind)) continue;
|
|
418
|
+
const candidate = tokens(locator.path);
|
|
419
|
+
let score = locator.path.startsWith("entity/") ? 1 : 0;
|
|
420
|
+
for (const token of wanted) if (candidate.includes(token)) score += 2;
|
|
421
|
+
if (score > bestScore) {
|
|
422
|
+
best = locator;
|
|
423
|
+
bestScore = score;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return best;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* A trident's entity sheet. Vanilla's is `entity/trident` (32×32) and mods
|
|
430
|
+
* that reuse the vanilla model ship the same path under their own namespace;
|
|
431
|
+
* a mod that names its sheet after the item instead (an `iron_trident` with
|
|
432
|
+
* `entity/iron_trident`) is covered by the item-name fallback. Searches the
|
|
433
|
+
* item's namespace first, then vanilla.
|
|
434
|
+
*/
|
|
435
|
+
async function findTridentTexture(resources, namespace, itemName) {
|
|
436
|
+
for (const source of [namespace, "minecraft"]) for (const candidate of [
|
|
437
|
+
"entity/trident",
|
|
438
|
+
"entity/trident/trident",
|
|
439
|
+
`entity/${itemName}`
|
|
440
|
+
]) {
|
|
441
|
+
const locator = new ResourceLocator(source, candidate);
|
|
442
|
+
if (await resources.hasResource("texture", locator)) return locator;
|
|
443
|
+
}
|
|
295
444
|
return null;
|
|
296
445
|
}
|
|
446
|
+
/**
|
|
447
|
+
* A mod's shield face, scored by how much of the item name it accounts for.
|
|
448
|
+
* `_blocking` is the raised pose rather than a different shield, and a
|
|
449
|
+
* `_nopattern` sheet is the plain one a banner would otherwise decorate.
|
|
450
|
+
*/
|
|
451
|
+
async function findShieldTexture(resources, namespace, itemName) {
|
|
452
|
+
const wanted = tokens(itemName).filter((token) => token !== "shield" && token !== "blocking");
|
|
453
|
+
let best = null;
|
|
454
|
+
let bestScore = 0;
|
|
455
|
+
for (const locator of await resources.listResources("texture", namespace)) {
|
|
456
|
+
if (!locator.path.startsWith("entity/") || !locator.path.includes("shield")) continue;
|
|
457
|
+
const candidate = tokens(locator.path);
|
|
458
|
+
let score = candidate.includes("nopattern") ? 1 : 0;
|
|
459
|
+
for (const token of wanted) if (candidate.includes(token)) score += 2;
|
|
460
|
+
if (score > bestScore) {
|
|
461
|
+
best = locator;
|
|
462
|
+
bestScore = score;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return best;
|
|
466
|
+
}
|
|
297
467
|
//#endregion
|
|
298
|
-
export { renderEntityFallback as n,
|
|
468
|
+
export { spawnEggTints as a, renderEntityFallback as i, dyedVariantTint as n, renderDyedVariantFallback as r, dyeVariantName as t };
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { c as normalize, g as transformVector, h as transformDirection, m as sub, r as dot, t as cross } from "./vector-CCxLae_T.js";
|
|
2
|
-
import { a as
|
|
3
|
-
import { a as drawTexturedTriangle, i as createFaceBuffer, n as clearFaceBuffer, o as phpRound, r as compactFaceBuffer, t as RowCursor } from "./rasterizer-
|
|
2
|
+
import { a as scaleTextureAlpha, n as cloneFloatTexture, r as darkenTexture, s as tintTexture, u as uvWindow } from "./blend-KXMclcHk.js";
|
|
3
|
+
import { a as drawTexturedTriangle, i as createFaceBuffer, n as clearFaceBuffer, o as phpRound, r as compactFaceBuffer, t as RowCursor } from "./rasterizer-DcVJzkxz.js";
|
|
4
4
|
//#region src/render/face.ts
|
|
5
5
|
/**
|
|
6
6
|
* Face rendering: cull, transform, project, tint, darken, rasterize — a faithful
|
|
7
7
|
* port of upstream Face::render (docs/research/renderchest-spec.md §4).
|
|
8
8
|
*/
|
|
9
|
+
function createShadeCache() {
|
|
10
|
+
return {
|
|
11
|
+
byTexture: /* @__PURE__ */ new WeakMap(),
|
|
12
|
+
bytes: 0
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
/** Roughly a small sheet reused freely, or one large sheet and no more. */
|
|
16
|
+
const MAX_SHADE_CACHE_BYTES = 67108864;
|
|
17
|
+
const FLOAT_BYTES_PER_TEXEL = 32;
|
|
9
18
|
function faceMaxZ(geometry) {
|
|
10
19
|
return Math.max(geometry.vertices[0][2], geometry.vertices[1][2], geometry.vertices[2][2], geometry.vertices[3][2]);
|
|
11
20
|
}
|
|
@@ -54,19 +63,36 @@ function renderFace(face, width, height, transformation, scratch, shadeCache) {
|
|
|
54
63
|
const absU2 = geometry.uv2[0] * face.texture.width;
|
|
55
64
|
const absV2 = geometry.uv2[1] * face.texture.height;
|
|
56
65
|
const tint = geometry.tintIndex !== null ? face.tint : null;
|
|
57
|
-
const darkness = 1 - face.light.lightLevelForNormal(shadeDirection);
|
|
58
|
-
const
|
|
59
|
-
let
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
const darkness = geometry.emissive ? 0 : 1 - face.light.lightLevelForNormal(shadeDirection);
|
|
67
|
+
const [windowX1, windowY1, windowX2, windowY2] = uvWindow(face.texture, absU1, absV1, absU2, absV2);
|
|
68
|
+
let shading = {
|
|
69
|
+
tint,
|
|
70
|
+
darkness,
|
|
71
|
+
alpha: geometry.alpha,
|
|
72
|
+
windowX1,
|
|
73
|
+
windowY1,
|
|
74
|
+
windowX2,
|
|
75
|
+
windowY2
|
|
76
|
+
};
|
|
77
|
+
let texture = face.texture;
|
|
78
|
+
const shadeKey = `${tint ? `${tint.r},${tint.g},${tint.b}` : "-"}|${darkness}|${geometry.alpha}|${absU1},${absV1},${absU2},${absV2}`;
|
|
79
|
+
const byKey = shadeCache?.byTexture.get(face.texture);
|
|
80
|
+
const cached = byKey?.get(shadeKey);
|
|
81
|
+
const cloneBytes = face.texture.width * face.texture.height * FLOAT_BYTES_PER_TEXEL;
|
|
82
|
+
if (cached) {
|
|
83
|
+
texture = cached;
|
|
84
|
+
shading = null;
|
|
85
|
+
} else if (shadeCache && shadeCache.bytes + cloneBytes <= MAX_SHADE_CACHE_BYTES) {
|
|
86
|
+
const shaded = cloneFloatTexture(face.texture);
|
|
87
|
+
if (tint) tintTexture(shaded, tint.r, tint.g, tint.b);
|
|
88
|
+
darkenTexture(shaded, darkness, absU1, absV1, absU2, absV2);
|
|
89
|
+
if (geometry.alpha < 1) scaleTextureAlpha(shaded, geometry.alpha, absU1, absV1, absU2, absV2);
|
|
90
|
+
const store = byKey ?? /* @__PURE__ */ new Map();
|
|
91
|
+
store.set(shadeKey, shaded);
|
|
92
|
+
shadeCache.byTexture.set(face.texture, store);
|
|
93
|
+
shadeCache.bytes += cloneBytes;
|
|
94
|
+
texture = shaded;
|
|
95
|
+
shading = null;
|
|
70
96
|
}
|
|
71
97
|
const uvs = [
|
|
72
98
|
[geometry.uv1[0], geometry.uv1[1]],
|
|
@@ -97,9 +123,9 @@ function renderFace(face, width, height, transformation, scratch, shadeCache) {
|
|
|
97
123
|
};
|
|
98
124
|
};
|
|
99
125
|
const cursor = new RowCursor();
|
|
100
|
-
drawTexturedTriangle(point(0), point(2), point(3), buffer, texture, cursor);
|
|
101
|
-
drawTexturedTriangle(point(0), point(1), point(2), buffer, texture, cursor);
|
|
126
|
+
drawTexturedTriangle(point(0), point(2), point(3), buffer, texture, cursor, shading);
|
|
127
|
+
drawTexturedTriangle(point(0), point(1), point(2), buffer, texture, cursor, shading);
|
|
102
128
|
return compactFaceBuffer(buffer);
|
|
103
129
|
}
|
|
104
130
|
//#endregion
|
|
105
|
-
export {
|
|
131
|
+
export { faceMaxZ as n, renderFace as r, createShadeCache as t };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { n as FloatTexture } from "./blend-8lnfxtLe.js";
|
|
2
|
+
import { t as Mat4 } from "./vector-DRKRi4--.js";
|
|
3
|
+
import { n as FaceGeometry } from "./geometry-w0yQbzDZ.js";
|
|
4
|
+
import { r as LightSource } from "./lighting-3FGRC3Af.js";
|
|
5
|
+
import { n as FaceBuffer } from "./rasterizer-BSQHEhJ-.js";
|
|
6
|
+
//#region src/render/face.d.ts
|
|
7
|
+
interface TintColor {
|
|
8
|
+
r: number;
|
|
9
|
+
g: number;
|
|
10
|
+
b: number;
|
|
11
|
+
}
|
|
12
|
+
interface RenderableFace {
|
|
13
|
+
geometry: FaceGeometry;
|
|
14
|
+
texture: FloatTexture;
|
|
15
|
+
light: LightSource;
|
|
16
|
+
tint: TintColor | null;
|
|
17
|
+
/** Untransformed model-space max Z — upstream's stable pre-sort key. */
|
|
18
|
+
maxZ: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Pre-shaded textures for one model render, with a byte ceiling.
|
|
22
|
+
*
|
|
23
|
+
* Shading a texel as it is sampled is always correct, but for a small sheet it
|
|
24
|
+
* is slower than shading one copy and reusing it: a block model's faces repeat
|
|
25
|
+
* the same few (window, light level) pairs, and there are far more drawn pixels
|
|
26
|
+
* than texels. The reverse holds for a detailed model on a big sheet — every
|
|
27
|
+
* face is its own key, and the copies are what once reached 20 GB for a single
|
|
28
|
+
* icon. So cache while it is cheap and fall through to per-sample shading once
|
|
29
|
+
* the budget is spent; the two produce identical output.
|
|
30
|
+
*/
|
|
31
|
+
interface FaceShadeCache {
|
|
32
|
+
byTexture: WeakMap<FloatTexture, Map<string, FloatTexture>>;
|
|
33
|
+
bytes: number;
|
|
34
|
+
}
|
|
35
|
+
declare function createShadeCache(): FaceShadeCache;
|
|
36
|
+
declare function faceMaxZ(geometry: FaceGeometry): number;
|
|
37
|
+
/** Returns null when the face is culled, degenerate, or has a zero-area UV. */
|
|
38
|
+
declare function renderFace(face: RenderableFace, width: number, height: number, transformation: Mat4,
|
|
39
|
+
/** Reused across a model's faces; cleared here, compacted before return. */
|
|
40
|
+
scratch?: FaceBuffer,
|
|
41
|
+
/** Bounded store of pre-shaded textures; omitted means always shade per sample. */
|
|
42
|
+
shadeCache?: FaceShadeCache): FaceBuffer | null;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { faceMaxZ as a, createShadeCache as i, RenderableFace as n, renderFace as o, TintColor as r, FaceShadeCache as t };
|
|
@@ -58,9 +58,14 @@ function averageColor(texture) {
|
|
|
58
58
|
async function paintBucketFluid(bucket, fluid, textures, resources) {
|
|
59
59
|
const fluidLocator = ResourceLocator.tryParse(fluid);
|
|
60
60
|
if (!fluidLocator) return false;
|
|
61
|
+
const bare = fluidLocator.path.replace(/^fluid_/, "").replace(/_(?:still|flowing|source)$/, "");
|
|
62
|
+
const names = /* @__PURE__ */ new Set([fluidLocator.path, bare]);
|
|
61
63
|
let still = null;
|
|
62
|
-
for (const
|
|
63
|
-
|
|
64
|
+
for (const name of names) {
|
|
65
|
+
for (const pattern of STILL_TEXTURE_PATTERNS) {
|
|
66
|
+
still = await textures.load(new ResourceLocator(fluidLocator.namespace, pattern(name)));
|
|
67
|
+
if (still) break;
|
|
68
|
+
}
|
|
64
69
|
if (still) break;
|
|
65
70
|
}
|
|
66
71
|
still ??= resources ? await particleTexture(fluidLocator, textures, resources) : null;
|