mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
OptiFine CTM emissive tiles: blocks keep their overlays first; every tile pairs
Block overlays come before tiles under the shared cap, so a pack's many tiles can't crowd out vanilla blocks'; any tile named by its file pairs, not only those under ctm/; the doc comment is back on load_optifine. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
6d89cb0195
commit
752049907d
2 files changed
+32
-24
No files matched your search
@@ -28,21 +28,19 @@ pub fn load(root: &Path, sprites: &mut Sprites) {
|
||||
}
|
||||
}
|
||||
|
||||
/// OptiFine's emissive overlays of the block sprites already loaded (what the terrain draws;
|
||||
/// items draw from the HUD atlas): for each
|
||||
/// `<ns>:block/<name>`, or connected-texture tile `assets/<ns>/optifine/ctm/.../<name>.png`,
|
||||
/// whose `<name><suffix>.png` sits beside it, the overlay is loaded too and paired with it, first
|
||||
/// by name, at most [`MAX`] - [`NATIVE`] (native mods keep their share of
|
||||
/// the table). A pack without such files adds nothing.
|
||||
/// A connected-texture tile's sprite name (its resource path, `Sprites::insert_file`'s) without
|
||||
/// `.png`.
|
||||
fn ctm_tile(name: &str) -> Option<&str> {
|
||||
let stem = name.strip_suffix(".png")?;
|
||||
let mut parts = stem.strip_prefix("assets/")?.splitn(3, '/');
|
||||
let (_namespace, top, rest) = (parts.next()?, parts.next()?, parts.next()?);
|
||||
(matches!(top, "optifine" | "mcpatcher") && rest.starts_with("ctm/")).then_some(stem)
|
||||
/// A connected-texture tile's sprite name without `.png`: tiles outside `textures/` are named by
|
||||
/// their resource path (`Sprites::insert_file`, which only they use), block sprites by an id.
|
||||
fn tile_file(name: &str) -> Option<&str> {
|
||||
name.strip_prefix("assets/")?;
|
||||
name.strip_suffix(".png")
|
||||
}
|
||||
|
||||
/// OptiFine's emissive overlays of the block sprites already loaded (what the terrain draws;
|
||||
/// items draw from the HUD atlas): for each
|
||||
/// `<ns>:block/<name>`, or connected-texture tile `assets/<ns>/.../<name>.png`, whose
|
||||
/// `<name><suffix>.png` sits beside it, the overlay is loaded too and paired with it, blocks
|
||||
/// first, then tiles, each by name, at most [`MAX`] - [`NATIVE`] (native mods keep their share of
|
||||
/// the table). A pack without such files adds nothing.
|
||||
pub fn load_optifine(root: &Path, sprites: &mut Sprites) -> Vec<(String, String)> {
|
||||
let suffix = horizon_optifine::emissive::suffix(root);
|
||||
// Blocks with identical pixels share a layer (and the shader pairs by layer): a shared
|
||||
@@ -51,7 +49,7 @@ pub fn load_optifine(root: &Path, sprites: &mut Sprites) -> Vec<(String, String)
|
||||
for layer in sprites.layers.values() {
|
||||
*sharing.entry(*layer).or_default() += 1;
|
||||
}
|
||||
let bases: Vec<String> = sprites
|
||||
let mut bases: Vec<String> = sprites
|
||||
.layers
|
||||
.iter()
|
||||
.filter(|(name, layer)| {
|
||||
@@ -59,14 +57,16 @@ pub fn load_optifine(root: &Path, sprites: &mut Sprites) -> Vec<(String, String)
|
||||
&& (name
|
||||
.split_once(':')
|
||||
.is_some_and(|(_, p)| p.starts_with("block/") && !p.ends_with(&suffix))
|
||||
|| ctm_tile(name).is_some_and(|stem| !stem.ends_with(&suffix)))
|
||||
|| tile_file(name).is_some_and(|stem| !stem.ends_with(&suffix)))
|
||||
})
|
||||
.map(|(name, _)| name.clone())
|
||||
.collect();
|
||||
// Blocks before tiles: a pack's many tiles must not crowd vanilla blocks' overlays out.
|
||||
bases.sort_by_key(|name| (tile_file(name).is_some(), name.clone()));
|
||||
let mut pairs = Vec::new();
|
||||
for base in bases {
|
||||
// A tile is named by its file, a block sprite by its id.
|
||||
let (overlay, file) = match ctm_tile(&base) {
|
||||
let (overlay, file) = match tile_file(&base) {
|
||||
Some(stem) => {
|
||||
let overlay = format!("{stem}{suffix}.png");
|
||||
(overlay.clone(), root.join(overlay))
|
||||
@@ -223,25 +223,33 @@ mod tests {
|
||||
png(&tiles.join("0.png"), 230);
|
||||
png(&tiles.join("0_glow.png"), 240);
|
||||
png(&tiles.join("1.png"), 250);
|
||||
for tile in ["0", "1"] {
|
||||
// A tile outside `ctm/` (`tiles=~/glass/2`) is a tile all the same.
|
||||
png(&root.join("assets/minecraft/optifine/glass/2.png"), 245);
|
||||
png(
|
||||
&root.join("assets/minecraft/optifine/glass/2_glow.png"),
|
||||
246,
|
||||
);
|
||||
for tile in ["ctm/lamp/0", "ctm/lamp/1", "glass/2"] {
|
||||
sprites
|
||||
.insert_file(
|
||||
&root,
|
||||
&format!("assets/minecraft/optifine/ctm/lamp/{tile}.png"),
|
||||
)
|
||||
.insert_file(&root, &format!("assets/minecraft/optifine/{tile}.png"))
|
||||
.unwrap();
|
||||
}
|
||||
let pairs = load_optifine(&root, &mut sprites);
|
||||
assert_eq!(
|
||||
pairs,
|
||||
// Blocks first, then tiles.
|
||||
[
|
||||
(
|
||||
"minecraft:block/deepslate".into(),
|
||||
"minecraft:block/deepslate_glow".into()
|
||||
),
|
||||
(
|
||||
"assets/minecraft/optifine/ctm/lamp/0.png".into(),
|
||||
"assets/minecraft/optifine/ctm/lamp/0_glow.png".into()
|
||||
),
|
||||
(
|
||||
"minecraft:block/deepslate".into(),
|
||||
"minecraft:block/deepslate_glow".into()
|
||||
"assets/minecraft/optifine/glass/2.png".into(),
|
||||
"assets/minecraft/optifine/glass/2_glow.png".into()
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
@@ -40,7 +40,7 @@ harness named checks that loader against vanilla).
|
||||
| Item definitions and item models (all model types, display transforms, tints) | `items/`, `models/item/` | works | `test_item_model_parity` |
|
||||
| Custom entity models (OptiFine/EMF): a `.jem` reshapes a mob's model layer, with its animations and texture; Entity Model Features' files win over OptiFine's | `optifine/cem/`, `emf/cem/` | partly | `mobs::cem` and `mobs::cem_anim` unit tests; no per-bone textures, no random models, no textures under `optifine/` (vanilla's own entity models are code in 26.3, which `test_entity_model_parity` checks) |
|
||||
| Random entity textures (OptiFine/ETF): numbered variants and their rules (biome, height, name, profession, colour, baby, health, moon, time, weather, size, blocks), chosen per entity from its UUID and rechecked once a second | `optifine/random/`, `optifine/mob/`, `mcpatcher/mob/`, `etf/random/`, `textures/entity/` with a `.properties` | partly | `horizon-optifine` `random` and `random_textures` tests, `mobs::random_textures` tests; no `nbt.*` or ETF's extra conditions (teams, items...), no block entities |
|
||||
| Connected textures (OptiFine/Continuity): every method (`ctm`, `ctm_compact` with `ctm.N`, `horizontal`, `vertical`, `horizontal+vertical`, `vertical+horizontal`, `top`, `random`, `repeat`, `fixed`, `overlay`, `overlay_ctm`/`_random`/`_repeat`/`_fixed`, and Continuity's `overlay_horizontal`/`_vertical`/`_h+v`/`_v+h`), `matchTiles`/`matchBlocks` and the file-name forms, `tiles` (ranges, names, paths, `<skip>`, `<default>`), `weight`, `faces`, `biomes`, `heights` (and the old `minHeight`/`maxHeight`), `connect`, `connectTiles`/`connectBlocks`, `innerSeams`, `weights`, `randomLoops`, `symmetry`, `linked`, `width`/`height`, `tintIndex`/`tintBlock`, `layer`; Continuity's `orient`, `prioritize`, `optifineOnly` and its stacked-pane culling; tiles a rule picked matched again by another; panes drawn with OptiFine's unmirrored UVs | `optifine/ctm/**/*.properties` (and `mcpatcher/ctm/`) in any namespace, with their tiles | partly | `horizon-optifine` `ctm` and `ctm::connect` tests (the tile tables read off OptiFine's template images), `connected` and `mesher::quarter_tests` tests; `name=` rules are not loaded (the client meshing chunks never receives block entities' custom names, so they could never match); `random` picks from its own fixed hash, so random tiles land in other places than in OptiFine (same weights); tiles glow with their `_e` overlays as blocks do |
|
||||
| Connected textures (OptiFine/Continuity): every method (`ctm`, `ctm_compact` with `ctm.N`, `horizontal`, `vertical`, `horizontal+vertical`, `vertical+horizontal`, `top`, `random`, `repeat`, `fixed`, `overlay`, `overlay_ctm`/`_random`/`_repeat`/`_fixed`, and Continuity's `overlay_horizontal`/`_vertical`/`_h+v`/`_v+h`), `matchTiles`/`matchBlocks` and the file-name forms, `tiles` (ranges, names, paths, `<skip>`, `<default>`), `weight`, `faces`, `biomes`, `heights` (and the old `minHeight`/`maxHeight`), `connect`, `connectTiles`/`connectBlocks`, `innerSeams`, `weights`, `randomLoops`, `symmetry`, `linked`, `width`/`height`, `tintIndex`/`tintBlock`, `layer`; Continuity's `orient`, `prioritize`, `optifineOnly` and its stacked-pane culling; tiles a rule picked matched again by another; panes drawn with OptiFine's unmirrored UVs | `optifine/ctm/**/*.properties` (and `mcpatcher/ctm/`) in any namespace, with their tiles | partly | `horizon-optifine` `ctm` and `ctm::connect` tests (the tile tables read off OptiFine's template images), `connected` and `mesher::quarter_tests` tests; `name=` rules are not loaded (the client meshing chunks never receives block entities' custom names, so they could never match); `random` picks from its own fixed hash, so random tiles land in other places than in OptiFine (same weights); tiles glow with their `_e` overlays, sharing the emissive row's table and limits (block overlays come first) |
|
||||
| Emissive textures (OptiFine/ETF): `<texture>_e.png` (or the pack's `suffix.emissive`) drawn full bright over mobs, their layers and armour, armour stands, the elytra, the dragon, thrown tridents, block entities, placed blocks and connected-texture tiles | `<texture>_e.png` beside its texture (also random variants' and blink frames'); the suffix from `optifine/emissive.properties`, `etf/emissive.properties` or `textures/emissive.properties` | partly | `horizon-optifine` `emissive` tests, `mobs::render::emissive_tests`, `block_entity_render` and `native_emissive` tests; at most 96 block overlays (native mods keep 32 more), cutout; none on translucent faces, nor on blocks whose texture is pixel-identical to another's (they share a layer); not over items, armour trims, other projectiles, minecarts or end crystals |
|
||||
| Blinking textures (ETF): `<texture>_blink.png` and `_blink2.png`, `blinkLength`/`blinkFrequency` | `textures/entity/`, random variants' folders | works | `horizon-optifine` `blink` tests, `mobs::render` blink test; sleeping villagers keep their eyes shut |
|
||||
| Textures, any resolution (16x to 512x) | `textures/` | works | atlases stitched from the overlay; Faithful 32x, Default HD 128x and FPBR measured in [reuse-pack-overlays.md](reuse-pack-overlays.md) |
|
||||
|
||||
Reference in new issue
Block a user