mirror of
https://github.com/horizon-rust/horizon.git
synced 2026-11-07 11:06:11 -10:00
gfx: upload atlas patches on skipped frames and refresh skins after pack reload
Fixes #5097 Co-Authored-By: Antigravity <[email protected]>
This commit is contained in:
1 parent
571ec1b76e
commit
190e96938b
6 files changed
+75
-33
No files matched your search
@@ -4044,8 +4044,26 @@ impl Renderer {
|
||||
}
|
||||
pub fn render(&mut self, frame: &Frame) -> Result<bool> {
|
||||
let rendered = self.draw_frame(frame);
|
||||
// A frame that was not drawn still submits the section copies.
|
||||
if let Some(copies) = self.take_section_copies() {
|
||||
// A frame that was not drawn still submits the section copies and
|
||||
// atlas patches (glyphs, skins, maps), which the caller already took.
|
||||
if !matches!(rendered, Ok(true)) && !frame.hud.patches.is_empty() {
|
||||
let section_copies = self.section_copies.take();
|
||||
let has_section_copies = section_copies.is_some();
|
||||
let mut encoder = section_copies.unwrap_or_else(|| {
|
||||
self.device
|
||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
label: Some("Horizon atlas patches"),
|
||||
})
|
||||
});
|
||||
self.hud
|
||||
.upload_patches(&mut self.uploads, &mut encoder, &frame.hud.patches);
|
||||
self.uploads.finish(&encoder);
|
||||
if has_section_copies {
|
||||
self.section_copy_bytes = 0;
|
||||
self.section_uploads.finish(&encoder);
|
||||
}
|
||||
self.queue.submit([encoder.finish()]);
|
||||
} else if let Some(copies) = self.take_section_copies() {
|
||||
self.queue.submit([copies]);
|
||||
}
|
||||
rendered
|
||||
|
||||
@@ -1817,6 +1817,38 @@ impl HudRenderer {
|
||||
*previous = state;
|
||||
}
|
||||
}
|
||||
/// Stage `patches` into the shared atlas texture.
|
||||
pub fn upload_patches(
|
||||
&self,
|
||||
uploads: &mut crate::gfx::upload::Uploads,
|
||||
encoder: &mut wgpu::CommandEncoder,
|
||||
patches: &[crate::font::Patch],
|
||||
) {
|
||||
if let Some(texture) = &self.atlas_texture {
|
||||
for p in patches {
|
||||
if p.x.saturating_add(p.width) <= texture.width()
|
||||
&& p.y.saturating_add(p.height) <= texture.height()
|
||||
{
|
||||
uploads.texture(
|
||||
encoder,
|
||||
wgpu::TexelCopyTextureInfo {
|
||||
texture,
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d {
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
z: 0,
|
||||
},
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
},
|
||||
p.width,
|
||||
p.height,
|
||||
&p.rgba,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Stage the batch's atlas patches, vertices and uniform: before the
|
||||
/// frame's first pass, so the copies share one command buffer.
|
||||
pub fn prepare(
|
||||
@@ -1827,26 +1859,7 @@ impl HudRenderer {
|
||||
batch: &HudBatch,
|
||||
size: [u32; 2],
|
||||
) {
|
||||
if let Some(texture) = &self.atlas_texture {
|
||||
for p in &batch.patches {
|
||||
uploads.texture(
|
||||
encoder,
|
||||
wgpu::TexelCopyTextureInfo {
|
||||
texture,
|
||||
mip_level: 0,
|
||||
origin: wgpu::Origin3d {
|
||||
x: p.x,
|
||||
y: p.y,
|
||||
z: 0,
|
||||
},
|
||||
aspect: wgpu::TextureAspect::All,
|
||||
},
|
||||
p.width,
|
||||
p.height,
|
||||
&p.rgba,
|
||||
);
|
||||
}
|
||||
}
|
||||
self.upload_patches(uploads, encoder, &batch.patches);
|
||||
if batch.vertices.is_empty() || size.contains(&0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7276,6 +7276,10 @@ impl Game<'_> {
|
||||
return batch;
|
||||
}
|
||||
if self.screen == Screen::Options {
|
||||
if self.title.is_none() {
|
||||
self.flush_skin_slots();
|
||||
self.update_remote_skins();
|
||||
}
|
||||
self.draw_options(&mut batch);
|
||||
return batch;
|
||||
}
|
||||
|
||||
@@ -301,6 +301,7 @@ impl Game<'_> {
|
||||
// upload into it again instead of naming sprites it does not have.
|
||||
self.skin_slots.forget();
|
||||
self.maps.slots.forget();
|
||||
self.map_patches.clear();
|
||||
// The atlas's sprites moved: the particle engine re-reads every rect
|
||||
// and the packs' sprite sets, or every particle draws a stale region.
|
||||
self.particles
|
||||
|
||||
@@ -4348,7 +4348,7 @@ impl Game<'_> {
|
||||
/// `PlayerInfo.getSkin` for every player entity, including NPCs that are
|
||||
/// never in the tab list: resolve each profile's textures and give the
|
||||
/// level's player models their skin.
|
||||
fn update_remote_skins(&mut self) {
|
||||
pub(super) fn update_remote_skins(&mut self) {
|
||||
let local = self.remote.as_ref().map(|r| r.profile);
|
||||
self.poll_own_profile();
|
||||
let Some(r) = self.remote.as_mut() else {
|
||||
@@ -4413,7 +4413,7 @@ impl Game<'_> {
|
||||
&& let Some((rgba, is_slim)) = horizon_client::skins::offline_skin()
|
||||
{
|
||||
const OFFLINE: &str = "horizon/offline_skin";
|
||||
if !self.skin_slots.contains(OFFLINE) {
|
||||
if !self.skin_slots.contains(OFFLINE) || !self.gui.atlas.sprites.contains_key(OFFLINE) {
|
||||
self.store_skin(OFFLINE.into(), rgba.clone());
|
||||
}
|
||||
if *is_slim {
|
||||
@@ -4426,7 +4426,7 @@ impl Game<'_> {
|
||||
&& let Some(rgba) = horizon_client::skins::offline_cape()
|
||||
{
|
||||
const OFFLINE: &str = "capes/offline";
|
||||
if !self.skin_slots.contains(OFFLINE) {
|
||||
if !self.skin_slots.contains(OFFLINE) || !self.gui.atlas.sprites.contains_key(OFFLINE) {
|
||||
self.store_skin(OFFLINE.into(), rgba.to_vec());
|
||||
}
|
||||
capes.insert(local, OFFLINE.into());
|
||||
@@ -4610,7 +4610,8 @@ impl Game<'_> {
|
||||
uuid: u128,
|
||||
(skin, slim): (String, bool),
|
||||
) -> (String, bool) {
|
||||
if skin.starts_with("skins/") && !self.again_skin(&skin) {
|
||||
if (skin.starts_with("skins/") || skin == "horizon/offline_skin") && !self.again_skin(&skin)
|
||||
{
|
||||
let skin = horizon_client::tab_list::default_skin(uuid);
|
||||
return (skin.to_owned(), skin.contains("/slim/"));
|
||||
}
|
||||
|
||||
@@ -747,13 +747,9 @@ impl Game<'_> {
|
||||
}
|
||||
|
||||
impl Game<'_> {
|
||||
/// `Hud.extractTabList`: the player list while the player-list key is
|
||||
/// held. A local world shows it with a joined LAN guest or a `list`
|
||||
/// objective.
|
||||
pub(super) fn draw_tab_list(&mut self, batch: &mut HudBatch) {
|
||||
use horizon_client::tab_list::{self, TabInputs};
|
||||
// Player heads and the player list both draw from the same skin
|
||||
// slots: a new frame, with what the last one drew.
|
||||
/// Advance the skin slots to a new frame with what the last one drew, and
|
||||
/// store any finished skin downloads into the atlas.
|
||||
pub(super) fn flush_skin_slots(&mut self) {
|
||||
let (ready, drawn) = {
|
||||
let mut downloads = self.skin_downloads.borrow_mut();
|
||||
(downloads.take_ready(), downloads.take_drawn())
|
||||
@@ -762,6 +758,15 @@ impl Game<'_> {
|
||||
for (location, rgba) in ready {
|
||||
self.store_skin(location, rgba);
|
||||
}
|
||||
}
|
||||
/// `Hud.extractTabList`: the player list while the player-list key is
|
||||
/// held. A local world shows it with a joined LAN guest or a `list`
|
||||
/// objective.
|
||||
pub(super) fn draw_tab_list(&mut self, batch: &mut HudBatch) {
|
||||
use horizon_client::tab_list::{self, TabInputs};
|
||||
// Player heads and the player list both draw from the same skin
|
||||
// slots: a new frame, with what the last one drew.
|
||||
self.flush_skin_slots();
|
||||
let key = self.screen == super::Screen::Playing
|
||||
&& self.keys.contains(&winit::keyboard::KeyCode::Tab);
|
||||
let (mut players, online_mode, upside_down) = match self.remote_tab_players() {
|
||||
|
||||
Reference in new issue
Block a user