Mii rendering and parsing library

Compare changes

Choose any two refs to compare.

Changed files
+199 -503
lightweight_viewer
vfl
+30 -31
lightweight_viewer/src/char.rs
··· 1 1 use crate::State; 2 2 use crate::render::shape_data_to_render_3d_shape; 3 3 use glam::{Vec3, uvec2}; 4 - use image::{DynamicImage, RgbaImage}; 4 + use image::DynamicImage; 5 5 use vfl::color::nx::ModulationIntent; 6 + use vfl::draw::render_2d::texture_format_to_wgpu; 6 7 use vfl::draw::render_3d::Rendered3dShape; 7 - use vfl::res::tex::nx::{ResourceTexture, TextureElement}; 8 + use vfl::draw::wgpu_render::texture::TextureBundle; 9 + use vfl::res::tex::nx::{RawTexture, ResourceTexture, TextureElement}; 8 10 use vfl::{ 9 11 color::nx::{ColorModulated, modulate}, 10 12 draw::{ ··· 15 17 }; 16 18 use wgpu::{CommandEncoder, TextureView}; 17 19 18 - pub fn draw_noseline(st: &mut State, texture_view: &TextureView, encoder: &mut CommandEncoder) { 20 + pub fn draw_noseline( 21 + st: &mut State, 22 + texture_view: Option<TextureBundle>, 23 + encoder: &mut CommandEncoder, 24 + ) -> texture::TextureBundle { 19 25 let res_texture = &st.resources.texture_header; 20 26 let file_texture = &st.resources.texture_data; 21 27 22 28 let noseline_num = usize::from(st.char_info.nose_type); 23 29 24 - let tex: image::ImageBuffer<image::Rgba<u8>, Vec<u8>> = res_texture.noseline[noseline_num] 25 - .get_image(file_texture) 30 + let tex = res_texture.noseline[noseline_num] 31 + .get_uncompressed_bytes(file_texture) 26 32 .unwrap() 27 33 .unwrap(); 28 - let tex = DynamicImage::ImageRgba8(tex); 34 + 35 + let output_texture = if let Some(texture_view) = texture_view { 36 + texture_view 37 + } else { 38 + texture::TextureBundle::create_texture(&st.device, &uvec2(256, 256), "noselinetex") 39 + }; 29 40 30 41 Rendered2dShape::render_texture_trivial( 31 42 tex, 32 43 modulate(ColorModulated::NoseLineShape, &st.char_info), 33 44 None, 34 45 st, 35 - texture_view, 46 + &output_texture.view, 36 47 encoder, 37 48 ); 49 + 50 + output_texture 38 51 } 39 52 40 53 pub fn draw_mask(st: &mut State, texture_view: &TextureView, encoder: &mut CommandEncoder) { ··· 56 69 st: &mut State, 57 70 texture_element: TextureElement, 58 71 modulated: ColorModulated, 59 - ) -> Option<(DynamicImage, ModulationIntent)> { 72 + ) -> Option<(RawTexture, ModulationIntent)> { 60 73 texture_element 61 - .get_image(&st.resources.texture_data) 74 + .get_uncompressed_bytes(&st.resources.texture_data) 62 75 .unwrap() 63 - .map(|tex| { 64 - ( 65 - DynamicImage::ImageRgba8(tex), 66 - modulate(modulated, &st.char_info), 67 - ) 68 - }) 76 + .map(|bytes| (bytes, modulate(modulated, &st.char_info))) 69 77 } 70 78 71 79 // Load faceline textures in order [wrinkle, makeup, beard], and removes any that don't exist 72 80 fn get_faceline_textures( 73 81 st: &mut State, 74 82 res_texture: &ResourceTexture, 75 - ) -> Vec<(DynamicImage, ModulationIntent)> { 83 + ) -> Vec<(RawTexture, ModulationIntent)> { 76 84 vec![ 77 85 load_faceline_texture( 78 86 st, ··· 101 109 fn draw_faceline(st: &mut State, texture_view: &TextureView, encoder: &mut CommandEncoder) { 102 110 let res_texture = st.resources.texture_header; 103 111 104 - // let makeup_tex = res_texture.makeup[st.char_info.faceline_make as usize] 105 - // .get_image(&st.resources.texture_data) 106 - // .unwrap(); 107 - // let Some(makeup_tex) = makeup_tex else { 108 - // return; 109 - // }; 110 - // let makeup_tex = image::DynamicImage::ImageRgba8(tex); 111 - 112 112 let textures = get_faceline_textures(st, &res_texture); 113 113 114 114 for (i, (rendered_texture, modulation)) in textures.iter().enumerate() { ··· 121 121 Rendered2dShape::render_texture_trivial( 122 122 rendered_texture.to_owned(), 123 123 modulation.to_owned(), 124 - opaque, 124 + None, 125 125 st, 126 126 texture_view, 127 127 encoder, ··· 197 197 // // "noselinetex", 198 198 // // ); 199 199 200 - let noseline_texture = 201 - texture::Texture::create_texture(&st.device, &uvec2(256, 256), "noselinetex"); 200 + // let noseline_texture = 201 + // texture::TextureBundle::create_texture(&st.device, &uvec2(256, 256), "noselinetex"); 202 202 203 - draw_noseline(st, &noseline_texture.view, encoder); 203 + let noseline_texture = draw_noseline(st, None, encoder); 204 204 205 205 Some(noseline_texture) 206 206 } 207 207 Shape::Mask => { 208 208 let mask_texture = 209 - texture::Texture::create_texture(&st.device, &uvec2(512, 512), "masktex"); 209 + texture::TextureBundle::create_texture(&st.device, &uvec2(512, 512), "masktex"); 210 210 211 211 draw_mask(st, &mask_texture.view, encoder); 212 212 ··· 214 214 } 215 215 Shape::FaceLine => { 216 216 let faceline_texture = 217 - texture::Texture::create_texture(&st.device, &uvec2(512, 512), "facelinetex"); 217 + texture::TextureBundle::create_texture(&st.device, &uvec2(512, 512), "facelinetex"); 218 218 219 - println!("hi!"); 220 219 draw_faceline(st, &faceline_texture.view, encoder); 221 220 222 221 Some(faceline_texture)
+6 -11
lightweight_viewer/src/char_model.rs
··· 1 - use vfl::{ 2 - draw::{faceline, render_3d::Rendered3dShape}, 3 - res::shape::nx::{Shape, ShapeData}, 4 - }; 1 + use vfl::{draw::render_3d::Rendered3dShape, res::shape::nx::Shape}; 5 2 use wgpu::{CommandEncoder, TextureView}; 6 3 7 4 use crate::{State, char::load_shape}; 8 5 9 - type Tex = wgpu::Texture; 10 - type TexOpt = Option<wgpu::Texture>; 11 6 type Model = Rendered3dShape; 12 7 type ModelOpt = Option<Rendered3dShape>; 13 8 ··· 37 32 encoder: &mut CommandEncoder, 38 33 ) { 39 34 self.face_line.render(st, texture_view, encoder); 40 - if let Some(hair) = self.hair.as_mut() { 41 - hair.render(st, texture_view, encoder); 42 - } 43 - self.mask.render(st, texture_view, encoder); 35 + // if let Some(hair) = self.hair.as_mut() { 36 + // hair.render(st, texture_view, encoder); 37 + // } 38 + // self.mask.render(st, texture_view, encoder); 44 39 45 - self.nose_line.render(st, texture_view, encoder); 40 + // self.nose_line.render(st, texture_view, encoder); 46 41 } 47 42 } 48 43
+28 -68
lightweight_viewer/src/main.rs
··· 1 - use std::rc::Rc; 2 - use std::sync::{Mutex, OnceLock}; 3 - use std::{f32::consts::FRAC_PI_2, fs::File, io::BufReader, sync::Arc}; 4 - 5 1 use camera::{Camera, CameraUniform}; 6 - use char::draw_char; 7 2 use char_model::CharModel; 8 3 use glam::{UVec2, Vec3, Vec4, uvec2, vec4}; 4 + use std::sync::{Mutex, OnceLock}; 5 + use std::{f32::consts::FRAC_PI_2, fs::File, sync::Arc}; 9 6 use vfl::res::shape::nx::ResourceShape; 10 7 use vfl::res::tex::nx::ResourceTexture; 11 8 use vfl::{ ··· 13 10 draw::{render_3d::ProgramState, wgpu_render::texture}, 14 11 res::{shape::nx::SHAPE_MID_DAT, tex::nx::TEXTURE_MID_SRGB_DAT}, 15 12 }; 13 + use wgpu::Features; 16 14 use wgpu::{Backends, util::DeviceExt}; 17 - use wgpu::{CommandEncoder, TextureView}; 18 15 use winit::{ 19 16 application::ApplicationHandler, 20 17 event::WindowEvent, ··· 28 25 pub mod char_model; 29 26 pub mod render; 30 27 28 + #[allow(unused)] 31 29 const OVERLAY_REBECCA_PURPLE: wgpu::Color = wgpu::Color { 32 30 r: 0.1, 33 31 g: 0.12, ··· 65 63 shape_data: Vec<u8>, 66 64 } 67 65 68 - struct WgpuSubState<'a> { 69 - inner: ( 70 - wgpu::Device, 71 - wgpu::Queue, 72 - &'a wgpu::BindGroupLayout, 73 - &'a wgpu::BindGroup, 74 - wgpu::TextureFormat, 75 - &'a texture::Texture, 76 - ), 77 - } 78 - 79 66 pub struct State { 80 67 window: Arc<Window>, 81 68 device: wgpu::Device, ··· 84 71 surface: wgpu::Surface<'static>, 85 72 surface_format: wgpu::TextureFormat, 86 73 char_info: NxCharInfo, 87 - char_model: Option<CharModel>, 88 74 char_remake: bool, 89 75 camera: Camera, 90 76 camera_buffer: wgpu::Buffer, 91 77 camera_bind_group: wgpu::BindGroup, 92 78 camera_uniform: CameraUniform, 93 79 camera_bind_group_layout: wgpu::BindGroupLayout, 94 - depth_texture: texture::Texture, 80 + depth_texture: texture::TextureBundle, 95 81 camera_rotations: usize, 96 82 resources: ResourceData, 97 83 } ··· 117 103 self.surface_format 118 104 } 119 105 120 - fn depth_texture(&self) -> &vfl::draw::wgpu_render::texture::Texture { 106 + fn depth_texture(&self) -> &vfl::draw::wgpu_render::texture::TextureBundle { 121 107 &self.depth_texture 122 108 } 123 109 } 124 110 125 - impl<'a> ProgramState for WgpuSubState<'a> { 126 - fn device(&self) -> wgpu::Device { 127 - self.inner.0.clone() 128 - } 129 - 130 - fn queue(&self) -> wgpu::Queue { 131 - self.inner.1.clone() 132 - } 133 - 134 - fn camera_bgl(&self) -> &wgpu::BindGroupLayout { 135 - self.inner.2 136 - } 137 - 138 - fn camera_bg(&self) -> &wgpu::BindGroup { 139 - self.inner.3 140 - } 141 - 142 - fn surface_fmt(&self) -> wgpu::TextureFormat { 143 - self.inner.4.clone() 144 - } 145 - 146 - fn depth_texture(&self) -> &texture::Texture { 147 - self.inner.5 148 - } 149 - } 150 - 151 111 impl State { 152 - fn wgpu_sub_state(&self) -> WgpuSubState { 153 - WgpuSubState { 154 - inner: ( 155 - self.device(), 156 - self.queue(), 157 - self.camera_bgl(), 158 - self.camera_bg(), 159 - self.surface_fmt(), 160 - self.depth_texture(), 161 - ), 162 - } 163 - } 164 - 165 112 async fn new(window: Arc<Window>) -> State { 166 113 let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor { 167 114 backends: Backends::PRIMARY | Backends::SECONDARY, ··· 171 118 .request_adapter(&wgpu::RequestAdapterOptions::default()) 172 119 .await 173 120 .unwrap(); 174 - let (device, queue) = adapter 175 - .request_device(&wgpu::DeviceDescriptor::default()) 176 - .await 177 - .unwrap(); 121 + 122 + dbg!( 123 + adapter.get_texture_format_features(wgpu::TextureFormat::Astc { 124 + block: wgpu::AstcBlock::B4x4, 125 + channel: wgpu::AstcChannel::Unorm 126 + }) 127 + ); 128 + let device_descriptor = wgpu::DeviceDescriptor { 129 + required_features: Features::TEXTURE_COMPRESSION_ASTC 130 + | Features::TEXTURE_COMPRESSION_BC, 131 + ..Default::default() 132 + }; 133 + let (device, queue) = adapter.request_device(&device_descriptor).await.unwrap(); 178 134 179 135 let size = window.inner_size(); 180 136 let size = uvec2(size.width, size.height); ··· 183 139 let cap = surface.get_capabilities(&adapter); 184 140 let surface_format = cap.formats[0]; 185 141 186 - let depth_texture = texture::Texture::create_depth_texture(&device, &size, "depth_texture"); 142 + let depth_texture = 143 + texture::TextureBundle::create_depth_texture(&device, &size, "depth_texture"); 187 144 188 145 let mut char_info = 189 146 File::open(format!("{}/../{}", env!("CARGO_MANIFEST_DIR"), FACES[0])).unwrap(); ··· 237 194 let shape_header = ResourceShape::read(&mut File::open(SHAPE_MID_DAT).unwrap()).unwrap(); 238 195 let texture_header = 239 196 ResourceTexture::read(&mut File::open(TEXTURE_MID_SRGB_DAT).unwrap()).unwrap(); 240 - let shape_data = (std::fs::read(SHAPE_MID_DAT).unwrap()); 241 - let texture_data = (std::fs::read(TEXTURE_MID_SRGB_DAT).unwrap()); 197 + let shape_data = std::fs::read(SHAPE_MID_DAT).unwrap(); 198 + let texture_data = std::fs::read(TEXTURE_MID_SRGB_DAT).unwrap(); 242 199 243 200 let resources = ResourceData { 244 201 shape_header, ··· 255 212 surface, 256 213 surface_format, 257 214 char_info, 258 - char_model: None, 259 215 camera, 260 216 camera_buffer, 261 217 camera_bind_group, ··· 299 255 self.configure_surface(); 300 256 301 257 self.depth_texture = 302 - texture::Texture::create_depth_texture(&self.device, &self.size, "depth_texture"); 258 + texture::TextureBundle::create_depth_texture(&self.device, &self.size, "depth_texture"); 303 259 } 304 260 305 261 fn render(&mut self) { ··· 356 312 let new_model = CharModel::new(self, &mut encoder); 357 313 CHAR_MODEL.set(Mutex::new(new_model)).unwrap(); 358 314 } 315 + 316 + // For profiling: 317 + // self.char_remake = true; 318 + 359 319 if self.char_remake { 360 320 self.char_remake = false; 361 321 // let mut encoder = self.device.create_command_encoder(&Default::default());
+1 -3
lightweight_viewer/src/render.rs
··· 1 - use crate::OVERLAY_REBECCA_PURPLE; 2 - use crate::wgpu_color_to_vec4; 3 1 use glam::{Vec3, vec4}; 4 2 use vfl::draw::render_3d::Rendered3dShape; 5 3 use vfl::draw::wgpu_render::texture; ··· 15 13 shape: Shape, 16 14 color: usize, 17 15 position: Vec3, 18 - projected_texture: Option<texture::Texture>, 16 + projected_texture: Option<texture::TextureBundle>, 19 17 ) -> Rendered3dShape { 20 18 let mut vertices: Vec<Vertex> = vec![]; 21 19 let tex_coords = d
+67 -18
vfl/src/draw/render_2d.rs
··· 3 3 use image::DynamicImage; 4 4 use nalgebra::Matrix4; 5 5 use wgpu::{ 6 - CommandEncoder, PipelineCompilationOptions, TexelCopyTextureInfo, TextureView, include_wgsl, 7 - util::DeviceExt, 6 + CommandEncoder, PipelineCompilationOptions, TexelCopyTextureInfo, TextureFormat, TextureView, 7 + include_wgsl, util::DeviceExt, 8 8 }; 9 9 10 10 use crate::{ 11 11 color::nx::{ModulationIntent, modulate}, 12 - res::tex::nx::ResourceTextureFormat, 12 + res::tex::nx::{RawTexture, ResourceTexture, ResourceTextureFormat, TextureElement}, 13 13 }; 14 14 15 15 use super::{ ··· 25 25 pub struct Rendered2dShape { 26 26 pub vertices: Vec<Vertex>, 27 27 pub indices: Vec<u32>, 28 - pub tex: DynamicImage, 28 + pub tex: RawTexture, 29 29 pub mvp_matrix: Matrix4<f32>, 30 30 pub modulation: ModulationIntent, 31 31 pub opaque: Option<Color>, 32 32 } 33 33 34 + pub fn texture_format_to_wgpu(tex: TextureElement) -> TextureFormat { 35 + use TextureFormat as WgpuTextureFormat; 36 + let format = ResourceTextureFormat::try_from(tex.texture.format).unwrap(); 37 + match format { 38 + ResourceTextureFormat::R => WgpuTextureFormat::R8Unorm, 39 + ResourceTextureFormat::Rg => WgpuTextureFormat::Rg8Unorm, 40 + ResourceTextureFormat::Rgba => WgpuTextureFormat::Rgba8Unorm, 41 + ResourceTextureFormat::Bc4 => WgpuTextureFormat::Bc4RUnorm, 42 + ResourceTextureFormat::Bc5 => WgpuTextureFormat::Bc5RgUnorm, 43 + ResourceTextureFormat::Bc7 => WgpuTextureFormat::Bc7RgbaUnorm, 44 + ResourceTextureFormat::Astc4x4 => WgpuTextureFormat::Astc { 45 + block: wgpu::AstcBlock::B4x4, 46 + channel: wgpu::AstcChannel::Unorm, 47 + }, 48 + } 49 + } 50 + 51 + pub fn texture_format_buffer_layout(tex: TextureElement) -> wgpu::TexelCopyBufferLayout { 52 + use ResourceTextureFormat as Rtf; 53 + const BC3_BYTES_PER_BLOCK: u32 = 16; 54 + const BC3_PIXELS_PER_BLOCK: u32 = 4; 55 + const BC4_BYTES_PER_BLOCK: u32 = 8; 56 + 57 + let format = Rtf::try_from(tex.texture.format).unwrap(); 58 + 59 + match format { 60 + Rtf::R => wgpu::TexelCopyBufferLayout { 61 + offset: 0, 62 + bytes_per_row: Some(u32::from(tex.texture.width)), 63 + rows_per_image: None, 64 + }, 65 + Rtf::Rg => wgpu::TexelCopyBufferLayout { 66 + offset: 0, 67 + bytes_per_row: Some(2 * u32::from(tex.texture.width)), 68 + rows_per_image: None, 69 + }, 70 + Rtf::Astc4x4 | Rtf::Bc7 | Rtf::Bc4 | Rtf::Rgba => wgpu::TexelCopyBufferLayout { 71 + offset: 0, 72 + bytes_per_row: Some((16 / 4) * u32::from(tex.texture.width)), 73 + rows_per_image: None, 74 + }, 75 + Rtf::Bc5 => wgpu::TexelCopyBufferLayout { 76 + offset: 0, 77 + bytes_per_row: Some((32 / 4) * u32::from(tex.texture.width)), 78 + rows_per_image: None, 79 + }, 80 + } 81 + } 82 + 34 83 impl Rendered2dShape { 35 84 pub fn render_texture_trivial( 36 - rendered_texture: DynamicImage, 85 + rendered_texture: RawTexture, 37 86 modulation: ModulationIntent, 38 87 opaque: Option<Color>, 39 88 st: &mut impl ProgramState, ··· 84 133 usage: wgpu::BufferUsages::INDEX, 85 134 }); 86 135 87 - let shape_texture_rgba = self.tex.to_rgba8(); 88 - let shape_texture_dimensions = shape_texture_rgba.dimensions(); 89 136 let shape_texture_size = wgpu::Extent3d { 90 - width: shape_texture_dimensions.0, 91 - height: shape_texture_dimensions.1, 137 + width: u32::from(self.tex.metadata.texture.width), 138 + height: u32::from(self.tex.metadata.texture.height), 92 139 depth_or_array_layers: 1, 93 140 }; 94 141 let shape_diffuse_texture = st.device().create_texture(&wgpu::TextureDescriptor { ··· 96 143 mip_level_count: 1, 97 144 sample_count: 1, 98 145 dimension: wgpu::TextureDimension::D2, 99 - format: st.surface_fmt().add_srgb_suffix(), 146 + format: texture_format_to_wgpu(self.tex.metadata), 100 147 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, 101 148 label: Some("diffuse_texture"), 102 - view_formats: &[st.surface_fmt()], 149 + view_formats: &[ 150 + texture_format_to_wgpu(self.tex.metadata), 151 + texture_format_to_wgpu(self.tex.metadata).add_srgb_suffix(), 152 + ], 103 153 }); 104 154 105 155 st.queue().write_texture( ··· 109 159 origin: wgpu::Origin3d::ZERO, 110 160 aspect: wgpu::TextureAspect::All, 111 161 }, 112 - &shape_texture_rgba, 113 - wgpu::TexelCopyBufferLayout { 114 - offset: 0, 115 - bytes_per_row: Some(4 * shape_texture_dimensions.0), 116 - rows_per_image: Some(shape_texture_dimensions.1), 117 - }, 162 + &self.tex.bytes, 163 + texture_format_buffer_layout(self.tex.metadata), 118 164 shape_texture_size, 119 165 ); 120 166 121 167 let shape_diffuse_texture_view = 122 - shape_diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default()); 168 + shape_diffuse_texture.create_view(&wgpu::TextureViewDescriptor { 169 + format: Some(texture_format_to_wgpu(self.tex.metadata)), 170 + ..Default::default() 171 + }); 123 172 let shape_diffuse_sampler = st.device().create_sampler(&wgpu::SamplerDescriptor { 124 173 address_mode_u: wgpu::AddressMode::ClampToEdge, 125 174 address_mode_v: wgpu::AddressMode::ClampToEdge,
+3 -3
vfl/src/draw/render_3d.rs
··· 21 21 fn camera_bgl(&self) -> &wgpu::BindGroupLayout; 22 22 fn camera_bg(&self) -> &wgpu::BindGroup; 23 23 fn surface_fmt(&self) -> wgpu::TextureFormat; 24 - fn depth_texture(&self) -> &texture::Texture; 24 + fn depth_texture(&self) -> &texture::TextureBundle; 25 25 } 26 26 27 27 #[derive(Default, Debug)] ··· 29 29 pub vertices: Vec<Vertex>, 30 30 pub indices: Vec<u32>, 31 31 pub color: Vec4, 32 - pub texture: Option<crate::draw::wgpu_render::texture::Texture>, 32 + pub texture: Option<crate::draw::wgpu_render::texture::TextureBundle>, 33 33 pub position: Vec3, 34 34 } 35 35 ··· 190 190 conservative: false, 191 191 }, 192 192 depth_stencil: Some(wgpu::DepthStencilState { 193 - format: texture::Texture::DEPTH_FORMAT, 193 + format: texture::TextureBundle::DEPTH_FORMAT, 194 194 depth_write_enabled: true, 195 195 depth_compare: wgpu::CompareFunction::Less, // 1. 196 196 stencil: wgpu::StencilState::default(), // 2.
+16 -12
vfl/src/draw/shader.wgsl
··· 52 52 // AlphaTexture = 3, 53 53 // LuminanceAlphaTexture = 4, 54 54 // } 55 - 56 55 if mvp.modulation_mode == 0 { 57 56 return modulate_single_color(color); 58 - } else if mvp.modulation_mode == 1 { 59 - return modulate_direct_texture(color); 60 - } else if mvp.modulation_mode == 2 { 61 - return modulate_rgba(color); 62 - } else if mvp.modulation_mode == 3 { 63 - return modulate_alpha(color); 64 - } else if mvp.modulation_mode == 4 { 65 - return modulate_lum_alpha(color); 66 - } else { 67 - // OOB access, return RebeccaPurple 68 - return vec4f(0.4, 0.2, 0.6, 1.0); 69 57 } 58 + return color; 59 + 60 + // if mvp.modulation_mode == 0 { 61 + // return modulate_single_color(color); 62 + // } else if mvp.modulation_mode == 1 { 63 + // return modulate_direct_texture(color); 64 + // } else if mvp.modulation_mode == 2 { 65 + // return modulate_rgba(color); 66 + // } else if mvp.modulation_mode == 3 { 67 + // return modulate_alpha(color); 68 + // } else if mvp.modulation_mode == 4 { 69 + // return modulate_lum_alpha(color); 70 + // } else { 71 + // // OOB access, return RebeccaPurple 72 + // return vec4f(0.4, 0.2, 0.6, 1.0); 73 + // } 70 74 } 71 75 72 76 // Two trivial cases
+21 -349
vfl/src/draw/wgpu_render.rs
··· 113 113 256.0, 114 114 ); 115 115 116 - let tex = tex_data.get_image(file_texture).unwrap().unwrap(); 116 + let tex = tex_data 117 + .get_uncompressed_bytes(file_texture) 118 + .unwrap() 119 + .unwrap(); 117 120 118 121 Rendered2dShape { 119 122 vertices, 120 123 indices, 121 - tex: image::DynamicImage::ImageRgba8(tex), 124 + tex, 122 125 mvp_matrix: mtx, 123 126 modulation: modulate(modulated, char), 124 127 opaque: None, ··· 181 184 256.0, 182 185 ); 183 186 184 - let tex = tex_data.get_image(file_texture).unwrap().unwrap(); 187 + let tex = tex_data 188 + .get_uncompressed_bytes(file_texture) 189 + .unwrap() 190 + .unwrap(); 185 191 186 192 Rendered2dShape { 187 193 vertices, 188 194 indices, 189 - tex: image::DynamicImage::ImageRgba8(tex), 195 + tex, 190 196 mvp_matrix: mtx, 191 197 modulation: modulate(modulated, char), 192 198 opaque: None, ··· 231 237 256.0, 232 238 ); 233 239 234 - let tex = tex_data.get_image(file_texture)?.unwrap(); 240 + let tex = tex_data.get_uncompressed_bytes(file_texture)?.unwrap(); 235 241 236 242 let glass_l_render_shape = Rendered2dShape { 237 243 vertices, 238 244 indices, 239 - tex: image::DynamicImage::ImageRgba8(tex.clone()), 245 + tex: tex.clone(), 240 246 mvp_matrix: mtx, 241 247 modulation: modulate(ColorModulated::Glass, &char), 242 248 opaque: None, ··· 257 263 let glass_r_render_shape = Rendered2dShape { 258 264 vertices, 259 265 indices, 260 - tex: image::DynamicImage::ImageRgba8(tex), 266 + tex, 261 267 mvp_matrix: mtx, 262 268 modulation: modulate(ColorModulated::Glass, &char), 263 269 opaque: None, ··· 378 384 camera_bgl: wgpu::BindGroupLayout, 379 385 camera_bg: wgpu::BindGroup, 380 386 surface_fmt: wgpu::TextureFormat, 381 - depth_texture: texture::Texture, 387 + depth_texture: texture::TextureBundle, 382 388 } 383 389 384 390 impl ProgramState for HeadlessRenderer { ··· 402 408 self.surface_fmt 403 409 } 404 410 405 - fn depth_texture(&self) -> &texture::Texture { 411 + fn depth_texture(&self) -> &texture::TextureBundle { 406 412 &self.depth_texture 407 413 } 408 414 } ··· 440 446 // let surface_fmt = cap.formats[0]; 441 447 let surface_fmt = wgpu::TextureFormat::Bgra8Unorm; 442 448 443 - let depth_texture = texture::Texture::create_depth_texture(&device, &SIZE, "depth_texture"); 449 + let depth_texture = 450 + texture::TextureBundle::create_depth_texture(&device, &SIZE, "depth_texture"); 444 451 445 452 let camera = Camera { 446 453 eye: (0.0, 25.0, 100.0).into(), ··· 496 503 497 504 pub fn output_texture( 498 505 &mut self, 499 - texture: &texture::Texture, 506 + texture: &texture::TextureBundle, 500 507 mut encoder: CommandEncoder, 501 508 ) -> DynamicImage { 502 509 pollster::block_on(async { ··· 567 574 } 568 575 } 569 576 570 - #[deprecated] 571 - #[allow(clippy::too_many_lines)] 572 - pub async fn render_context_wgpu(render_context: RenderContext) -> DynamicImage { 573 - let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor { 574 - backends: wgpu::Backends::all(), 575 - ..Default::default() 576 - }); 577 - let adapter = instance 578 - .request_adapter(&wgpu::RequestAdapterOptions { 579 - power_preference: wgpu::PowerPreference::default(), 580 - compatible_surface: None, 581 - force_fallback_adapter: false, 582 - }) 583 - .await 584 - .unwrap(); 585 - let (device, queue) = adapter 586 - .request_device(&DeviceDescriptor::default()) 587 - .await 588 - .unwrap(); 589 - 590 - let texture_desc = wgpu::TextureDescriptor { 591 - size: wgpu::Extent3d { 592 - width: render_context.size.x, 593 - height: render_context.size.y, 594 - depth_or_array_layers: 1, 595 - }, 596 - mip_level_count: 1, 597 - sample_count: 1, 598 - dimension: wgpu::TextureDimension::D2, 599 - format: wgpu::TextureFormat::Rgba8UnormSrgb, 600 - usage: wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::RENDER_ATTACHMENT, 601 - label: None, 602 - view_formats: &[wgpu::TextureFormat::Rgba8UnormSrgb], 603 - }; 604 - let texture = device.create_texture(&texture_desc); 605 - let texture_view = texture.create_view(&Default::default()); 606 - let u32_size = std::mem::size_of::<u32>() as u32; 607 - let output_buffer_size = 608 - wgpu::BufferAddress::from(u32_size * render_context.size.x * render_context.size.y); 609 - let output_buffer_desc = wgpu::BufferDescriptor { 610 - size: output_buffer_size, 611 - usage: wgpu::BufferUsages::COPY_DST 612 - // this tells wpgu that we want to read this buffer from the cpu 613 - | wgpu::BufferUsages::MAP_READ, 614 - label: None, 615 - mapped_at_creation: false, 616 - }; 617 - let output_buffer = device.create_buffer(&output_buffer_desc); 618 - 619 - let mut encoder = 620 - device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None }); 621 - 622 - for shape in render_context.shape { 623 - let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 624 - label: Some("Vertex Buffer"), 625 - contents: bytemuck::cast_slice(&shape.vertices), 626 - usage: wgpu::BufferUsages::VERTEX, 627 - }); 628 - 629 - let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 630 - label: Some("Index Buffer"), 631 - contents: bytemuck::cast_slice(&shape.indices), 632 - usage: wgpu::BufferUsages::INDEX, 633 - }); 634 - 635 - let shape_texture_rgba = shape.tex.to_rgba8(); 636 - let shape_texture_dimensions = shape_texture_rgba.dimensions(); 637 - let shape_texture_size = wgpu::Extent3d { 638 - width: shape_texture_dimensions.0, 639 - height: shape_texture_dimensions.1, 640 - // All textures are stored as 3D, we represent our 2D texture 641 - // by setting depth to 1. 642 - depth_or_array_layers: 1, 643 - }; 644 - let shape_diffuse_texture = device.create_texture(&wgpu::TextureDescriptor { 645 - size: shape_texture_size, 646 - mip_level_count: 1, // We'll talk about this a little later 647 - sample_count: 1, 648 - dimension: wgpu::TextureDimension::D2, 649 - // Most images are stored using sRGB, so we need to reflect that here. 650 - format: wgpu::TextureFormat::Rgba8UnormSrgb, 651 - // TEXTURE_BINDING tells wgpu that we want to use this texture in shaders 652 - // COPY_DST means that we want to copy data to this texture 653 - usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, 654 - label: Some("diffuse_texture"), 655 - // This is the same as with the SurfaceConfig. It 656 - // specifies what texture formats can be used to 657 - // create TextureViews for this texture. The base 658 - // texture format (Rgba8UnormSrgb in this case) is 659 - // always supported. Note that using a different 660 - // texture format is not supported on the WebGL2 661 - // backend. 662 - view_formats: &[], 663 - }); 664 - 665 - queue.write_texture( 666 - TexelCopyTextureInfo { 667 - texture: &shape_diffuse_texture, 668 - mip_level: 0, 669 - origin: wgpu::Origin3d::ZERO, 670 - aspect: wgpu::TextureAspect::All, 671 - }, 672 - &shape_texture_rgba, 673 - wgpu::TexelCopyBufferLayout { 674 - offset: 0, 675 - bytes_per_row: Some(4 * shape_texture_dimensions.0), 676 - rows_per_image: Some(shape_texture_dimensions.1), 677 - }, 678 - shape_texture_size, 679 - ); 680 - 681 - let shape_diffuse_texture_view = 682 - shape_diffuse_texture.create_view(&wgpu::TextureViewDescriptor::default()); 683 - let shape_diffuse_sampler = device.create_sampler(&wgpu::SamplerDescriptor { 684 - address_mode_u: wgpu::AddressMode::ClampToEdge, 685 - address_mode_v: wgpu::AddressMode::ClampToEdge, 686 - address_mode_w: wgpu::AddressMode::ClampToEdge, 687 - mag_filter: wgpu::FilterMode::Linear, 688 - min_filter: wgpu::FilterMode::Nearest, 689 - mipmap_filter: wgpu::FilterMode::Nearest, 690 - ..Default::default() 691 - }); 692 - 693 - let texture_bind_group_layout = 694 - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { 695 - entries: &[ 696 - wgpu::BindGroupLayoutEntry { 697 - binding: 0, 698 - visibility: wgpu::ShaderStages::FRAGMENT, 699 - ty: wgpu::BindingType::Texture { 700 - multisampled: false, 701 - view_dimension: wgpu::TextureViewDimension::D2, 702 - sample_type: wgpu::TextureSampleType::Float { filterable: true }, 703 - }, 704 - count: None, 705 - }, 706 - wgpu::BindGroupLayoutEntry { 707 - binding: 1, 708 - visibility: wgpu::ShaderStages::FRAGMENT, 709 - // This should match the filterable field of the 710 - // corresponding Texture entry above. 711 - ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), 712 - count: None, 713 - }, 714 - ], 715 - label: Some("texture_bind_group_layout"), 716 - }); 717 - 718 - let shape_diffuse_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { 719 - layout: &texture_bind_group_layout, 720 - entries: &[ 721 - wgpu::BindGroupEntry { 722 - binding: 0, 723 - resource: wgpu::BindingResource::TextureView(&shape_diffuse_texture_view), 724 - }, 725 - wgpu::BindGroupEntry { 726 - binding: 1, 727 - resource: wgpu::BindingResource::Sampler(&shape_diffuse_sampler), 728 - }, 729 - ], 730 - label: Some("diffuse_bind_group"), 731 - }); 732 - 733 - let mvp_matrix = shape.mvp_matrix.into(); 734 - let mvp_uniform = TextureTransformUniform { 735 - mvp_matrix, 736 - channel_replacements_r: shape.modulation.channels[0], 737 - channel_replacements_g: shape.modulation.channels[1], 738 - channel_replacements_b: shape.modulation.channels[2], 739 - texture_type: (Into::<u8>::into(shape.modulation.mode)).into(), 740 - pad: Default::default(), 741 - }; 742 - 743 - let mvp_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 744 - label: Some("MvpMatrix Buffer"), 745 - contents: bytemuck::cast_slice(&[mvp_uniform]), 746 - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, 747 - }); 748 - 749 - let mvp_bind_group_layout = 750 - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { 751 - entries: &[wgpu::BindGroupLayoutEntry { 752 - binding: 0, 753 - visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT, 754 - ty: wgpu::BindingType::Buffer { 755 - ty: wgpu::BufferBindingType::Uniform, 756 - has_dynamic_offset: false, 757 - min_binding_size: None, 758 - }, 759 - count: None, 760 - }], 761 - label: Some("mvp_bind_group_layout"), 762 - }); 763 - 764 - let mvp_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { 765 - layout: &mvp_bind_group_layout, 766 - entries: &[wgpu::BindGroupEntry { 767 - binding: 0, 768 - resource: mvp_buffer.as_entire_binding(), 769 - }], 770 - label: Some("mvp_bind_group"), 771 - }); 772 - 773 - let shader = wgpu::ShaderSource::Wgsl(SHADER.into()); 774 - let shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor { 775 - label: Some("Shader"), 776 - source: shader, 777 - }); 778 - let render_pipeline_layout = 779 - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { 780 - label: Some("Render Pipeline Layout"), 781 - bind_group_layouts: &[&texture_bind_group_layout, &mvp_bind_group_layout], 782 - push_constant_ranges: &[], 783 - }); 784 - let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { 785 - label: Some("Render Pipeline"), 786 - layout: Some(&render_pipeline_layout), 787 - vertex: wgpu::VertexState { 788 - module: &shader_module, 789 - entry_point: Some("vs_main"), 790 - buffers: &[Vertex::desc()], 791 - compilation_options: Default::default(), 792 - }, 793 - fragment: Some(wgpu::FragmentState { 794 - module: &shader_module, 795 - entry_point: Some("fs_main"), 796 - targets: &[Some(wgpu::ColorTargetState { 797 - format: texture_desc.format, 798 - blend: Some(wgpu::BlendState::ALPHA_BLENDING), 799 - write_mask: wgpu::ColorWrites::ALL, 800 - })], 801 - compilation_options: Default::default(), 802 - }), 803 - primitive: wgpu::PrimitiveState { 804 - topology: wgpu::PrimitiveTopology::TriangleList, 805 - strip_index_format: None, 806 - front_face: wgpu::FrontFace::Ccw, 807 - cull_mode: Some(wgpu::Face::Back), 808 - // Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE 809 - polygon_mode: wgpu::PolygonMode::Fill, 810 - // Requires Features::DEPTH_CLIP_CONTROL 811 - unclipped_depth: false, 812 - // Requires Features::CONSERVATIVE_RASTERIZATION 813 - conservative: false, 814 - }, 815 - depth_stencil: None, 816 - multisample: wgpu::MultisampleState { 817 - count: 1, 818 - mask: !0, 819 - alpha_to_coverage_enabled: false, 820 - }, 821 - // If the pipeline will be used with a multiview render pass, this 822 - // indicates how many array layers the attachments will have. 823 - multiview: None, 824 - cache: None, 825 - }); 826 - 827 - { 828 - let render_pass_desc = wgpu::RenderPassDescriptor { 829 - label: Some("Render Pass"), 830 - color_attachments: &[Some(wgpu::RenderPassColorAttachment { 831 - view: &texture_view, 832 - resolve_target: None, 833 - ops: wgpu::Operations { 834 - load: wgpu::LoadOp::Load, 835 - store: wgpu::StoreOp::Store, 836 - }, 837 - })], 838 - depth_stencil_attachment: None, 839 - occlusion_query_set: None, 840 - timestamp_writes: None, 841 - }; 842 - let mut render_pass = encoder.begin_render_pass(&render_pass_desc); 843 - 844 - render_pass.set_pipeline(&render_pipeline); 845 - render_pass.set_bind_group(0, &shape_diffuse_bind_group, &[]); 846 - render_pass.set_bind_group(1, &mvp_bind_group, &[]); 847 - render_pass.set_vertex_buffer(0, vertex_buffer.slice(..)); 848 - render_pass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32); 849 - 850 - render_pass.draw_indexed(0..shape.indices.len() as u32, 0, 0..1); 851 - } 852 - } 853 - encoder.copy_texture_to_buffer( 854 - wgpu::TexelCopyTextureInfo { 855 - aspect: wgpu::TextureAspect::All, 856 - texture: &texture, 857 - mip_level: 0, 858 - origin: wgpu::Origin3d::ZERO, 859 - }, 860 - wgpu::TexelCopyBufferInfo { 861 - buffer: &output_buffer, 862 - layout: wgpu::TexelCopyBufferLayout { 863 - offset: 0, 864 - bytes_per_row: Some(u32_size * render_context.size.x), 865 - rows_per_image: Some(render_context.size.x), 866 - }, 867 - }, 868 - texture_desc.size, 869 - ); 870 - 871 - queue.submit(Some(encoder.finish())); 872 - 873 - let mut image = None; 874 - // We need to scope the mapping variables so that we can 875 - // unmap the buffer 876 - { 877 - let buffer_slice = output_buffer.slice(..); 878 - 879 - // NOTE: We have to create the mapping THEN device.poll() before await 880 - // the future. Otherwise the application will freeze. 881 - let (tx, rx) = futures_intrusive::channel::shared::oneshot_channel(); 882 - buffer_slice.map_async(wgpu::MapMode::Read, move |result| { 883 - tx.send(result).unwrap(); 884 - }); 885 - device.poll(wgpu::PollType::Wait).unwrap(); 886 - rx.receive().await.unwrap().unwrap(); 887 - 888 - let data = &buffer_slice.get_mapped_range()[..]; 889 - 890 - use image::{ImageBuffer, Rgba}; 891 - let buffer: RgbaImage = ImageBuffer::<Rgba<u8>, _>::from_raw( 892 - render_context.size.x, 893 - render_context.size.y, 894 - data.to_owned(), 895 - ) 896 - .unwrap(); 897 - // buffer.save("image.png").unwrap(); 898 - image = Some(DynamicImage::ImageRgba8(buffer)); 899 - } 900 - output_buffer.unmap(); 901 - 902 - image.unwrap() 903 - } 904 - 905 577 pub mod texture { 906 578 use std::error::Error; 907 579 use std::fmt::Debug; ··· 910 582 use image::GenericImageView; 911 583 use wgpu::TextureFormat; 912 584 913 - pub struct Texture { 585 + pub struct TextureBundle { 914 586 #[allow(unused)] 915 587 pub texture: wgpu::Texture, 916 588 pub view: wgpu::TextureView, 917 589 pub sampler: wgpu::Sampler, 918 590 } 919 - impl Debug for Texture { 591 + impl Debug for TextureBundle { 920 592 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 921 593 f.debug_struct("Texture").finish() 922 594 } 923 595 } 924 596 925 597 #[allow(unused)] 926 - impl Texture { 598 + impl TextureBundle { 927 599 pub fn from_bytes( 928 600 device: &wgpu::Device, 929 601 queue: &wgpu::Queue,
+27 -8
vfl/src/res/tex/nx.rs
··· 34 34 #[repr(u8)] 35 35 pub enum ResourceTextureFormat { 36 36 R = 0, // R8Unorm (Ffl Name) 37 - Rb = 1, // R8B8Unorm 38 - Rgba = 2, // R8B8G8A8Unorm 37 + Rg = 1, // R8G8Unorm 38 + Rgba = 2, // R8G8B8A8Unorm 39 39 Bc4 = 3, // Bc4Unorm (Compressed R) 40 40 Bc5 = 4, // Bc5Unorm (Compressed Rb) 41 41 Bc7 = 5, // Bc7Unorm (Compressed Rgba) 42 42 Astc4x4 = 6, // Astc4x4Unorm (Compressed Rgba) 43 43 } 44 44 45 + // pub enum RawTexture { 46 + // R(Vec<u8>), 47 + // Rb(Vec<u8>), 48 + // Rgba(Vec<u8>), 49 + // Bc4(Vec<u8>), 50 + // Bc5(Vec<u8>), 51 + // Bc7(Vec<u8>), 52 + // Astc4x4(Vec<u8>), 53 + // } 54 + 55 + #[derive(Clone, Debug)] 56 + pub struct RawTexture { 57 + pub bytes: Vec<u8>, 58 + pub metadata: TextureElement, 59 + } 60 + 45 61 impl TextureElement { 46 62 pub fn get_texture_bytes(&self, file: &Vec<u8>) -> Result<Vec<u8>, Box<dyn Error>> { 47 63 let start: usize = self.common.offset as usize; ··· 64 80 let tex_data = if needs_swizzling { 65 81 let block_size = match ResourceTextureFormat::try_from(self.texture.format).unwrap() { 66 82 ResourceTextureFormat::R 67 - | ResourceTextureFormat::Rb 83 + | ResourceTextureFormat::Rg 68 84 | ResourceTextureFormat::Rgba => 1, 69 85 ResourceTextureFormat::Bc4 70 86 | ResourceTextureFormat::Bc5 ··· 75 91 let bytes_per_pixel = 76 92 match ResourceTextureFormat::try_from(self.texture.format).unwrap() { 77 93 ResourceTextureFormat::R 78 - | ResourceTextureFormat::Rb 94 + | ResourceTextureFormat::Rg 79 95 | ResourceTextureFormat::Rgba => 1, 80 96 ResourceTextureFormat::Bc4 => 8, 81 97 ResourceTextureFormat::Bc5 ··· 106 122 pub fn get_uncompressed_bytes( 107 123 &self, 108 124 file: &Vec<u8>, 109 - ) -> Result<Option<Vec<u8>>, Box<dyn Error>> { 125 + ) -> Result<Option<RawTexture>, Box<dyn Error>> { 110 126 let normalize_textures = false; 111 127 112 128 if self.texture.width == 0 || self.texture.height == 0 { ··· 191 207 }) 192 208 .collect(); 193 209 194 - Ok(Some(tex_data_decoded)) 210 + Ok(Some(RawTexture { 211 + bytes: tex_data_decoded, 212 + metadata: self.clone(), 213 + })) 195 214 } 196 215 197 216 #[cfg(feature = "draw")] 198 217 pub fn get_image(&self, bytes: &Vec<u8>) -> Result<Option<RgbaImage>, Box<dyn Error>> { 199 - let bytes = match self.get_uncompressed_bytes(bytes) { 218 + let raw_texture = match self.get_uncompressed_bytes(bytes) { 200 219 Ok(Some(bytes)) => bytes, 201 220 Ok(None) => return Ok(None), 202 221 Err(e) => return Err(e), ··· 205 224 let img: ImageBuffer<Rgba<u8>, Vec<u8>> = image::RgbaImage::from_raw( 206 225 self.texture.width.into(), 207 226 self.texture.height.into(), 208 - bytes, 227 + raw_texture.bytes, 209 228 ) 210 229 .unwrap(); 211 230