# HG changeset patch # User Emmanuel Gil Peyrot # Date 1582661024 -3600 # Node ID a662dddd4a2b0ac1c8cf5ccd9a171edcaa989923 # Parent 5e5e7136ac9257e4a1871c50f51f61201554c92e examples: Use array textures for enemy PNGs This requires luminance 0.39. diff --git a/Cargo.toml b/Cargo.toml --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ nom = "5" encoding_rs = "0.8" image = { version = "0.22", default-features = false, features = ["png_codec", "jpeg"] } bitflags = "1" -luminance = "0.38" +luminance = "0.39" luminance-glfw = { version = "0.12", default-features = false, features = ["log-errors"] } luminance-derive = "0.5" ears = "0.8" diff --git a/examples/anmrenderer.rs b/examples/anmrenderer.rs --- a/examples/anmrenderer.rs +++ b/examples/anmrenderer.rs @@ -5,7 +5,7 @@ use luminance::pixel::NormUnsigned; use luminance::render_state::RenderState; use luminance::shader::program::{Program, Uniform}; use luminance::tess::{Mode, TessBuilder}; -use luminance::texture::{Dim2, Flat}; +use luminance::texture::Dim2; use luminance_derive::{Semantics, Vertex, UniformInterface}; use luminance_glfw::{Action, Key, WindowEvent, GlfwSurface, Surface, WindowDim, WindowOpt}; use touhou::th06::anm0::Anm0; @@ -80,7 +80,7 @@ struct Vertex { #[derive(UniformInterface)] struct ShaderInterface { // the 'static lifetime acts as “anything” here - color_map: Uniform<&'static BoundTexture<'static, Flat, Dim2, NormUnsigned>>, + color_map: Uniform<&'static BoundTexture<'static, Dim2, NormUnsigned>>, #[uniform(name = "mvp")] mvp: Uniform<[[f32; 4]; 4]>, @@ -187,6 +187,7 @@ fn main() { let bound_tex = match &tex { LoadedTexture::Rgb(tex) => pipeline.bind_texture(tex), LoadedTexture::Rgba(tex) => pipeline.bind_texture(tex), + LoadedTexture::RgbaArray(tex) => unreachable!(), }; shd_gate.shade(&program, |iface, mut rdr_gate| { diff --git a/examples/common.rs b/examples/common.rs --- a/examples/common.rs +++ b/examples/common.rs @@ -1,6 +1,6 @@ use image::{GenericImageView, DynamicImage, GrayImage, ImageError}; use luminance::pixel::{NormRGB8UI, NormRGBA8UI}; -use luminance::texture::{Dim2, Flat, Sampler, Texture, GenMipmaps}; +use luminance::texture::{Dim2, Dim2Array, Sampler, Texture, GenMipmaps}; use luminance_glfw::GlfwSurface; use touhou::th06::anm0::Anm0; use std::fs::File; @@ -16,8 +16,9 @@ pub fn load_file_into_vec } pub enum LoadedTexture { - Rgba(Texture), - Rgb(Texture), + Rgba(Texture), + Rgb(Texture), + RgbaArray(Texture), } #[derive(Debug)] @@ -49,7 +50,7 @@ pub fn load_from_data(data: &[u8]) -> Re image::load_from_memory(data) } -pub fn reupload_texture_from_rgb_image(tex: &mut Texture, img: DynamicImage) -> Result<(), TextureLoadError> { +pub fn reupload_texture_from_rgb_image(tex: &mut Texture, img: DynamicImage) -> Result<(), TextureLoadError> { let texels = img .pixels() .map(|(_x, _y, rgb)| (rgb[0], rgb[1], rgb[2])) @@ -118,3 +119,46 @@ pub fn load_anm_image>(mu } } } + +fn load_array_texture(surface: &mut GlfwSurface, images: &[(&Path, &Path)]) -> Result { + let mut decoded = vec![]; + let dimensions = (256, 256); + for (rgb, alpha) in images { + let img = open_alpha_png(&alpha)?; + assert_eq!(dimensions, img.dimensions()); + let alpha = match img.grayscale() { + DynamicImage::ImageLuma8(img) => img, + _ => { + return Err(TextureLoadError::AlphaToGrayscale(alpha.to_str().unwrap().to_owned())) + } + }; + let img = open_rgb_png(&rgb)?; + assert_eq!(dimensions, img.dimensions()); + let texels = merge_rgb_alpha(&img, &alpha); + decoded.push(texels); + } + + // create the luminance texture; the third argument is the number of mipmaps we want (leave it + // to 0 for now) and the latest is a the sampler to use when sampling the texels in the + // shader (we’ll just use the default one) + let tex = + Texture::new(surface, ([dimensions.0, dimensions.1], images.len() as u32), 0, Sampler::default()).expect("luminance texture creation"); + + // the first argument disables mipmap generation (we don’t care so far) + tex.upload(GenMipmaps::No, &decoded.into_iter().flatten().collect::>()).unwrap(); + + Ok(LoadedTexture::RgbaArray(tex)) +} + +pub fn load_multiple_anm_images>(mut surface: &mut GlfwSurface, anms: &[Anm0], anm_filename: P) -> Result { + let anm_filename = anm_filename.as_ref(); + let mut paths = vec![]; + for anm0 in anms.iter() { + let rgb_filename = anm_filename.with_file_name(Path::new(&anm0.png_filename).file_name().unwrap()); + let filename = anm0.alpha_filename.as_ref().expect("Can’t not have alpha here!"); + let alpha_filename = anm_filename.with_file_name(Path::new(filename).file_name().unwrap()); + paths.push((rgb_filename, alpha_filename)); + } + let paths: Vec<_> = paths.iter().map(|(rgb, alpha)| (rgb.as_ref(), alpha.as_ref())).collect(); + load_array_texture(&mut surface, paths.as_slice()) +} diff --git a/examples/eclrenderer.rs b/examples/eclrenderer.rs --- a/examples/eclrenderer.rs +++ b/examples/eclrenderer.rs @@ -5,7 +5,7 @@ use luminance::pixel::NormUnsigned; use luminance::render_state::RenderState; use luminance::shader::program::{Program, Uniform}; use luminance::tess::{Mode, TessBuilder}; -use luminance::texture::{Dim2, Flat}; +use luminance::texture::Dim2; use luminance_derive::{Semantics, Vertex, UniformInterface}; use luminance_glfw::{Action, Key, WindowEvent, GlfwSurface, Surface, WindowDim, WindowOpt}; use touhou::th06::anm0::Anm0; @@ -82,7 +82,7 @@ struct Vertex { #[derive(UniformInterface)] struct ShaderInterface { // the 'static lifetime acts as “anything” here - color_map: Uniform<&'static BoundTexture<'static, Flat, Dim2, NormUnsigned>>, + color_map: Uniform<&'static BoundTexture<'static, Dim2, NormUnsigned>>, #[uniform(name = "mvp")] mvp: Uniform<[[f32; 4]; 4]>, @@ -198,6 +198,7 @@ fn main() { let bound_tex = match &tex { LoadedTexture::Rgb(tex) => pipeline.bind_texture(tex), LoadedTexture::Rgba(tex) => pipeline.bind_texture(tex), + LoadedTexture::RgbaArray(tex) => unreachable!(), }; shd_gate.shade(&program, |iface, mut rdr_gate| { diff --git a/examples/menu.rs b/examples/menu.rs --- a/examples/menu.rs +++ b/examples/menu.rs @@ -6,7 +6,7 @@ use luminance::pixel::NormUnsigned; use luminance::render_state::RenderState; use luminance::shader::program::{Program, Uniform}; use luminance::tess::{Mode, TessBuilder}; -use luminance::texture::{Dim2, Flat}; +use luminance::texture::Dim2; use luminance_derive::{Semantics, Vertex, UniformInterface}; use luminance_glfw::{Action, Key, WindowEvent, GlfwSurface, Surface, WindowDim, WindowOpt}; use touhou::th06::pbg3; @@ -82,7 +82,7 @@ struct Vertex { #[derive(UniformInterface)] struct ShaderInterface { // the 'static lifetime acts as “anything” here - color_map: Uniform<&'static BoundTexture<'static, Flat, Dim2, NormUnsigned>>, + color_map: Uniform<&'static BoundTexture<'static, Dim2, NormUnsigned>>, #[uniform(name = "mvp")] mvp: Uniform<[[f32; 4]; 4]>, @@ -136,6 +136,7 @@ fn main() { let mut background = match background { LoadedTexture::Rgb(tex) => tex, LoadedTexture::Rgba(tex) => unreachable!(), + LoadedTexture::RgbaArray(tex) => unreachable!(), }; // set the uniform interface to our type so that we can read textures from the shader diff --git a/examples/stagerunner.rs b/examples/stagerunner.rs --- a/examples/stagerunner.rs +++ b/examples/stagerunner.rs @@ -5,7 +5,7 @@ use luminance::pixel::NormUnsigned; use luminance::render_state::RenderState; use luminance::shader::program::{Program, Uniform}; use luminance::tess::{Mode, TessBuilder}; -use luminance::texture::{Dim2, Flat}; +use luminance::texture::Dim2Array; use luminance_derive::{Semantics, Vertex, UniformInterface}; use luminance_glfw::{Action, Key, WindowEvent, GlfwSurface, Surface, WindowDim, WindowOpt}; use touhou::th06::anm0::Anm0; @@ -22,15 +22,17 @@ use std::path::Path; #[path = "common.rs"] mod common; -use common::{load_file_into_vec, load_anm_image, LoadedTexture}; +use common::{load_file_into_vec, load_multiple_anm_images, LoadedTexture}; const VS: &str = r#" in ivec3 in_position; +in uint in_layer; in vec2 in_texcoord; in uvec4 in_color; uniform mat4 mvp; +flat out uint layer; out vec2 texcoord; out vec4 color; @@ -41,20 +43,23 @@ void main() // Normalized from the u8 being passed. color = vec4(in_color) / 255.; + + layer = in_layer; } "#; const FS: &str = r#" +flat in uint layer; in vec2 texcoord; in vec4 color; -uniform sampler2D color_map; +uniform sampler2DArray color_map; out vec4 frag_color; void main() { - frag_color = texture(color_map, texcoord) * color; + frag_color = texture(color_map, vec3(texcoord, layer)) * color; } "#; @@ -63,6 +68,9 @@ pub enum Semantics { #[sem(name = "in_position", repr = "[i16; 3]", wrapper = "VertexPosition")] Position, + #[sem(name = "in_layer", repr = "u16", wrapper = "VertexLayer")] + Layer, + #[sem(name = "in_texcoord", repr = "[f32; 2]", wrapper = "VertexTexcoord")] Texcoord, @@ -75,6 +83,7 @@ pub enum Semantics { #[vertex(sem = "Semantics")] struct Vertex { pos: VertexPosition, + layer: VertexLayer, uv: VertexTexcoord, rgba: VertexColor, } @@ -82,7 +91,7 @@ struct Vertex { #[derive(UniformInterface)] struct ShaderInterface { // the 'static lifetime acts as “anything” here - color_map: Uniform<&'static BoundTexture<'static, Flat, Dim2, NormUnsigned>>, + color_map: Uniform<&'static BoundTexture<'static, Dim2Array, NormUnsigned>>, #[uniform(name = "mvp")] mvp: Uniform<[[f32; 4]; 4]>, @@ -136,15 +145,8 @@ fn main() { let mut surface = GlfwSurface::new(WindowDim::Windowed(384, 448), "Touhou", WindowOpt::default()).unwrap(); // Open the image atlas matching this ANM. - let mut textures = vec![]; - for anm0 in anms.iter() { - let tex = load_anm_image(&mut surface, &anm0, &anm_filename).expect("image loading"); - textures.push(tex); - } - + let tex = load_multiple_anm_images(&mut surface, &anms, &anm_filename).expect("image loading"); let anms = Rc::new(RefCell::new(anms)); - let tex = textures.pop().unwrap(); - let tex = textures.pop().unwrap(); // set the uniform interface to our type so that we can read textures from the shader let program = @@ -209,8 +211,9 @@ fn main() { .pipeline(&back_buffer, &PipelineState::default(), |pipeline, mut shd_gate| { // bind our fancy texture to the GPU: it gives us a bound texture we can use with the shader let bound_tex = match &tex { - LoadedTexture::Rgb(tex) => pipeline.bind_texture(tex), - LoadedTexture::Rgba(tex) => pipeline.bind_texture(tex), + LoadedTexture::Rgb(tex) => unreachable!(), + LoadedTexture::Rgba(tex) => unreachable!(), + LoadedTexture::RgbaArray(tex) => pipeline.bind_texture(tex), }; shd_gate.shade(&program, |iface, mut rdr_gate| { @@ -226,6 +229,7 @@ fn main() { iface.mvp.update(*mvp.borrow_inner()); let render_state = RenderState::default() + .set_depth_test(None) .set_blending((Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement)); rdr_gate.render(&render_state, |mut tess_gate| { diff --git a/examples/stdrenderer.rs b/examples/stdrenderer.rs --- a/examples/stdrenderer.rs +++ b/examples/stdrenderer.rs @@ -5,7 +5,7 @@ use luminance::pixel::NormUnsigned; use luminance::render_state::RenderState; use luminance::shader::program::{Program, Uniform}; use luminance::tess::{Mode, TessBuilder, TessSliceIndex}; -use luminance::texture::{Dim2, Flat}; +use luminance::texture::Dim2; use luminance_derive::{Semantics, Vertex, UniformInterface}; use luminance_glfw::{Action, Key, WindowEvent, GlfwSurface, Surface, WindowDim, WindowOpt}; use touhou::th06::anm0::Anm0; @@ -89,7 +89,7 @@ struct Vertex { #[derive(UniformInterface)] struct ShaderInterface { // the 'static lifetime acts as “anything” here - color_map: Uniform<&'static BoundTexture<'static, Flat, Dim2, NormUnsigned>>, + color_map: Uniform<&'static BoundTexture<'static, Dim2, NormUnsigned>>, #[uniform(name = "mvp")] mvp: Uniform<[[f32; 4]; 4]>, @@ -211,6 +211,7 @@ fn main() { let bound_tex = match &tex { LoadedTexture::Rgb(tex) => pipeline.bind_texture(tex), LoadedTexture::Rgba(tex) => pipeline.bind_texture(tex), + LoadedTexture::RgbaArray(tex) => unreachable!(), }; shd_gate.shade(&program, |iface, mut rdr_gate| {