Compare commits

...
Author SHA1 Message Date
Ludovic MarieandClaude Sonnet 5.5 ec4e5e7f7d Merge origin/main into feat/world-post-chain-hook
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-26 01:59:55 +01:00
Ludovic MarieandClaude Opus 5.5 99a8ea053b Renderer: one post-processing chain hook over the world, for every pack kind
The world's own target (world_post::prepare) and the dispatch that draws it
onto the screen under the hand and HUD now go through world_post::Chain, an
enum with one variant per kind of post-processing. Today its only variant is
the shaders/-format pack (PackPost, unchanged); Horizon's own WGSL packs add
theirs next, sharing the hook instead of duplicating it. The dimension the
shader pack was last set for is kept beside it. No change in behaviour.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-25 15:42:54 +01:00
2 changed files with 59 additions and 18 deletions

No files matched your search

+19 -17
View File
@@ -471,8 +471,10 @@ pub struct Renderer {
occlusion: occlusion::Occlusion,
/// Resolution scale and FXAA (Horizon settings).
world_post: world_post::Post,
/// The shader pack's post-processing, and the dimension (legacy id) it was loaded for.
pack_post: Option<(i32, Option<pack_post::PackPost>)>,
/// The post-processing chain over the world, if any (`world_post::Chain`).
post_chain: Option<world_post::Chain>,
/// The dimension (legacy id) the shader pack was last set for.
shader_pack_dimension: Option<i32>,
/// The block sprites as one atlas, while a shader pack is loaded.
pack_atlas: Option<pack_atlas::PackAtlas>,
pub hud: HudRenderer,
@@ -2361,7 +2363,8 @@ impl Renderer {
block_entity_revision: next_block_entity_revision(),
occlusion: occlusion::Occlusion::new(crate::chunk::MIN_Y, crate::chunk::HEIGHT / 16),
world_post,
pack_post: None,
post_chain: None,
shader_pack_dimension: None,
pack_atlas: None,
hud,
menu_blur: None,
@@ -2831,12 +2834,13 @@ impl Renderer {
let programs = p.programs().into_iter().map(str::to_owned).collect();
(programs, p.notes.clone())
});
self.pack_post = Some((dimension, post));
self.post_chain = post.map(world_post::Chain::Java);
self.shader_pack_dimension = Some(dimension);
report
}
/// The dimension the shader pack was last set for.
pub fn shader_pack_dimension(&self) -> Option<i32> {
self.pack_post.as_ref().map(|p| p.0)
self.shader_pack_dimension
}
/// The Mipmap Levels option: block textures sample at most `levels`
/// reduced copies (0: none).
@@ -3712,11 +3716,11 @@ impl Renderer {
timer.begin(&mut encoder);
}
// The world's targets: the screen, or the scaled target of `post`.
let pack_post = !frame.title && self.pack_post.as_ref().is_some_and(|p| p.1.is_some());
let post_chain = !frame.title && self.post_chain.is_some();
let scaled = self.world_post.prepare(
&self.device,
[self.config.width, self.config.height],
pack_post,
post_chain,
);
let (world_view, world_depth) = match &scaled {
Some((color, depth)) => (color, depth),
@@ -3754,8 +3758,8 @@ impl Renderer {
view: world_depth,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(0.0),
// Phase 2 of occlusion culling draws over it; a shader pack reads it.
store: if cull.is_some() || pack_post {
// Phase 2 of occlusion culling draws over it; a post chain reads it.
store: if cull.is_some() || post_chain {
wgpu::StoreOp::Store
} else {
wgpu::StoreOp::Discard
@@ -3818,7 +3822,7 @@ impl Renderer {
&mut encoder,
world_view,
world_depth,
pack_post,
post_chain,
);
pass.set_bind_group(0, &self.group, &[]);
pass.set_pipeline(&flat.solid);
@@ -3847,7 +3851,7 @@ impl Renderer {
&mut encoder,
world_view,
world_depth,
pack_post,
post_chain,
);
pass.set_bind_group(0, &self.group, &[]);
pass.set_pipeline(&self.solid);
@@ -4024,19 +4028,17 @@ impl Renderer {
}
}
if let Some((color, depth)) = &scaled
&& pack_post
&& let Some((_, Some(post))) = &mut self.pack_post
&& post_chain
&& let Some(chain) = &mut self.post_chain
{
let size = self.world_post.size().unwrap_or([1, 1]);
post.run(
chain.run(
&self.device,
&self.queue,
&mut encoder,
color,
depth,
(color, depth),
&view_target,
frame,
&frame.pack,
size,
[self.config.width, self.config.height],
);
+40 -1
View File
@@ -1,7 +1,8 @@
//! Resolution scale and FXAA (Horizon settings): the world renders into its
//! own target at the scaled size, then one full-screen pass copies or
//! anti-aliases it onto the screen, under the hand and HUD. With neither on,
//! the world renders straight to the screen.
//! the world renders straight to the screen. A post-processing chain
//! ([`Chain`]) takes that target instead and draws onto the screen itself.
struct WorldTarget {
size: [u32; 2],
@@ -216,3 +217,41 @@ impl Post {
pass.draw(0..3, 0..1);
}
}
/// A post-processing chain over the world: it reads the world's own target
/// (colour, and depth reversed) and draws onto the screen, under the hand and
/// HUD. One runs at a time; each kind keeps its own state.
pub enum Chain {
/// A shader pack in the `shaders/` format (`pack_post.rs`).
Java(super::pack_post::PackPost),
}
impl Chain {
/// Draws the world target `world` (colour, depth) of `size` onto `screen` of `window`.
pub fn run(
&mut self,
device: &wgpu::Device,
queue: &wgpu::Queue,
encoder: &mut wgpu::CommandEncoder,
world: (&wgpu::TextureView, &wgpu::TextureView),
screen: &wgpu::TextureView,
frame: &super::Frame,
size: [u32; 2],
window: [u32; 2],
) {
match self {
Chain::Java(post) => post.run(
device,
queue,
encoder,
world.0,
world.1,
screen,
frame,
&frame.pack,
size,
window,
),
}
}
}