mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
Merge pull request #10502 from arslanarm/shaderpacks/dimension-folder-gbuffers
Shader packs: terrain without a program in the pack is drawn by nothing
This commit is contained in:
3 files changed
+131
-3
No files matched your search
@@ -40,6 +40,9 @@ mod higher_shadowcolor_tests;
|
||||
#[cfg(test)]
|
||||
mod single_side_tests;
|
||||
|
||||
#[cfg(test)]
|
||||
mod undrawn_terrain_tests;
|
||||
|
||||
#[cfg(test)]
|
||||
mod shadow_faces_tests;
|
||||
|
||||
@@ -558,6 +561,10 @@ pub struct PackPost {
|
||||
terrain_cutout: Option<Pass>,
|
||||
/// What draws translucent terrain (`gbuffers_water` or its fallback), after `deferred`.
|
||||
water: Option<Pass>,
|
||||
/// The pack has no program for solid and cutout terrain, or for translucent terrain:
|
||||
/// nothing draws it (`horizon_shaders::Post::terrain_undrawn`).
|
||||
terrain_undrawn: bool,
|
||||
water_undrawn: bool,
|
||||
/// What draws the sky (`gbuffers_skybasic` or its fallback), before terrain, and its vertices.
|
||||
sky: Option<Sky>,
|
||||
/// What draws entities and block entities, after terrain, and their vertices.
|
||||
@@ -2300,6 +2307,7 @@ impl PackPost {
|
||||
cull: g.cull,
|
||||
});
|
||||
let split = post.terrain.is_some() && post.terrain_cutout.is_some();
|
||||
let (terrain_undrawn, water_undrawn) = (post.terrain_undrawn, post.water_undrawn);
|
||||
let mut terrain = post
|
||||
.terrain
|
||||
.zip(terrain_geometry.as_ref())
|
||||
@@ -2846,6 +2854,8 @@ impl PackPost {
|
||||
terrain,
|
||||
terrain_cutout,
|
||||
water,
|
||||
terrain_undrawn,
|
||||
water_undrawn,
|
||||
sky,
|
||||
entities,
|
||||
clouds,
|
||||
@@ -4073,9 +4083,9 @@ impl PackPost {
|
||||
})
|
||||
}
|
||||
|
||||
/// Whether the pack draws terrain itself.
|
||||
/// Whether the pack draws terrain itself, or has nothing draw it.
|
||||
pub fn has_terrain(&self) -> bool {
|
||||
self.terrain.is_some() || self.terrain_cutout.is_some()
|
||||
self.terrain.is_some() || self.terrain_cutout.is_some() || self.terrain_undrawn
|
||||
}
|
||||
|
||||
/// Whether the pack's shadow pass draws terrain (`shadow_view`).
|
||||
@@ -4103,7 +4113,7 @@ impl PackPost {
|
||||
|
||||
/// Whether the pack draws translucent terrain itself.
|
||||
pub fn has_water(&self) -> bool {
|
||||
self.water.is_some()
|
||||
self.water.is_some() || self.water_undrawn
|
||||
}
|
||||
|
||||
/// The names of the programs that run, in order.
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//! A pack with no program for terrain draws none (#10455): Iris 1.11.7 drew no terrain, solid
|
||||
//! or translucent, into any buffer or depth with probe packs of ours having no gbuffers
|
||||
//! programs. The game hands the pack its terrain, so it doesn't draw it either. The programs
|
||||
//! here are original and cut down.
|
||||
use super::destination_tests::Fixture;
|
||||
use std::io::{Cursor, Write};
|
||||
|
||||
const VERTEX: &str = "#version 120\nvoid main() { gl_Position = ftransform(); }\n";
|
||||
const WHITE: &str =
|
||||
"#version 120\n/* DRAWBUFFERS:0 */\nvoid main() { gl_FragData[0] = vec4(1.0); }\n";
|
||||
|
||||
/// A pack with `programs` (each drawing white into colortex0) loaded for a game that can hand it
|
||||
/// terrain: whether it takes solid and translucent terrain from the game.
|
||||
fn takes_terrain(programs: &[&str]) -> Option<(bool, bool)> {
|
||||
let gpu = Fixture::new()?;
|
||||
let mut zip = zip::ZipWriter::new(Cursor::new(Vec::new()));
|
||||
for name in programs {
|
||||
for (ext, source) in [("vsh", VERTEX), ("fsh", WHITE)] {
|
||||
zip.start_file(
|
||||
format!("shaders/{name}.{ext}"),
|
||||
zip::write::SimpleFileOptions::default(),
|
||||
)
|
||||
.unwrap();
|
||||
zip.write_all(source.as_bytes()).unwrap();
|
||||
}
|
||||
}
|
||||
let pack = horizon_shaders::Pack::from_zip_bytes(
|
||||
"undrawn-terrain",
|
||||
zip.finish().unwrap().into_inner(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut macros = horizon_shaders::Macros::standard();
|
||||
let (properties, _) = horizon_shaders::read_properties(&pack, &mut macros);
|
||||
let inputs = horizon_shaders::GameInputs {
|
||||
terrain: Some(Default::default()),
|
||||
..Default::default()
|
||||
};
|
||||
let post = horizon_shaders::load_post(&pack, "", &properties, ¯os, &inputs);
|
||||
let post = gpu.try_build(post).ok()?;
|
||||
Some((post.has_terrain(), post.has_water()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_pack_without_terrain_programs_takes_terrain_from_the_game() {
|
||||
let Some(taken) = takes_terrain(&["composite"]) else {
|
||||
return;
|
||||
};
|
||||
assert_eq!(taken, (true, true));
|
||||
}
|
||||
@@ -426,6 +426,14 @@ pub struct Post {
|
||||
pub terrain_cutout: Option<PostProgram>,
|
||||
/// What draws translucent terrain (water, stained glass) after deferred.
|
||||
pub water: Option<PostProgram>,
|
||||
/// The pack has no program for solid and cutout terrain (none of `gbuffers_terrain`'s
|
||||
/// chain, nor `_solid` or `_cutout`), or for translucent terrain (none of
|
||||
/// `gbuffers_water`'s): nothing draws that terrain, into no buffer nor depth. Iris 1.11.7
|
||||
/// drew no terrain with our probe packs having no gbuffers programs, at the root or in a
|
||||
/// dimension's folder (#10455). A program that is there but doesn't load still leaves its
|
||||
/// terrain to the game.
|
||||
pub terrain_undrawn: bool,
|
||||
pub water_undrawn: bool,
|
||||
/// What draws the sky (disc, sunset, stars, void) before terrain.
|
||||
pub sky: Option<PostProgram>,
|
||||
/// What draws the sun and moon, between the sunset and the stars.
|
||||
@@ -639,6 +647,8 @@ pub fn load_post(
|
||||
terrain: None,
|
||||
terrain_cutout: None,
|
||||
water: None,
|
||||
terrain_undrawn: false,
|
||||
water_undrawn: false,
|
||||
sky: None,
|
||||
sky_textured: None,
|
||||
entities: None,
|
||||
@@ -939,6 +949,19 @@ pub fn load_post(
|
||||
// gbuffers_water falls back to gbuffers_terrain's chain (2.3).
|
||||
let water = gbuffers(&WATER, Group::Translucent, terrain);
|
||||
loader.post.notes.extend(lone);
|
||||
loader.post.terrain_undrawn = !has_solid && !has_cutout;
|
||||
loader.post.water_undrawn = !WATER.iter().any(|n| loader.has(n));
|
||||
for (undrawn, part) in [
|
||||
(loader.post.terrain_undrawn, "terrain"),
|
||||
(loader.post.water_undrawn, "translucent terrain"),
|
||||
] {
|
||||
if undrawn {
|
||||
loader
|
||||
.post
|
||||
.notes
|
||||
.push(format!("no program for {part}; nothing draws it"));
|
||||
}
|
||||
}
|
||||
loader.post.terrain = solid;
|
||||
loader.post.water = water.map(|mut p| {
|
||||
p.blend = blend(properties, &p.name).unwrap_or(Some(TRANSLUCENT_BLEND));
|
||||
@@ -1673,6 +1696,52 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// #10455, with probe packs of ours in Iris 1.11.7: a pack (or the dimension folder it
|
||||
/// uses) with no gbuffers programs drew no terrain, solid or translucent, into any buffer or
|
||||
/// depth, and the root folder's gbuffers programs didn't draw the Nether's terrain when
|
||||
/// `world-1` had none. A `gbuffers_water` alone draws translucent terrain only (Horizon's
|
||||
/// choice; not measured in Iris).
|
||||
#[test]
|
||||
fn a_folder_without_terrain_programs_draws_no_terrain() {
|
||||
const VSH: &str = "#version 120\nvoid main() { gl_Position = ftransform(); }";
|
||||
const FSH: &str =
|
||||
"#version 120\n/* DRAWBUFFERS:0 */\nvoid main() { gl_FragData[0] = vec4(1.0); }";
|
||||
let pack = Pack::from_zip_bytes(
|
||||
"original-undrawn-terrain",
|
||||
crate::pack::tests::zip(&[
|
||||
("shaders/gbuffers_basic.vsh", VSH),
|
||||
("shaders/gbuffers_basic.fsh", FSH),
|
||||
("shaders/world-1/composite.vsh", VSH),
|
||||
("shaders/world-1/composite.fsh", FSH),
|
||||
("shaders/world1/gbuffers_water.vsh", VSH),
|
||||
("shaders/world1/gbuffers_water.fsh", FSH),
|
||||
]),
|
||||
)
|
||||
.unwrap();
|
||||
let inputs = GameInputs {
|
||||
terrain: Some(GbuffersInputs::default()),
|
||||
..Default::default()
|
||||
};
|
||||
let load = |folder: &str| {
|
||||
let post = load_post(
|
||||
&pack,
|
||||
folder,
|
||||
&Properties::default(),
|
||||
&Macros::standard(),
|
||||
&inputs,
|
||||
);
|
||||
(
|
||||
post.terrain.is_some(),
|
||||
post.water.is_some(),
|
||||
post.terrain_undrawn,
|
||||
post.water_undrawn,
|
||||
)
|
||||
};
|
||||
assert_eq!(load(""), (true, true, false, false));
|
||||
assert_eq!(load("world-1"), (false, false, true, true));
|
||||
assert_eq!(load("world1"), (false, true, true, false));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn named_dimension_folder_reaches_the_program_loader() {
|
||||
let pack = Pack::from_zip_bytes(
|
||||
|
||||
Reference in new issue
Block a user