summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/teleia/src/assets/shaders/uber/frag.glsl48
-rw-r--r--crates/teleia/src/postprocessing.rs52
-rw-r--r--crates/teleia/src/renderer.rs44
3 files changed, 97 insertions, 47 deletions
diff --git a/crates/teleia/src/assets/shaders/uber/frag.glsl b/crates/teleia/src/assets/shaders/uber/frag.glsl
index 31efd0d..9c9e64a 100644
--- a/crates/teleia/src/assets/shaders/uber/frag.glsl
+++ b/crates/teleia/src/assets/shaders/uber/frag.glsl
@@ -7,8 +7,11 @@ uniform vec2 sprite_offset;
uniform vec2 sprite_dims;
uniform vec4 color;
+
uniform sampler2D texture_color;
uniform sampler2D texture_normal;
+uniform vec2 texture_flip;
+
uniform vec3 light_ambient_color;
uniform vec3 light_dir;
uniform vec3 light_dir_color;
@@ -17,10 +20,10 @@ uniform vec3 light_pos[5];
uniform vec3 light_color[5];
uniform vec2 light_attenuation[5];
-uniform int effect_flip;
-uniform float effect_flash;
-uniform float effect_hueshift;
-uniform float effect_huescale;
+uniform float flash;
+
+uniform float hue_shift;
+uniform float hue_scale;
uniform float opacity;
@@ -37,20 +40,21 @@ bool flag(int mask) {
return (flags & mask) != 0;
}
-mat3 compute_tbn() {
+mat3 compute_tbn(vec2 tc) {
vec3 p = -vertex_view_vector;
vec3 normal = normalize(vertex_normal);
vec3 dpx = dFdx(p);
vec3 dpy = dFdy(p);
- vec2 duvx = dFdx(vertex_texcoord);
- vec2 duvy = dFdy(vertex_texcoord);
+ vec2 duvx = dFdx(tc);
+ vec2 duvy = dFdy(tc);
vec3 dpyperp = cross(dpy, normal);
vec3 dpxperp = cross(normal, dpx);
vec3 tangent = dpyperp * duvx.x + dpxperp * duvy.x;
vec3 bitangent = dpyperp * duvx.y + dpxperp * duvy.y;
float invmax = inversesqrt(max(dot(bitangent, bitangent), dot(bitangent, bitangent)));
- float flip = flag(FLIP_TEXTURE) ? 1.0 : -1.0;
- return mat3(-tangent * invmax, flip * bitangent * invmax, normal);
+ // float xflip = -1.0 + 2.0 * float(texture_flip.x);
+ // float yflip = -1.0 + 2.0 * float(texture_flip.y);
+ return mat3(-tangent * invmax, bitangent * invmax, normal);
}
@@ -144,14 +148,16 @@ vec3 hsl_to_rgb(vec3 hsl) {
}
void main() {
- float tcy = flag(FLIP_TEXTURE) ? vertex_texcoord.y : 1.0 - vertex_texcoord.y;
- vec2 tc = vec2(vertex_texcoord.x, tcy);
- mat3 tbn = compute_tbn();
- if (flag(EFFECTS)) {
- float fbase = float(effect_flip);
- float fmul = 1.0 - 2.0 * fbase;
- tc = vec2(fbase + fmul * vertex_texcoord.x, tcy);
+ vec2 tc = vec2(vertex_texcoord.x, vertex_texcoord.y);
+ if (flag(TEXTURE_FLIP)) {
+ float xfbase = float(texture_flip.x);
+ float xfmul = 1.0 - 2.0 * xfbase;
+ float yfbase = float(texture_flip.y);
+ float yfmul = 1.0 - 2.0 * yfbase;
+ tc.x *= xfmul; tc.x += xfbase;
+ tc.y *= yfmul; tc.y += yfbase;
}
+ mat3 tbn = compute_tbn(tc);
if (flag(SPRITE)) {
tc *= sprite_dims;
tc += sprite_offset;
@@ -160,11 +166,13 @@ void main() {
if (flag(TEXTURE_COLOR)) {
frag_color = texture(texture_color, tc);
}
- if (flag(EFFECTS)) {
+ if (flag(HUE)) {
vec3 hsl = rgb_to_hsl(frag_color.rgb);
- hsl.x = mod(hsl.x * effect_huescale + effect_hueshift, 1.0);
- vec3 p = hsl_to_rgb(hsl);
- frag_color.rgb = vec3(p.r + effect_flash, p.g + effect_flash, p.b + effect_flash);
+ hsl.x = mod(hsl.x * hue_scale + hue_shift, 1.0);
+ frag_color.rgb = hsl_to_rgb(hsl);
+ }
+ if (flag(FLASH)) {
+ frag_color.rgb += vec3(flash);
}
vec3 normal = vertex_normal;
if (flag(TEXTURE_NORMAL)) {
diff --git a/crates/teleia/src/postprocessing.rs b/crates/teleia/src/postprocessing.rs
index b5e8165..227af09 100644
--- a/crates/teleia/src/postprocessing.rs
+++ b/crates/teleia/src/postprocessing.rs
@@ -1,12 +1,28 @@
use crate::{context, framebuffer, shader, state, utils};
+const NUM_BINDINGS: usize = 5;
+
#[derive(Clone, Copy)]
pub struct Effect(usize);
+
+pub enum Uniform {
+ I32(i32),
+ F32(f32),
+ Vec2(glam::Vec2),
+ Vec3(glam::Vec3),
+ Vec4(glam::Vec4),
+ Mat4(glam::Mat4),
+}
+struct Stage {
+ effect: Effect,
+ bindings: [Option<(&'static str, Uniform)>; NUM_BINDINGS],
+}
+
pub struct Pipeline {
- pub effects: Vec<shader::Shader>,
- pub upscale: shader::Shader,
- pub stages: Vec<Effect>,
- pub framebuffer: framebuffer::Framebuffer,
+ effects: Vec<shader::Shader>,
+ upscale: shader::Shader,
+ stages: Vec<Stage>,
+ framebuffer: framebuffer::Framebuffer,
}
impl Pipeline {
pub fn new(ctx: &context::Context) -> Self {
@@ -37,19 +53,43 @@ impl Pipeline {
}
/// Apply a postprocessing effect to the current frame.
pub fn apply(&mut self, effect: Effect) {
- self.stages.push(effect);
+ self.stages.push(Stage { effect, bindings: Default::default() });
+ }
+ /// Apply a postprocessing effect and set extra uniforms.
+ pub fn apply_with_bindings<I>(&mut self, effect: Effect, bs: I)
+ where I: IntoIterator<Item=(&'static str, Uniform)> {
+ let mut bindings: [_; _] = Default::default();
+ for (si, b) in bs.into_iter().enumerate() {
+ if si < NUM_BINDINGS {
+ bindings[si] = Some(b);
+ } else {
+ log::warn!("too many bindings on postprocessing effect!");
+ break;
+ }
+ }
+ self.stages.push(Stage { effect, bindings });
}
/// Upscale the image in the state's rendering framebuffer to the screen,
/// applying postprocessing effects in between.
pub fn render(&self, ctx: &context::Context, st: &state::State) -> utils::Erm<()> {
let mut src = &st.render_framebuffer;
let mut dst = &self.framebuffer;
- for Effect(e) in self.stages.iter() {
+ for Stage { effect: Effect(e), bindings } in self.stages.iter() {
let s = &self.effects[*e];
dst.bind(ctx);
ctx.clear();
s.bind(ctx);
s.set_f32(ctx, "time", st.tick as f32 + (st.tick % 60) as f32 / 60.0);
+ for (nm, val) in bindings.iter().flatten(){
+ match val {
+ Uniform::I32(x) => s.set_i32(ctx, nm, *x),
+ Uniform::F32(x) => s.set_f32(ctx, nm, *x),
+ Uniform::Vec2(x) => s.set_vec2(ctx, nm, x),
+ Uniform::Vec3(x) => s.set_vec3(ctx, nm, x),
+ Uniform::Vec4(x) => s.set_vec4(ctx, nm, x),
+ Uniform::Mat4(x) => s.set_mat4(ctx, nm, x),
+ }
+ }
src.bind_texture(ctx);
ctx.render_no_geometry();
std::mem::swap(&mut src, &mut dst);
diff --git a/crates/teleia/src/renderer.rs b/crates/teleia/src/renderer.rs
index faad4f7..4864cc5 100644
--- a/crates/teleia/src/renderer.rs
+++ b/crates/teleia/src/renderer.rs
@@ -5,17 +5,18 @@ use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct UberFlags: u32 {
- const TEXTURE_COLOR = 0b00000000001;
- const TEXTURE_NORMAL = 0b00000000010;
- const FLIP_TEXTURE = 0b00000000100;
- const LIGHT_AMBIENT = 0b00000001000;
- const LIGHT_DIR = 0b00000010000;
- const LIGHT_POINT = 0b00000100000;
- const SPRITE = 0b00001000000;
- const EFFECTS = 0b00010000000;
- const YSKEW = 0b00100000000;
- const VERTEX_COLOR = 0b01000000000;
- const OPACITY = 0b10000000000;
+ const VERTEX_COLOR = 1 << 0;
+ const TEXTURE_COLOR = 1 << 1;
+ const TEXTURE_NORMAL = 1 << 2;
+ const TEXTURE_FLIP = 1 << 3;
+ const LIGHT_AMBIENT = 1 << 4;
+ const LIGHT_DIR = 1 << 5;
+ const LIGHT_POINT = 1 << 6;
+ const HUE = 1 << 7;
+ const SPRITE = 1 << 8;
+ const FLASH = 1 << 9;
+ const YSKEW = 1 << 10;
+ const OPACITY = 1 << 11;
}
}
impl UberFlags {
@@ -268,9 +269,10 @@ impl<A: Assets> Renderer<A> {
pos: glam::Vec2,
dims: glam::Vec2,
) {
- self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR);
+ self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::TEXTURE_FLIP);
self.bind_texture(ctx, st, texture);
self.set_position_2d(ctx, st, pos, dims);
+ self.set_vec2(ctx, st, "texture_flip", glam::Vec2::new(0.0, 1.0));
self.render_square(ctx, st);
}
@@ -281,9 +283,10 @@ impl<A: Assets> Renderer<A> {
dims: glam::Vec2,
rot: glam::Quat,
) {
- self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR);
+ self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::TEXTURE_FLIP);
self.bind_texture(ctx, st, texture);
self.set_position_2d_rotate(ctx, st, pos, dims, rot);
+ self.set_vec2(ctx, st, "texture_flip", glam::Vec2::new(0.0, 1.0));
self.render_square(ctx, st);
}
@@ -293,14 +296,13 @@ impl<A: Assets> Renderer<A> {
pos: glam::Vec2,
dims: glam::Vec2,
) {
- self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::EFFECTS);
+ self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::TEXTURE_FLIP | UberFlags::HUE);
self.bind_texture(ctx, st, texture);
- self.set_f32(ctx, st, "effect_huescale", 0.0);
- self.set_f32(ctx, st, "effect_hueshift", hue);
+ self.set_vec2(ctx, st, "texture_flip", glam::Vec2::new(0.0, 1.0));
+ self.set_f32(ctx, st, "hue_scale", 0.0);
+ self.set_f32(ctx, st, "hue_shift", hue);
self.set_position_2d(ctx, st, pos, dims);
self.render_square(ctx, st);
- self.set_f32(ctx, st, "effect_huescale", 1.0);
- self.set_f32(ctx, st, "effect_hueshift", 0.0);
}
/// Common case: text in the default font (units are pixels, pos is top left)
@@ -311,7 +313,7 @@ impl<A: Assets> Renderer<A> {
) {
// drawing text might bind the texture
self.texture = BoundTexture::None;
- self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR | UberFlags::FLIP_TEXTURE);
+ self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR);
let dims = glam::Vec2::new(st.font_default.char_width as f32, st.font_default.char_height as f32);
let fpos = pos + glam::Vec2::new(-dims.x / 2.0, dims.y / 2.0);
self.set_position_2d(ctx, st, fpos, dims);
@@ -326,7 +328,7 @@ impl<A: Assets> Renderer<A> {
s: &str,
) {
self.texture = BoundTexture::None;
- self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR | UberFlags::FLIP_TEXTURE);
+ self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR);
let dims = glam::Vec2::new(st.font_default.char_width as f32, st.font_default.char_height as f32);
let fpos = pos + glam::Vec2::new(-dims.x / 2.0, st.font_default.char_height as f32 / 2.0);
self.set_position_2d(ctx, st, fpos, dims);
@@ -340,7 +342,7 @@ impl<A: Assets> Renderer<A> {
s: &str,
) {
self.texture = BoundTexture::None;
- self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR | UberFlags::FLIP_TEXTURE);
+ self.bind_uber_2d(ctx, st, UberFlags::TEXTURE_COLOR | UberFlags::VERTEX_COLOR);
let width = s.len() as f32 * st.font_default.char_width as f32;
let dims = glam::Vec2::new(st.font_default.char_width as f32, st.font_default.char_height as f32);
let fpos = pos + glam::Vec2::new(-dims.x / 2.0 - (width / 2.0).round(), st.font_default.char_height as f32 / 2.0);