mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
The breeze's wind and the wind charge scroll their textures
Vanilla draws the breeze's wind layer and the wind charge with `RenderTypes.breezeWind`, whose texture scrolls with the entity's age: by 0.02 of the texture per tick for the breeze's wind layer and 0.03 for the wind charge. Horizon drew both with a still texture, so the breeze's gust and the wind charge did not move. The draw now takes a scroll offset and wraps the vertex's U inside the texture, as the texture matrix of the vanilla's render type does. Fixes #2760 Co-Authored-By: minimax-m3.1-flash (Claude Code) <[email protected]>
This commit is contained in:
1 parent
6f4b1bf4c2
commit
f507a067cd
2 files changed
+89
-13
No files matched your search
@@ -570,11 +570,15 @@ impl Game<'_> {
|
||||
poses.yrot("wind", age * 16.0_f32.to_radians());
|
||||
let base = glam::Mat4::from_translation(at)
|
||||
* glam::Mat4::from_scale(glam::Vec3::new(-1.0, -1.0, 1.0));
|
||||
horizon_client::mobs::render::draw(
|
||||
horizon_client::mobs::render::draw_scrolled(
|
||||
model,
|
||||
base,
|
||||
&poses,
|
||||
[r.u0, r.v0, r.u1, r.v1],
|
||||
horizon_client::mobs::render::scroll_offset(
|
||||
age,
|
||||
horizon_client::mobs::render::WIND_CHARGE_SCROLL,
|
||||
),
|
||||
0xFFFF_FFFF,
|
||||
light,
|
||||
0,
|
||||
|
||||
@@ -20,12 +20,32 @@ pub type Atlas<'a> = &'a dyn Fn(&str) -> Option<[f32; 4]>;
|
||||
/// the model UV and reads `enchanted_glint_armor`.
|
||||
pub const ARMOR_GLINT: u32 = 13;
|
||||
|
||||
/// `RenderTypes.breezeWind`: the texture of the breeze's wind layer scrolls
|
||||
/// by 0.02 of the texture per tick.
|
||||
pub const BREEZE_WIND_SCROLL: f32 = 0.02;
|
||||
/// `WindChargeRenderer.xOffset`: the wind charge's texture scrolls by 0.03 of
|
||||
/// the texture per tick.
|
||||
pub const WIND_CHARGE_SCROLL: f32 = 0.03;
|
||||
/// The offset of a scrolling texture: `RenderTypes.breezeWind` takes the
|
||||
/// texture's age times the speed, modulo one.
|
||||
pub fn scroll_offset(age: f32, speed: f32) -> f32 {
|
||||
(age * speed) % 1.0
|
||||
}
|
||||
/// The vertex's U with the scroll: the texture matrix of
|
||||
/// `RenderTypes.breezeWind` moves the texture under the model, so the U
|
||||
/// moves by the offset and wraps around the texture.
|
||||
fn scroll_u(u: f32, scroll: f32) -> f32 {
|
||||
if scroll == 0.0 { u } else { (u + scroll) % 1.0 }
|
||||
}
|
||||
|
||||
/// One draw of a model with a texture.
|
||||
pub struct Layer {
|
||||
pub model: String,
|
||||
pub texture: String,
|
||||
pub color: u32,
|
||||
pub full_bright: bool,
|
||||
/// `RenderTypes.breezeWind`: the texture scrolls with the entity's age.
|
||||
pub scroll: f32,
|
||||
}
|
||||
/// DyeColor.getTextureDiffuseColor (RGB).
|
||||
pub const DYE: [u32; 16] = [
|
||||
@@ -436,6 +456,7 @@ pub fn layers(m: &Mob) -> Vec<Layer> {
|
||||
texture: texture.into(),
|
||||
color,
|
||||
full_bright,
|
||||
scroll: 0.0,
|
||||
})
|
||||
};
|
||||
match m.species() {
|
||||
@@ -465,16 +486,17 @@ pub fn layers(m: &Mob) -> Vec<Layer> {
|
||||
push(&mut v, "happy_ghast_harness#main", &texture, white, false);
|
||||
}
|
||||
}
|
||||
// BreezeWindLayer (the scroll is not reproduced: atlas sprites do
|
||||
// not wrap) and BreezeEyesLayer.
|
||||
// BreezeWindLayer and BreezeEyesLayer. The wind layer's texture
|
||||
// scrolls (`RenderTypes.breezeWind`): the offset is taken inside the
|
||||
// sprite, so the atlas does not have to wrap.
|
||||
S::Breeze => {
|
||||
push(
|
||||
&mut v,
|
||||
"breeze#wind",
|
||||
"entity/breeze/breeze_wind",
|
||||
white,
|
||||
false,
|
||||
);
|
||||
v.push(Layer {
|
||||
model: "breeze#wind".into(),
|
||||
texture: "entity/breeze/breeze_wind".into(),
|
||||
color: white,
|
||||
full_bright: false,
|
||||
scroll: scroll_offset(m.age as f32, BREEZE_WIND_SCROLL),
|
||||
});
|
||||
push(
|
||||
&mut v,
|
||||
"breeze#eyes",
|
||||
@@ -801,6 +823,7 @@ fn humanoid_armor(m: &Mob, v: &mut Vec<Layer>) {
|
||||
texture: format!("entity/equipment/{folder}/{asset}"),
|
||||
color: tint,
|
||||
full_bright: false,
|
||||
scroll: 0.0,
|
||||
});
|
||||
if asset == "leather" {
|
||||
v.push(Layer {
|
||||
@@ -808,6 +831,7 @@ fn humanoid_armor(m: &Mob, v: &mut Vec<Layer>) {
|
||||
texture: format!("entity/equipment/{folder}/leather_overlay"),
|
||||
color: 0xFFFF_FFFF,
|
||||
full_bright: false,
|
||||
scroll: 0.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1009,6 +1033,23 @@ pub fn draw(
|
||||
light: u32,
|
||||
overlay: u32,
|
||||
out: &mut Vec<Vertex>,
|
||||
) {
|
||||
draw_scrolled(part, base, poses, uv, 0.0, color, light, overlay, out);
|
||||
}
|
||||
/// `draw` for a texture that scrolls: the vertex's U is moved by the offset
|
||||
/// and wraps inside the texture, as the texture matrix of
|
||||
/// `RenderTypes.breezeWind` does.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn draw_scrolled(
|
||||
part: &Part,
|
||||
base: glam::Mat4,
|
||||
poses: &Poses,
|
||||
uv: [f32; 4],
|
||||
scroll: f32,
|
||||
color: u32,
|
||||
light: u32,
|
||||
overlay: u32,
|
||||
out: &mut Vec<Vertex>,
|
||||
) {
|
||||
draw_normals(
|
||||
part,
|
||||
@@ -1016,6 +1057,7 @@ pub fn draw(
|
||||
ModelNormals::new(base),
|
||||
poses,
|
||||
uv,
|
||||
scroll,
|
||||
color,
|
||||
light,
|
||||
overlay,
|
||||
@@ -1029,6 +1071,7 @@ fn draw_normals(
|
||||
normals: ModelNormals,
|
||||
poses: &Poses,
|
||||
uv: [f32; 4],
|
||||
scroll: f32,
|
||||
color: u32,
|
||||
light: u32,
|
||||
overlay: u32,
|
||||
@@ -1066,7 +1109,7 @@ fn draw_normals(
|
||||
normal,
|
||||
pos: pos.to_array(),
|
||||
uv: [
|
||||
uv[0] + (uv[2] - uv[0]) * v[3],
|
||||
uv[0] + (uv[2] - uv[0]) * scroll_u(v[3], scroll),
|
||||
uv[1] + (uv[3] - uv[1]) * v[4],
|
||||
],
|
||||
layer: overlay,
|
||||
@@ -1078,7 +1121,7 @@ fn draw_normals(
|
||||
}
|
||||
}
|
||||
for c in &part.children {
|
||||
draw_normals(c, m, normals, poses, uv, color, light, overlay, out);
|
||||
draw_normals(c, m, normals, poses, uv, scroll, color, light, overlay, out);
|
||||
}
|
||||
}
|
||||
/// Render a mob with its variant model, texture and layers.
|
||||
@@ -1199,6 +1242,7 @@ fn render_visible(
|
||||
texture: texture.into(),
|
||||
color: ((a.clamp(0.0, 1.0) * 255.0) as u32) << 24 | 0x00FF_FFFF,
|
||||
full_bright: true,
|
||||
scroll: 0.0,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1240,11 +1284,12 @@ fn render_visible(
|
||||
None => overlay,
|
||||
};
|
||||
let start = out.len();
|
||||
draw(
|
||||
draw_scrolled(
|
||||
&part,
|
||||
base,
|
||||
&layer_poses,
|
||||
uv,
|
||||
layer.scroll,
|
||||
layer.color,
|
||||
light,
|
||||
overlay,
|
||||
@@ -1618,3 +1663,30 @@ mod tests {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod scroll_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn the_scrolling_texture_wraps_around() {
|
||||
// RenderTypes.breezeWind: the breeze's wind layer's texture scrolls
|
||||
// by 0.02 of the texture per tick, the wind charge's by 0.03.
|
||||
assert_eq!(scroll_offset(0.0, BREEZE_WIND_SCROLL), 0.0);
|
||||
assert!((scroll_offset(25.0, BREEZE_WIND_SCROLL) - 0.5).abs() < 1e-6);
|
||||
assert!((scroll_offset(50.0, BREEZE_WIND_SCROLL) - 0.0).abs() < 1e-6);
|
||||
assert!((scroll_offset(50.0, WIND_CHARGE_SCROLL) - 0.5).abs() < 1e-6);
|
||||
assert!((scroll_offset(100.0, WIND_CHARGE_SCROLL) - 0.0).abs() < 1e-6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_scrolled_u_wraps_inside_the_texture() {
|
||||
// Without a scroll the U is the vertex's own.
|
||||
assert_eq!(scroll_u(0.25, 0.0), 0.25);
|
||||
assert_eq!(scroll_u(1.0, 0.0), 1.0);
|
||||
// With one, it moves and wraps around the texture.
|
||||
assert!((scroll_u(0.25, 0.5) - 0.75).abs() < 1e-6);
|
||||
assert!((scroll_u(0.75, 0.5) - 0.25).abs() < 1e-6);
|
||||
assert!((scroll_u(1.0, 0.5) - 0.5).abs() < 1e-6);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user