mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-09 10:39:46 -10:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27740e2e8f | ||
|
|
a7d211a1fc | ||
|
|
7ae28b9d3e | ||
|
|
950c368a3c |
No files matched your search
Generated
+1
@@ -1858,6 +1858,7 @@ name = "horizon-render-pipeline"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"naga",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -7714,7 +7714,7 @@ impl Renderer {
|
||||
inputs.declarations.push_str(
|
||||
"layout(set = 5, binding = 0) readonly buffer HzIndices { uint hz_indices[]; };\n",
|
||||
);
|
||||
horizon_shaders::GeometryInputs {
|
||||
horizon_render_pipeline::GeometryInputs {
|
||||
inputs,
|
||||
pull: pack_atlas::PULL.to_owned(),
|
||||
index: "hz_indices[@]".to_owned(),
|
||||
@@ -7737,7 +7737,7 @@ impl Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
fn pack_terrain_inputs(&mut self) -> Option<horizon_shaders::GbuffersInputs> {
|
||||
fn pack_terrain_inputs(&mut self) -> Option<horizon_render_pipeline::GbuffersInputs> {
|
||||
// Flat draws whenever the device has them (`render` keeps them on with a pack).
|
||||
let flat = self.flat.is_some() && self.flat_on;
|
||||
// Flat draws read each sprite's place from a table: the atlas is stitched as the game's.
|
||||
|
||||
@@ -597,9 +597,9 @@ const FACE: &str = " uint hz_q = (uint(gl_VertexIndex) & ~3u) * 6u;\n \
|
||||
/// quad lands whole in one part. The colour's alpha can't decide it, as with `separateAo` it
|
||||
/// holds each vertex's own ambient occlusion.
|
||||
pub fn terrain_parts(
|
||||
terrain: &horizon_shaders::GbuffersInputs,
|
||||
terrain: &horizon_render_pipeline::GbuffersInputs,
|
||||
lava: &[u16],
|
||||
) -> [horizon_shaders::GbuffersInputs; 2] {
|
||||
) -> [horizon_render_pipeline::GbuffersInputs; 2] {
|
||||
let opaque = crate::mesher::OPAQUE_LAYER;
|
||||
let lava: String = lava
|
||||
.iter()
|
||||
@@ -619,7 +619,7 @@ pub fn terrain_parts(
|
||||
impl PackAtlas {
|
||||
/// The vertex inputs of a gbuffers program drawing terrain (`TerrainVertex`, terrain.wgsl's
|
||||
/// `vs_terrain` or, for `flat` draws, `vs_terrain_flat`), in atlas coordinates.
|
||||
pub fn terrain_inputs(&self, flat: bool) -> horizon_shaders::GbuffersInputs {
|
||||
pub fn terrain_inputs(&self, flat: bool) -> horizon_render_pipeline::GbuffersInputs {
|
||||
let mut declarations = String::from(
|
||||
"layout(location = 0) in vec3 hz_v_pos;\nlayout(location = 1) in uvec2 hz_v_uv;\n\
|
||||
layout(location = 2) in uint hz_v_layer;\nlayout(location = 3) in vec4 hz_v_color;\n\
|
||||
@@ -753,7 +753,7 @@ impl PackAtlas {
|
||||
("vaColor", "hz_Color"),
|
||||
("vaNormal", "hz_Normal"),
|
||||
];
|
||||
horizon_shaders::GbuffersInputs {
|
||||
horizon_render_pipeline::GbuffersInputs {
|
||||
declarations,
|
||||
body,
|
||||
attributes: attributes
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//! translator's `DRAW_UNIFORMS`): one slot per render stage of a uniform buffer, picked with a
|
||||
//! dynamic offset at each draw.
|
||||
|
||||
use horizon_shaders::{RENDER_STAGES, render_stage};
|
||||
use horizon_render_pipeline::{RENDER_STAGES, render_stage};
|
||||
|
||||
/// Where a run of `Frame::entities` begins, and what it is (slice 7): the run lasts until the
|
||||
/// next span. Recorded only while a shader pack draws entities, so Horizon's own frames carry
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
use horizon_shaders::render_stage;
|
||||
use horizon_render_pipeline::render_stage;
|
||||
|
||||
use super::Vertex;
|
||||
use super::pack_draw::EntitySpan;
|
||||
@@ -31,7 +31,7 @@ pub fn buffers() -> [Option<wgpu::VertexBufferLayout<'static>>; 1] {
|
||||
/// position, the shared atlas's UV, colour, light (block, sky in 16ths) and the world-oriented
|
||||
/// normal. The quad's corners, read from the same vertices at set 1, give the face normal where
|
||||
/// the vertex has none (custom geometry) and `at_tangent` along the texture's u, as for terrain.
|
||||
pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
pub fn inputs() -> horizon_render_pipeline::GbuffersInputs {
|
||||
let words = std::mem::size_of::<Vertex>() / 4;
|
||||
let mut declarations = "layout(location = 0) in vec3 hz_v_pos;\nlayout(location = 1) in vec2 hz_v_uv;\n\
|
||||
layout(location = 2) in uint hz_v_overlay;\nlayout(location = 3) in vec4 hz_v_color;\n\
|
||||
@@ -112,7 +112,7 @@ pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
// bright.
|
||||
("horizonTier", "float((hz_v_overlay >> 16u) & 255u)"),
|
||||
];
|
||||
horizon_shaders::GbuffersInputs {
|
||||
horizon_render_pipeline::GbuffersInputs {
|
||||
declarations,
|
||||
body,
|
||||
attributes: attributes
|
||||
@@ -121,7 +121,7 @@ pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
.collect(),
|
||||
after: String::new(),
|
||||
// Cutout, as vanilla's entity types mostly are (OQ-23): the loader's test at 0.1.
|
||||
alpha_test: Some(horizon_shaders::AlphaTest {
|
||||
alpha_test: Some(horizon_render_pipeline::AlphaTest {
|
||||
op: ">",
|
||||
reference: 0.1,
|
||||
}),
|
||||
@@ -138,7 +138,7 @@ pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
/// inputs of [`inputs`], each vertex read from set 1 (`hz_entity_vertices`), as `Vertex` lays
|
||||
/// it out. The draw's corners walk its quads two triangles each, as `quad_indices` does: corner
|
||||
/// `c` of a draw from vertex `first` (a whole quad) is drawn as vertex `first / 4 * 6 + c`.
|
||||
pub fn geometry_inputs() -> horizon_shaders::GeometryInputs {
|
||||
pub fn geometry_inputs() -> horizon_render_pipeline::GeometryInputs {
|
||||
let words = std::mem::size_of::<Vertex>() / 4;
|
||||
let pull = format!(
|
||||
" uint hz_pw = hz_vertex_index * {words}u;\n \
|
||||
@@ -150,7 +150,7 @@ pub fn geometry_inputs() -> horizon_shaders::GeometryInputs {
|
||||
hz_v_light = uvec4(hz_pl & 255u, (hz_pl >> 8u) & 255u, (hz_pl >> 16u) & 255u, hz_pl >> 24u);\n \
|
||||
hz_v_normal = unpackSnorm4x8(hz_entity_vertices[hz_pw + 8u]);\n"
|
||||
);
|
||||
horizon_shaders::GeometryInputs {
|
||||
horizon_render_pipeline::GeometryInputs {
|
||||
inputs: inputs(),
|
||||
pull,
|
||||
// Quad `c / 6`, corner 0, 1, 2, 0, 2, 3 of it.
|
||||
@@ -163,7 +163,7 @@ pub fn geometry_inputs() -> horizon_shaders::GeometryInputs {
|
||||
/// What `gbuffers_clouds` reads from the clouds' mesh (entity vertices, `vs_cloud`): the
|
||||
/// position moved by the clouds' offset, the colour of the face's shade from their palette,
|
||||
/// full light, the face's normal. Set 1 holds the clouds' uniform (`clouds::Uniform`).
|
||||
pub fn cloud_inputs() -> horizon_shaders::GbuffersInputs {
|
||||
pub fn cloud_inputs() -> horizon_render_pipeline::GbuffersInputs {
|
||||
let declarations = "layout(location = 0) in vec3 hz_v_pos;\nlayout(location = 1) in vec2 hz_v_uv;\n\
|
||||
layout(location = 2) in uint hz_v_overlay;\nlayout(location = 3) in vec4 hz_v_color;\n\
|
||||
layout(location = 4) in uvec4 hz_v_light;\nlayout(location = 5) in vec4 hz_v_normal;\n\
|
||||
@@ -183,7 +183,7 @@ pub fn cloud_inputs() -> horizon_shaders::GbuffersInputs {
|
||||
("vaColor", "hz_Color"),
|
||||
("vaNormal", "hz_Normal"),
|
||||
];
|
||||
horizon_shaders::GbuffersInputs {
|
||||
horizon_render_pipeline::GbuffersInputs {
|
||||
declarations,
|
||||
body,
|
||||
attributes: attributes
|
||||
|
||||
@@ -17,7 +17,7 @@ const UNIFORM: u64 = 2 * 64;
|
||||
const SLOT: u64 = 32;
|
||||
|
||||
/// What `gbuffers_hand` reads: the entity inputs, and the hand's projection from set 1.
|
||||
pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
pub fn inputs() -> horizon_render_pipeline::GbuffersInputs {
|
||||
let mut inputs = super::pack_entities::inputs();
|
||||
// No last frame's hand to measure from: the hand's `at_velocity` reads zero (and its set 1
|
||||
// has no previous vertices).
|
||||
@@ -270,7 +270,7 @@ fn translucent_quad(quad: &[Vertex]) -> bool {
|
||||
/// outside block entities, and `currentRenderedItemId`.
|
||||
fn draw_slot(id: i32, translucent: bool) -> [u8; SLOT as usize] {
|
||||
let mut bytes = [0u8; SLOT as usize];
|
||||
let stage = horizon_shaders::render_stage(if translucent {
|
||||
let stage = horizon_render_pipeline::render_stage(if translucent {
|
||||
"HAND_TRANSLUCENT"
|
||||
} else {
|
||||
"HAND_SOLID"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
/// width in pixels. The strip's corners 0 and 1 are at the start, 2 and 3 at the end (six
|
||||
/// vertices per edge: pack pipelines draw triangle lists); the
|
||||
/// width is applied in screen space after the pack's transform.
|
||||
pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
pub fn inputs() -> horizon_render_pipeline::GbuffersInputs {
|
||||
let declarations =
|
||||
"layout(location = 0) in vec3 hz_l_start;\nlayout(location = 1) in vec3 hz_l_end;\n\
|
||||
layout(location = 2) in vec4 hz_l_argb;\nlayout(location = 3) in float hz_l_width;\n\
|
||||
@@ -41,7 +41,7 @@ pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
if ((hz_l_c & 1) != 0) hz_l_o = -hz_l_o;\n \
|
||||
gl_Position.xy += hz_l_o * gl_Position.w;\n }\n"
|
||||
.to_owned();
|
||||
horizon_shaders::GbuffersInputs {
|
||||
horizon_render_pipeline::GbuffersInputs {
|
||||
declarations,
|
||||
body,
|
||||
attributes: attributes
|
||||
|
||||
@@ -125,7 +125,7 @@ enum Source {
|
||||
ShadowDepth(usize, bool),
|
||||
/// `shadowcolor0/1` read outside the shadow programs (in them they are `Color`).
|
||||
ShadowColor(usize),
|
||||
/// The boats' water patches' depth (`horizon_shaders::WATER_MASK`), for translucent terrain.
|
||||
/// The boats' water patches' depth (`horizon_render_pipeline::WATER_MASK`), for translucent terrain.
|
||||
WaterMask,
|
||||
}
|
||||
|
||||
@@ -883,7 +883,7 @@ fn fits(ty: &str, sample_type: wgpu::TextureSampleType) -> bool {
|
||||
/// `hz_depth_linear` for a program: 1 for each of shadowtex0, shadowtex1, `shadow` and
|
||||
/// `watershadow` whose depth filters (`linear`, bit n: shadowtex n). `shadow` is shadowtex1 in a
|
||||
/// program that also declares `watershadow` (6.3).
|
||||
fn depth_linear(interface: &horizon_shaders::Interface, linear: u8) -> [f32; 4] {
|
||||
fn depth_linear(interface: &horizon_render_pipeline::Interface, linear: u8) -> [f32; 4] {
|
||||
let watershadow = interface.samplers.iter().any(|s| s.name == "watershadow");
|
||||
[0, 1, usize::from(watershadow), 0].map(|n| f32::from(linear >> n & 1))
|
||||
}
|
||||
@@ -921,7 +921,7 @@ fn source(name: &str, shadow_space: bool, shadow_pass: bool, watershadow: bool)
|
||||
"lightmap" => Source::Lightmap,
|
||||
"normals" => Source::Normals,
|
||||
"specular" => Source::Specular,
|
||||
horizon_shaders::WATER_MASK => Source::WaterMask,
|
||||
horizon_render_pipeline::WATER_MASK => Source::WaterMask,
|
||||
n => horizon_render_pipeline::buffer_index(n).map_or(Source::Dummy, Source::Color),
|
||||
}
|
||||
}
|
||||
@@ -1503,7 +1503,7 @@ fn owned_buffers(
|
||||
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
|
||||
fn bindings(
|
||||
features: wgpu::Features,
|
||||
interface: &horizon_shaders::Interface,
|
||||
interface: &horizon_render_pipeline::Interface,
|
||||
name: &str,
|
||||
group: Group,
|
||||
buffers: &[u32],
|
||||
@@ -1574,7 +1574,7 @@ fn bindings(
|
||||
// pack of ours (#9064) bound it over `gaux2` and `noisetex` but not over names of its
|
||||
// own, where a raw texture was bound; this rule is a fit to those cases.
|
||||
let unbound = t.png
|
||||
&& t.stage != horizon_shaders::EVERY_STAGE
|
||||
&& t.stage != horizon_render_pipeline::textures::EVERY_STAGE
|
||||
&& source(&s.name, false, true, false) == Source::Dummy;
|
||||
!unbound
|
||||
&& (t.stage != pack_textures::stage(group)
|
||||
@@ -2283,7 +2283,7 @@ fn build_compute(
|
||||
device: &wgpu::Device,
|
||||
name: String,
|
||||
group: Group,
|
||||
c: horizon_shaders::ComputeProgram,
|
||||
c: horizon_render_pipeline::ComputeProgram,
|
||||
formats: &[wgpu::TextureFormat; BUFFERS],
|
||||
shadow: Option<&[wgpu::TextureFormat; SHADOW_COLORS]>,
|
||||
notes: &mut Vec<String>,
|
||||
@@ -6065,7 +6065,7 @@ mod tests {
|
||||
texture("composite", "tr", false),
|
||||
texture("composite", "gaux2", true),
|
||||
texture("composite", "noisetex", true),
|
||||
texture(horizon_shaders::EVERY_STAGE, "cp", true),
|
||||
texture(horizon_render_pipeline::textures::EVERY_STAGE, "cp", true),
|
||||
];
|
||||
let names = ["tp", "tr", "gaux2", "noisetex", "cp"];
|
||||
let interface = horizon_shaders::Interface {
|
||||
|
||||
@@ -58,7 +58,7 @@ pub(super) const ATTRIBUTES: [wgpu::VertexAttribute; 2] =
|
||||
wgpu::vertex_attr_array![0 => Float32x3, 1 => Uint32];
|
||||
|
||||
/// What `gbuffers_skybasic` reads from these vertices.
|
||||
pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
pub fn inputs() -> horizon_render_pipeline::GbuffersInputs {
|
||||
let declarations =
|
||||
"layout(location = 0) in vec3 hz_v_pos;\nlayout(location = 1) in uint hz_v_kind;\n\
|
||||
layout(set = 1, binding = 0) uniform HzSky { mat4 hz_sky_stars; vec4 hz_sky_color; \
|
||||
@@ -90,7 +90,7 @@ pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
hz_MultiTexCoord2 = hz_MultiTexCoord1;\n \
|
||||
hz_Normal = vec3(0.0, 0.0, 1.0);\n"
|
||||
);
|
||||
horizon_shaders::GbuffersInputs {
|
||||
horizon_render_pipeline::GbuffersInputs {
|
||||
declarations,
|
||||
body,
|
||||
attributes: vec![
|
||||
@@ -111,8 +111,8 @@ pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
}
|
||||
|
||||
/// What `gbuffers_skytextured` reads from the sun and moon's vertices.
|
||||
pub fn celestial_inputs() -> horizon_shaders::GbuffersInputs {
|
||||
horizon_shaders::GbuffersInputs {
|
||||
pub fn celestial_inputs() -> horizon_render_pipeline::GbuffersInputs {
|
||||
horizon_render_pipeline::GbuffersInputs {
|
||||
declarations:
|
||||
"layout(location = 0) in vec3 hz_v_pos;\nlayout(location = 1) in vec2 hz_v_uv;\n\
|
||||
layout(location = 2) in vec4 hz_v_color;\n"
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
//! which of them a program's sampler reads.
|
||||
|
||||
use horizon_render_pipeline::Kind;
|
||||
use horizon_shaders::{CustomTexture, Group, Texels, Texture, TextureDim, TextureSource};
|
||||
use horizon_render_pipeline::textures::{
|
||||
CustomTexture, Dim as TextureDim, EVERY_STAGE, Texels, Texture, TextureSource,
|
||||
};
|
||||
use horizon_shaders::Group;
|
||||
|
||||
/// What a custom texture is once uploaded: an image of ours, or one the game already has.
|
||||
pub(super) enum Image {
|
||||
@@ -127,16 +130,16 @@ pub(super) fn find(textures: &[PackTexture], group: Group, ty: &str, name: &str)
|
||||
|| buffer.is_some() && horizon_render_pipeline::buffer_index(&t.name) == buffer)
|
||||
});
|
||||
staged.or_else(|| {
|
||||
textures.iter().position(|t| {
|
||||
t.stage == horizon_shaders::EVERY_STAGE && t.dimension == dimension && t.name == name
|
||||
})
|
||||
textures
|
||||
.iter()
|
||||
.position(|t| t.stage == EVERY_STAGE && t.dimension == dimension && t.name == name)
|
||||
})
|
||||
}
|
||||
|
||||
/// The `shaders.properties` key a texture came from, for notes.
|
||||
fn key(stage: &str, name: &str) -> String {
|
||||
match stage {
|
||||
horizon_shaders::EVERY_STAGE => format!("customTexture.{name}"),
|
||||
EVERY_STAGE => format!("customTexture.{name}"),
|
||||
_ => format!("texture.{stage}.{name}"),
|
||||
}
|
||||
}
|
||||
@@ -351,7 +354,7 @@ mod tests {
|
||||
#[test]
|
||||
fn custom_textures_reach_every_program() {
|
||||
use wgpu::TextureViewDimension as D;
|
||||
let every = horizon_shaders::EVERY_STAGE;
|
||||
let every = EVERY_STAGE;
|
||||
let textures = [
|
||||
lightmap(every, "texClouds", D::D3),
|
||||
lightmap("composite", "texClouds", D::D3),
|
||||
|
||||
@@ -2717,7 +2717,7 @@ pub(super) mod initial_history_tests {
|
||||
/// `horizonWaterPatch<k>`'s `k`: patch `k / 2`, its corner and y range (even) or edges (odd).
|
||||
fn water_patch_index(name: &str) -> Option<usize> {
|
||||
let k: usize = name.strip_prefix("horizonWaterPatch")?.parse().ok()?;
|
||||
(k < 2 * horizon_shaders::WATER_PATCHES).then_some(k)
|
||||
(k < 2 * horizon_render_pipeline::WATER_PATCHES).then_some(k)
|
||||
}
|
||||
|
||||
/// The boats' water patches among the frame's entity quads (`WATER_MASK_OVERLAY`), the first
|
||||
@@ -2729,7 +2729,7 @@ pub(super) fn water_patches(entities: &[super::Vertex]) -> Vec<[[f32; 4]; 2]> {
|
||||
let mut points: Vec<[f32; 3]> = Vec::new();
|
||||
let flush = |points: &mut Vec<[f32; 3]>, out: &mut Vec<[[f32; 4]; 2]>| {
|
||||
if let Some(b) = patch_box(points)
|
||||
&& out.len() < horizon_shaders::WATER_PATCHES
|
||||
&& out.len() < horizon_render_pipeline::WATER_PATCHES
|
||||
{
|
||||
out.push(b);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use super::pack_post::Weather;
|
||||
/// What `gbuffers_weather` reads from a weather vertex: camera-relative position, the UV in
|
||||
/// repeats of the sprite, colour (with vanilla's fade) and light. Weather has no normal; the
|
||||
/// pack sees straight up.
|
||||
pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
pub fn inputs() -> horizon_render_pipeline::GbuffersInputs {
|
||||
let declarations =
|
||||
"layout(location = 0) in vec3 hz_v_pos;\nlayout(location = 1) in vec2 hz_v_uv;\n\
|
||||
layout(location = 2) in uint hz_v_overlay;\nlayout(location = 3) in vec4 hz_v_color;\n\
|
||||
@@ -31,7 +31,7 @@ pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
("vaColor", "hz_Color"),
|
||||
("vaNormal", "hz_Normal"),
|
||||
];
|
||||
horizon_shaders::GbuffersInputs {
|
||||
horizon_render_pipeline::GbuffersInputs {
|
||||
declarations,
|
||||
body,
|
||||
attributes: attributes
|
||||
@@ -40,7 +40,7 @@ pub fn inputs() -> horizon_shaders::GbuffersInputs {
|
||||
.collect(),
|
||||
after: String::new(),
|
||||
// Vanilla's weather drops texels below 0.1, as Horizon's own weather shader does.
|
||||
alpha_test: Some(horizon_shaders::AlphaTest {
|
||||
alpha_test: Some(horizon_render_pipeline::AlphaTest {
|
||||
op: ">",
|
||||
reference: 0.1,
|
||||
}),
|
||||
|
||||
Generated
+1
@@ -497,6 +497,7 @@ name = "horizon-render-pipeline"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"naga",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -9,6 +9,8 @@ description = "What an external shader pipeline gives the renderer: its buffers,
|
||||
[dependencies]
|
||||
# The frame uniform is uploaded as bytes (inputs.rs).
|
||||
bytemuck = { version = "1.24", features = ["derive"] }
|
||||
# A translated program's stages are naga modules (program.rs).
|
||||
naga = "30.0.1"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -5,6 +5,9 @@
|
||||
//! `shaders/` packs). No wgpu and no pack file here.
|
||||
//!
|
||||
//! - [`config`]: the colortex buffers and the shadow map: formats, clearing, mipmaps, settings.
|
||||
//! - [`program`]: a translated program (naga modules and their interface) and the vertex
|
||||
//! inputs the renderer offers it.
|
||||
//! - [`textures`]: the custom textures the programs read; [`RENDER_STAGES`]: the stages they draw in.
|
||||
//! - [`stages`], [`inputs`], [`Api`]: the WGSL stage interface Horizon's own packs are written
|
||||
//! against (`horizon-shader-api` reads and checks those packs): the stages' functions, preludes,
|
||||
//! bindings and entry points, and the frame uniform the renderer fills.
|
||||
@@ -12,7 +15,10 @@
|
||||
mod api;
|
||||
pub mod config;
|
||||
pub mod inputs;
|
||||
pub mod program;
|
||||
mod render_stage;
|
||||
pub mod stages;
|
||||
pub mod textures;
|
||||
|
||||
pub use api::Api;
|
||||
pub use config::{
|
||||
@@ -20,4 +26,9 @@ pub use config::{
|
||||
shadow_color,
|
||||
};
|
||||
pub use inputs::Frame;
|
||||
pub use program::{
|
||||
AlphaTest, ComputeProgram, GbuffersInputs, GeometryInputs, Interface, Program, WATER_MASK,
|
||||
WATER_PATCHES,
|
||||
};
|
||||
pub use render_stage::{RENDER_STAGES, render_stage};
|
||||
pub use stages::StageKind;
|
||||
@@ -0,0 +1,199 @@
|
||||
//! A translated program as the renderer builds its pipelines from it: its naga modules and the
|
||||
//! interface they expect (uniforms, samplers, images, outputs), and what the renderer offers a
|
||||
//! program's vertex stage (`GbuffersInputs`, `GeometryInputs`). `horizon-shaders` translates a
|
||||
//! `shaders/` pack's GLSL into these.
|
||||
|
||||
/// What a program's stages need from the game.
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct Interface {
|
||||
/// The uniform block at binding 0: its size and each value's name, GLSL type and offset.
|
||||
/// Ours come first: `hz_target` (the target's width, height, 1/width, 1/height), and the
|
||||
/// fixed-function fog the compatibility `gl_Fog` reads (OQ-28): `hz_fog_color` (vanilla's fog
|
||||
/// colour) and `hz_fog` (density, start, end, 1 / (end - start)), then `hz_depth_linear`:
|
||||
/// 1 where `shadowtex0`, `shadowtex1`, `shadow` and `watershadow` (x to w) read through a
|
||||
/// plain sampler filter linearly, 0 where they take the nearest texel.
|
||||
pub uniform_size: u32,
|
||||
pub uniforms: Vec<Uniform>,
|
||||
/// std140 initial contents; runtime values overwrite their members each frame.
|
||||
pub initial_values: Vec<u8>,
|
||||
/// Each sampler: texture at `binding`, sampler object at `binding + 1`.
|
||||
pub samplers: Vec<Sampler>,
|
||||
/// The fragment stage's output locations.
|
||||
pub outputs: Vec<u32>,
|
||||
/// A gbuffers program reads `DRAW_UNIFORMS`: the block at set 2, binding 0, set per draw.
|
||||
pub draw: bool,
|
||||
/// Storage images (`colorimg4`...), after the samplers.
|
||||
pub images: Vec<Image>,
|
||||
/// The SSBOs' bindings in set 4 (`bufferObject.<n>`).
|
||||
pub buffers: Vec<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Image {
|
||||
pub name: String,
|
||||
/// `image2D`, `uimage3D`...
|
||||
pub ty: String,
|
||||
/// The format qualifier (`rgba16f`).
|
||||
pub format: String,
|
||||
/// `readonly`, `writeonly`, empty for both, or `atomic` for an image an atomic function
|
||||
/// uses.
|
||||
pub access: String,
|
||||
pub binding: u32,
|
||||
/// A compute program's copy of image `before` as it was before the dispatch, which its
|
||||
/// loads read (see `ordering`).
|
||||
pub before: Option<String>,
|
||||
}
|
||||
|
||||
/// A compute program (`deferred4_a.csh`): its module, what it reads and writes, and how many
|
||||
/// work groups it runs: `workGroups`, or `workGroupsRender` times the target's size over the
|
||||
/// local size (1, 1 when neither is set).
|
||||
#[derive(Clone)]
|
||||
pub struct ComputeProgram {
|
||||
pub module: naga::Module,
|
||||
pub interface: Interface,
|
||||
/// Non-fatal translation diagnostics, located in the authored source.
|
||||
pub notes: Vec<Error>,
|
||||
pub work_groups: Option<[u32; 3]>,
|
||||
pub work_groups_render: [f32; 2],
|
||||
}
|
||||
|
||||
/// The uniforms a gbuffers program reads per draw (5.3's "D"), in a block of their own
|
||||
/// (`HzDraw`, std140: four ints, a vec4; 32 bytes) the game sets for each draw.
|
||||
pub const DRAW_UNIFORMS: [(&str, &str); 5] = [
|
||||
("renderStage", "int"),
|
||||
("entityId", "int"),
|
||||
("blockEntityId", "int"),
|
||||
("currentRenderedItemId", "int"),
|
||||
("entityColor", "vec4"),
|
||||
];
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Uniform {
|
||||
pub name: String,
|
||||
/// The type the pack declared (`float`, `ivec2`, `mat4`; `bool` is stored as an `int`).
|
||||
pub ty: String,
|
||||
pub offset: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Sampler {
|
||||
pub name: String,
|
||||
/// The type the pack declared: `sampler2D`, `sampler2DShadow`, `usampler2D`, `sampler3D`...
|
||||
pub ty: String,
|
||||
pub binding: u32,
|
||||
}
|
||||
|
||||
/// A translation diagnostic at a pack file and line.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Error {
|
||||
pub file: String,
|
||||
pub line: u32,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Program {
|
||||
pub vertex: naga::Module,
|
||||
pub fragment: naga::Module,
|
||||
pub interface: Interface,
|
||||
/// Non-fatal translation diagnostics, located in the authored source.
|
||||
pub notes: Vec<Error>,
|
||||
}
|
||||
|
||||
/// Where the program draws, which decides the conventions of 5.5.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Target {
|
||||
/// Pack buffers: rows stored as GL stores them.
|
||||
Buffers,
|
||||
/// The window (`final`).
|
||||
Window,
|
||||
}
|
||||
|
||||
/// What a gbuffers-style program's vertex stage reads. The game writes it: it knows its vertex
|
||||
/// formats, the translator only places it.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct GbuffersInputs {
|
||||
/// GLSL declarations: the vertex inputs and any bindings of set 1.
|
||||
pub declarations: String,
|
||||
/// GLSL statements that set `hz_Vertex`, `hz_Color`, `hz_MultiTexCoord0`,
|
||||
/// `hz_MultiTexCoord1` and `hz_Normal` (the compatibility inputs), run first in `main`.
|
||||
pub body: String,
|
||||
/// The value of each attribute a pack may declare (`mc_Entity`, `vaPosition`...), as a GLSL
|
||||
/// expression of the declared type's size; an attribute not listed reads zero. Terrain
|
||||
/// also supplies `mc_chunkFade`, an implicit float input rather than a declared attribute.
|
||||
pub attributes: Vec<(String, String)>,
|
||||
/// GLSL statements run last in `main`, with `gl_Position` in wgpu's clip space.
|
||||
pub after: String,
|
||||
/// The alpha test applied to output 0 (`gl_FragData[0]`, `gl_FragColor`), the loader's
|
||||
/// (3.2 `alphaTest.<program>`): `None` keeps every fragment.
|
||||
pub alpha_test: Option<AlphaTest>,
|
||||
/// The program may read `currentRenderedItemId` without declaring it, as Iris 1.11.7
|
||||
/// lets the hand's (observed with probe packs; terrain's may not).
|
||||
pub item_id_declared: bool,
|
||||
/// The depth test sees the far plane (window depth 1) unless the program writes
|
||||
/// `gl_FragDepth`, while `gl_FragCoord.z` stays the geometry's own: the sky shows only where
|
||||
/// nothing else drew, and reads its own depth as in Iris 1.11.7.
|
||||
pub far_depth: bool,
|
||||
/// `normals` and `specular` are bound as paged maps of the atlas `texture` reads
|
||||
/// (`horizon-client-render`'s `paged_maps.rs`), not as images of its layout: the program's
|
||||
/// texture calls on them read through `hz_pagedTexture`.
|
||||
pub paged_maps: bool,
|
||||
/// Translucent terrain: a fragment behind the boats' water patches (`horizonWaterMask`, the
|
||||
/// patches' depth, 1 where there are none) is discarded, so no water shows inside a hull
|
||||
/// (`RenderTypes.waterMask`), while the frame's depth stays the pack's own.
|
||||
pub water_mask: bool,
|
||||
/// The shadow pass's translucent terrain: a fragment inside a boat's water patch
|
||||
/// (`horizonWaterPatch*`, camera-relative boxes) is discarded, so no water casts its light
|
||||
/// into a hull. Not with a geometry stage.
|
||||
pub water_patches: bool,
|
||||
}
|
||||
|
||||
/// The sampler of the boats' water patches' depth (`GbuffersInputs::water_mask`).
|
||||
pub const WATER_MASK: &str = "horizonWaterMask";
|
||||
|
||||
/// How many boats' water patches the shadow pass keeps water out of (`GbuffersInputs::water_patches`).
|
||||
pub const WATER_PATCHES: usize = 16;
|
||||
|
||||
/// A fragment stays when its output 0's alpha compares to `reference` as `op` says (a GLSL
|
||||
/// comparison operator, `true` for GL's `ALWAYS`, `false` for `NEVER`).
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct AlphaTest {
|
||||
pub op: &'static str,
|
||||
pub reference: f32,
|
||||
}
|
||||
|
||||
impl AlphaTest {
|
||||
/// `alphaTest.<program>`'s value: `off`, or a GL comparison and a reference.
|
||||
pub fn parse(value: &str) -> Option<Option<Self>> {
|
||||
let mut words = value.split_whitespace();
|
||||
let func = words.next()?;
|
||||
if func == "off" {
|
||||
return Some(None);
|
||||
}
|
||||
let op = match func.trim_start_matches("GL_") {
|
||||
"NEVER" => "false",
|
||||
"LESS" => "<",
|
||||
"EQUAL" => "==",
|
||||
"LEQUAL" => "<=",
|
||||
"GREATER" => ">",
|
||||
"NOTEQUAL" => "!=",
|
||||
"GEQUAL" => ">=",
|
||||
"ALWAYS" => return Some(None),
|
||||
_ => return None,
|
||||
};
|
||||
let reference = words.next()?.parse().ok()?;
|
||||
Some(Some(Self { op, reference }))
|
||||
}
|
||||
}
|
||||
|
||||
/// How a geometry program's vertex invocations reach their triangle's vertices.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct GeometryInputs {
|
||||
/// The game's vertex inputs, as `GbuffersInputs`; their `layout(location = n) in`
|
||||
/// declarations become plain globals the pull sets.
|
||||
pub inputs: GbuffersInputs,
|
||||
/// GLSL statements that set the vertex inputs from vertex `hz_vertex_index` (a `uint`).
|
||||
pub pull: String,
|
||||
/// The vertex of the `@`th corner of the draw (a `uint` expression, `hz_indices[@]`).
|
||||
pub index: String,
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//! The render stages a pipeline's programs are told they draw in (`renderStage`, and the
|
||||
//! `MC_RENDER_STAGE_*` macros `horizon-shaders` defines from them).
|
||||
|
||||
/// `MC_RENDER_STAGE_*` in the order the stages draw (spec 5.4); each is its index (OQ-7).
|
||||
pub const RENDER_STAGES: [&str; 24] = [
|
||||
"NONE",
|
||||
"SKY",
|
||||
"SUNSET",
|
||||
"CUSTOM_SKY",
|
||||
"SUN",
|
||||
"MOON",
|
||||
"STARS",
|
||||
"VOID",
|
||||
"TERRAIN_SOLID",
|
||||
"TERRAIN_CUTOUT_MIPPED",
|
||||
"TERRAIN_CUTOUT",
|
||||
"ENTITIES",
|
||||
"BLOCK_ENTITIES",
|
||||
"DESTROY",
|
||||
"OUTLINE",
|
||||
"DEBUG",
|
||||
"HAND_SOLID",
|
||||
"TERRAIN_TRANSLUCENT",
|
||||
"TRIPWIRE",
|
||||
"PARTICLES",
|
||||
"CLOUDS",
|
||||
"RAIN_SNOW",
|
||||
"WORLD_BORDER",
|
||||
"HAND_TRANSLUCENT",
|
||||
];
|
||||
|
||||
/// The value of `MC_RENDER_STAGE_<name>` (OQ-7: its index in `RENDER_STAGES`).
|
||||
pub fn render_stage(name: &str) -> u32 {
|
||||
RENDER_STAGES
|
||||
.iter()
|
||||
.position(|s| *s == name)
|
||||
.unwrap_or_else(|| panic!("no render stage {name}")) as u32
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
//! The custom textures a pipeline's programs read: an image of the pack (a PNG or a raw dump,
|
||||
//! decoded) or a resource location the game resolves, bound to a sampler name in the programs of
|
||||
//! a stage (`horizon-shaders` reads them from `shaders.properties`, spec 3.4).
|
||||
|
||||
use crate::Format;
|
||||
|
||||
/// The stage of a `customTexture.<name>`: every program's.
|
||||
pub const EVERY_STAGE: &str = "*";
|
||||
|
||||
/// A texture bound to sampler `name` in the programs of `stage` (`gbuffers`, `deferred`,
|
||||
/// `composite`...; [`EVERY_STAGE`] for a `customTexture`), or the noise texture (stage and
|
||||
/// name `noise`).
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CustomTexture {
|
||||
pub stage: String,
|
||||
pub name: String,
|
||||
pub source: TextureSource,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TextureSource {
|
||||
Image(Texture),
|
||||
/// A resource location for the game to resolve.
|
||||
Resource(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Dim {
|
||||
D1,
|
||||
D2,
|
||||
D3,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Texture {
|
||||
pub dim: Dim,
|
||||
/// Width, height and depth (1 for the dimensions the texture lacks).
|
||||
pub size: [u32; 3],
|
||||
/// The internal format the pack asked for.
|
||||
pub format: Format,
|
||||
pub texels: Texels,
|
||||
/// Linear filtering, and clamping instead of repeating: on for a raw texture and off for a
|
||||
/// PNG, unless the `.mcmeta` beside it says otherwise.
|
||||
pub blur: bool,
|
||||
pub clamp: bool,
|
||||
/// A raw dump rather than a PNG.
|
||||
pub raw: bool,
|
||||
}
|
||||
|
||||
/// Texel values, `components` per texel: 1, 2 or 4 (three widen to four, alpha 1).
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Texels {
|
||||
Float(Vec<f32>),
|
||||
Int(Vec<i32>),
|
||||
Uint(Vec<u32>),
|
||||
}
|
||||
|
||||
impl Texture {
|
||||
pub fn components(&self) -> usize {
|
||||
components(self.format.channels)
|
||||
}
|
||||
}
|
||||
|
||||
/// The components per texel a texture of `channels` channels stores: three widen to four.
|
||||
pub fn components(channels: u8) -> usize {
|
||||
match channels {
|
||||
1 => 1,
|
||||
2 => 2,
|
||||
_ => 4,
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
pub use horizon_render_pipeline::{RENDER_STAGES, render_stage};
|
||||
|
||||
/// The feature flags of `iris.features.*` (spec 3.2) Horizon has. A pack that requires one of
|
||||
/// them loads; one it lacks is noted. Horizon defines no `IRIS_FEATURE_<name>` macro for them
|
||||
/// (spec OQ-2, docs/cleanroom/README.md): that macro family names another loader, so packs take
|
||||
@@ -59,34 +61,6 @@ struct Macro {
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct Macros(BTreeMap<String, Macro>);
|
||||
|
||||
/// `MC_RENDER_STAGE_*` in the order the stages draw (spec 5.4); each is its index (OQ-7).
|
||||
pub const RENDER_STAGES: [&str; 24] = [
|
||||
"NONE",
|
||||
"SKY",
|
||||
"SUNSET",
|
||||
"CUSTOM_SKY",
|
||||
"SUN",
|
||||
"MOON",
|
||||
"STARS",
|
||||
"VOID",
|
||||
"TERRAIN_SOLID",
|
||||
"TERRAIN_CUTOUT_MIPPED",
|
||||
"TERRAIN_CUTOUT",
|
||||
"ENTITIES",
|
||||
"BLOCK_ENTITIES",
|
||||
"DESTROY",
|
||||
"OUTLINE",
|
||||
"DEBUG",
|
||||
"HAND_SOLID",
|
||||
"TERRAIN_TRANSLUCENT",
|
||||
"TRIPWIRE",
|
||||
"PARTICLES",
|
||||
"CLOUDS",
|
||||
"RAIN_SNOW",
|
||||
"WORLD_BORDER",
|
||||
"HAND_TRANSLUCENT",
|
||||
];
|
||||
|
||||
/// `DH_BLOCK_*`, each its index: Distant Horizons' block materials.
|
||||
pub const DH_BLOCK_MATERIALS: [&str; 16] = [
|
||||
"UNKNOWN",
|
||||
@@ -107,14 +81,6 @@ pub const DH_BLOCK_MATERIALS: [&str; 16] = [
|
||||
"ILLUMINATED",
|
||||
];
|
||||
|
||||
/// The value of `MC_RENDER_STAGE_<name>` (OQ-7: its index in `RENDER_STAGES`).
|
||||
pub fn render_stage(name: &str) -> u32 {
|
||||
RENDER_STAGES
|
||||
.iter()
|
||||
.position(|s| *s == name)
|
||||
.unwrap_or_else(|| panic!("no render stage {name}")) as u32
|
||||
}
|
||||
|
||||
impl Macros {
|
||||
/// The standard macros that need no renderer (spec 1.5.1): `MC_VERSION`, this system's
|
||||
/// `MC_OS_*`, the GL and GLSL versions Iris reports, the render stages and the host
|
||||
|
||||
@@ -4,71 +4,9 @@
|
||||
//! location the game resolves (`minecraft:textures/...`, `minecraft:dynamic/lightmap_1`).
|
||||
|
||||
use crate::{Format, Kind, Pack, Properties};
|
||||
|
||||
/// The stage of a `customTexture.<name>`: every program's.
|
||||
pub const EVERY_STAGE: &str = "*";
|
||||
|
||||
/// A texture bound to sampler `name` in the programs of `stage` (`gbuffers`, `deferred`,
|
||||
/// `composite`...; [`EVERY_STAGE`] for a `customTexture`), or the noise texture (stage and
|
||||
/// name `noise`).
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CustomTexture {
|
||||
pub stage: String,
|
||||
pub name: String,
|
||||
pub source: TextureSource,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TextureSource {
|
||||
Image(Texture),
|
||||
/// A resource location for the game to resolve.
|
||||
Resource(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Dim {
|
||||
D1,
|
||||
D2,
|
||||
D3,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Texture {
|
||||
pub dim: Dim,
|
||||
/// Width, height and depth (1 for the dimensions the texture lacks).
|
||||
pub size: [u32; 3],
|
||||
/// The internal format the pack asked for.
|
||||
pub format: Format,
|
||||
pub texels: Texels,
|
||||
/// Linear filtering, and clamping instead of repeating: on for a raw texture and off for a
|
||||
/// PNG, unless the `.mcmeta` beside it says otherwise.
|
||||
pub blur: bool,
|
||||
pub clamp: bool,
|
||||
/// A raw dump rather than a PNG.
|
||||
pub raw: bool,
|
||||
}
|
||||
|
||||
/// Texel values, `components` per texel: 1, 2 or 4 (three widen to four, alpha 1).
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Texels {
|
||||
Float(Vec<f32>),
|
||||
Int(Vec<i32>),
|
||||
Uint(Vec<u32>),
|
||||
}
|
||||
|
||||
impl Texture {
|
||||
pub fn components(&self) -> usize {
|
||||
components(self.format.channels)
|
||||
}
|
||||
}
|
||||
|
||||
fn components(channels: u8) -> usize {
|
||||
match channels {
|
||||
1 => 1,
|
||||
2 => 2,
|
||||
_ => 4,
|
||||
}
|
||||
}
|
||||
pub use horizon_render_pipeline::textures::{
|
||||
CustomTexture, Dim, EVERY_STAGE, Texels, Texture, TextureSource, components,
|
||||
};
|
||||
|
||||
/// Every `texture.*` and `customTexture.*` entry, read and decoded, and a note for each that
|
||||
/// failed.
|
||||
|
||||
@@ -13,21 +13,11 @@ use std::collections::BTreeSet;
|
||||
use std::fmt::Write;
|
||||
|
||||
use super::scan::{QUALIFIERS, STORAGE, significant};
|
||||
use super::{Error, GbuffersInputs, Program, Target};
|
||||
use super::{Error, Program, Target};
|
||||
use crate::Preprocessed;
|
||||
use crate::macros::lex;
|
||||
|
||||
/// How a geometry program's vertex invocations reach their triangle's vertices.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct GeometryInputs {
|
||||
/// The game's vertex inputs, as `GbuffersInputs`; their `layout(location = n) in`
|
||||
/// declarations become plain globals the pull sets.
|
||||
pub inputs: GbuffersInputs,
|
||||
/// GLSL statements that set the vertex inputs from vertex `hz_vertex_index` (a `uint`).
|
||||
pub pull: String,
|
||||
/// The vertex of the `@`th corner of the draw (a `uint` expression, `hz_indices[@]`).
|
||||
pub index: String,
|
||||
}
|
||||
pub use horizon_render_pipeline::program::GeometryInputs;
|
||||
|
||||
/// Translates `vertex`, `geometry` and `fragment` (a shadow program): the program, and how many
|
||||
/// triangles the geometry stage can emit (the instances to draw).
|
||||
@@ -601,6 +591,7 @@ fn strip_storage(text: &mut [String], tokens: &[&str], range: std::ops::Range<us
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::GbuffersInputs;
|
||||
use crate::pack::tests::zip;
|
||||
use crate::{Macros, Pack, preprocess};
|
||||
|
||||
|
||||
@@ -44,188 +44,10 @@ pub use geometry::{GeometryInputs, translate_geometry};
|
||||
|
||||
use scan::Stage;
|
||||
|
||||
/// What a program's stages need from the game.
|
||||
#[derive(Clone, Debug, Default, PartialEq)]
|
||||
pub struct Interface {
|
||||
/// The uniform block at binding 0: its size and each value's name, GLSL type and offset.
|
||||
/// Ours come first: `hz_target` (the target's width, height, 1/width, 1/height), and the
|
||||
/// fixed-function fog the compatibility `gl_Fog` reads (OQ-28): `hz_fog_color` (vanilla's fog
|
||||
/// colour) and `hz_fog` (density, start, end, 1 / (end - start)), then `hz_depth_linear`:
|
||||
/// 1 where `shadowtex0`, `shadowtex1`, `shadow` and `watershadow` (x to w) read through a
|
||||
/// plain sampler filter linearly, 0 where they take the nearest texel.
|
||||
pub uniform_size: u32,
|
||||
pub uniforms: Vec<Uniform>,
|
||||
/// std140 initial contents; runtime values overwrite their members each frame.
|
||||
pub initial_values: Vec<u8>,
|
||||
/// Each sampler: texture at `binding`, sampler object at `binding + 1`.
|
||||
pub samplers: Vec<Sampler>,
|
||||
/// The fragment stage's output locations.
|
||||
pub outputs: Vec<u32>,
|
||||
/// A gbuffers program reads `DRAW_UNIFORMS`: the block at set 2, binding 0, set per draw.
|
||||
pub draw: bool,
|
||||
/// Storage images (`colorimg4`...), after the samplers.
|
||||
pub images: Vec<Image>,
|
||||
/// The SSBOs' bindings in set 4 (`bufferObject.<n>`).
|
||||
pub buffers: Vec<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Image {
|
||||
pub name: String,
|
||||
/// `image2D`, `uimage3D`...
|
||||
pub ty: String,
|
||||
/// The format qualifier (`rgba16f`).
|
||||
pub format: String,
|
||||
/// `readonly`, `writeonly`, empty for both, or `atomic` for an image an atomic function
|
||||
/// uses.
|
||||
pub access: String,
|
||||
pub binding: u32,
|
||||
/// A compute program's copy of image `before` as it was before the dispatch, which its
|
||||
/// loads read (see `ordering`).
|
||||
pub before: Option<String>,
|
||||
}
|
||||
|
||||
/// A compute program (`deferred4_a.csh`): its module, what it reads and writes, and how many
|
||||
/// work groups it runs: `workGroups`, or `workGroupsRender` times the target's size over the
|
||||
/// local size (1, 1 when neither is set).
|
||||
#[derive(Clone)]
|
||||
pub struct ComputeProgram {
|
||||
pub module: naga::Module,
|
||||
pub interface: Interface,
|
||||
/// Non-fatal translation diagnostics, located in the authored source.
|
||||
pub notes: Vec<Error>,
|
||||
pub work_groups: Option<[u32; 3]>,
|
||||
pub work_groups_render: [f32; 2],
|
||||
}
|
||||
|
||||
/// The uniforms a gbuffers program reads per draw (5.3's "D"), in a block of their own
|
||||
/// (`HzDraw`, std140: four ints, a vec4; 32 bytes) the game sets for each draw.
|
||||
pub const DRAW_UNIFORMS: [(&str, &str); 5] = [
|
||||
("renderStage", "int"),
|
||||
("entityId", "int"),
|
||||
("blockEntityId", "int"),
|
||||
("currentRenderedItemId", "int"),
|
||||
("entityColor", "vec4"),
|
||||
];
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Uniform {
|
||||
pub name: String,
|
||||
/// The type the pack declared (`float`, `ivec2`, `mat4`; `bool` is stored as an `int`).
|
||||
pub ty: String,
|
||||
pub offset: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Sampler {
|
||||
pub name: String,
|
||||
/// The type the pack declared: `sampler2D`, `sampler2DShadow`, `usampler2D`, `sampler3D`...
|
||||
pub ty: String,
|
||||
pub binding: u32,
|
||||
}
|
||||
|
||||
/// A translation diagnostic at a pack file and line.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Error {
|
||||
pub file: String,
|
||||
pub line: u32,
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Program {
|
||||
pub vertex: naga::Module,
|
||||
pub fragment: naga::Module,
|
||||
pub interface: Interface,
|
||||
/// Non-fatal translation diagnostics, located in the authored source.
|
||||
pub notes: Vec<Error>,
|
||||
}
|
||||
|
||||
/// Where the program draws, which decides the conventions of 5.5.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Target {
|
||||
/// Pack buffers: rows stored as GL stores them.
|
||||
Buffers,
|
||||
/// The window (`final`).
|
||||
Window,
|
||||
}
|
||||
|
||||
/// What a gbuffers-style program's vertex stage reads. The game writes it: it knows its vertex
|
||||
/// formats, the translator only places it.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct GbuffersInputs {
|
||||
/// GLSL declarations: the vertex inputs and any bindings of set 1.
|
||||
pub declarations: String,
|
||||
/// GLSL statements that set `hz_Vertex`, `hz_Color`, `hz_MultiTexCoord0`,
|
||||
/// `hz_MultiTexCoord1` and `hz_Normal` (the compatibility inputs), run first in `main`.
|
||||
pub body: String,
|
||||
/// The value of each attribute a pack may declare (`mc_Entity`, `vaPosition`...), as a GLSL
|
||||
/// expression of the declared type's size; an attribute not listed reads zero. Terrain
|
||||
/// also supplies `mc_chunkFade`, an implicit float input rather than a declared attribute.
|
||||
pub attributes: Vec<(String, String)>,
|
||||
/// GLSL statements run last in `main`, with `gl_Position` in wgpu's clip space.
|
||||
pub after: String,
|
||||
/// The alpha test applied to output 0 (`gl_FragData[0]`, `gl_FragColor`), the loader's
|
||||
/// (3.2 `alphaTest.<program>`): `None` keeps every fragment.
|
||||
pub alpha_test: Option<AlphaTest>,
|
||||
/// The program may read `currentRenderedItemId` without declaring it, as Iris 1.11.7
|
||||
/// lets the hand's (observed with probe packs; terrain's may not).
|
||||
pub item_id_declared: bool,
|
||||
/// The depth test sees the far plane (window depth 1) unless the program writes
|
||||
/// `gl_FragDepth`, while `gl_FragCoord.z` stays the geometry's own: the sky shows only where
|
||||
/// nothing else drew, and reads its own depth as in Iris 1.11.7.
|
||||
pub far_depth: bool,
|
||||
/// `normals` and `specular` are bound as paged maps of the atlas `texture` reads
|
||||
/// (`horizon-client-render`'s `paged_maps.rs`), not as images of its layout: the program's
|
||||
/// texture calls on them read through `hz_pagedTexture`.
|
||||
pub paged_maps: bool,
|
||||
/// Translucent terrain: a fragment behind the boats' water patches (`horizonWaterMask`, the
|
||||
/// patches' depth, 1 where there are none) is discarded, so no water shows inside a hull
|
||||
/// (`RenderTypes.waterMask`), while the frame's depth stays the pack's own.
|
||||
pub water_mask: bool,
|
||||
/// The shadow pass's translucent terrain: a fragment inside a boat's water patch
|
||||
/// (`horizonWaterPatch*`, camera-relative boxes) is discarded, so no water casts its light
|
||||
/// into a hull. Not with a geometry stage.
|
||||
pub water_patches: bool,
|
||||
}
|
||||
|
||||
/// The sampler of the boats' water patches' depth (`GbuffersInputs::water_mask`).
|
||||
pub const WATER_MASK: &str = "horizonWaterMask";
|
||||
|
||||
/// How many boats' water patches the shadow pass keeps water out of (`GbuffersInputs::water_patches`).
|
||||
pub const WATER_PATCHES: usize = 16;
|
||||
|
||||
/// A fragment stays when its output 0's alpha compares to `reference` as `op` says (a GLSL
|
||||
/// comparison operator, `true` for GL's `ALWAYS`, `false` for `NEVER`).
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct AlphaTest {
|
||||
pub op: &'static str,
|
||||
pub reference: f32,
|
||||
}
|
||||
|
||||
impl AlphaTest {
|
||||
/// `alphaTest.<program>`'s value: `off`, or a GL comparison and a reference.
|
||||
pub fn parse(value: &str) -> Option<Option<Self>> {
|
||||
let mut words = value.split_whitespace();
|
||||
let func = words.next()?;
|
||||
if func == "off" {
|
||||
return Some(None);
|
||||
}
|
||||
let op = match func.trim_start_matches("GL_") {
|
||||
"NEVER" => "false",
|
||||
"LESS" => "<",
|
||||
"EQUAL" => "==",
|
||||
"LEQUAL" => "<=",
|
||||
"GREATER" => ">",
|
||||
"NOTEQUAL" => "!=",
|
||||
"GEQUAL" => ">=",
|
||||
"ALWAYS" => return Some(None),
|
||||
_ => return None,
|
||||
};
|
||||
let reference = words.next()?.parse().ok()?;
|
||||
Some(Some(Self { op, reference }))
|
||||
}
|
||||
}
|
||||
pub use horizon_render_pipeline::program::{
|
||||
AlphaTest, ComputeProgram, DRAW_UNIFORMS, Error, GbuffersInputs, Image, Interface, Program,
|
||||
Sampler, Target, Uniform, WATER_MASK, WATER_PATCHES,
|
||||
};
|
||||
|
||||
/// Translates a composite-style program (`composite`, `deferred`, `final`...).
|
||||
pub fn translate_composite(
|
||||
|
||||
Generated
+1
@@ -2845,6 +2845,7 @@ name = "horizon-render-pipeline"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"naga",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in new issue
Block a user