changeset 753:a662dddd4a2b

examples: Use array textures for enemy PNGs This requires luminance 0.39.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 25 Feb 2020 21:03:44 +0100
parents 5e5e7136ac92
children a6875f90c141
files Cargo.toml examples/anmrenderer.rs examples/common.rs examples/eclrenderer.rs examples/menu.rs examples/stagerunner.rs examples/stdrenderer.rs
diffstat 7 files changed, 80 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- 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"
--- 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| {
--- 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<P: AsRef<Path>
 }
 
 pub enum LoadedTexture {
-    Rgba(Texture<Flat, Dim2, NormRGBA8UI>),
-    Rgb(Texture<Flat, Dim2, NormRGB8UI>),
+    Rgba(Texture<Dim2, NormRGBA8UI>),
+    Rgb(Texture<Dim2, NormRGB8UI>),
+    RgbaArray(Texture<Dim2Array, NormRGBA8UI>),
 }
 
 #[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<Flat, Dim2, NormRGB8UI>, img: DynamicImage) -> Result<(), TextureLoadError> {
+pub fn reupload_texture_from_rgb_image(tex: &mut Texture<Dim2, NormRGB8UI>, 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<P: AsRef<Path>>(mu
         }
     }
 }
+
+fn load_array_texture(surface: &mut GlfwSurface, images: &[(&Path, &Path)]) -> Result<LoadedTexture, TextureLoadError> {
+    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::<Vec<_>>()).unwrap();
+
+    Ok(LoadedTexture::RgbaArray(tex))
+}
+
+pub fn load_multiple_anm_images<P: AsRef<Path>>(mut surface: &mut GlfwSurface, anms: &[Anm0], anm_filename: P) -> Result<LoadedTexture, TextureLoadError> {
+    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())
+}
--- 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| {
--- 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
--- 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| {
--- 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| {