diff --git a/src/app.rs b/src/app.rs index 1478daa..b59a3b2 100644 --- a/src/app.rs +++ b/src/app.rs @@ -4,6 +4,7 @@ use std::sync::Arc; mod waterfall; use waterfall::Waterfall; +pub mod turbo_colormap; /// We derive Deserialize/Serialize so we can persist app state on shutdown. pub struct TemplateApp { diff --git a/src/app/turbo_colormap.rs b/src/app/turbo_colormap.rs new file mode 100644 index 0000000..574de9d --- /dev/null +++ b/src/app/turbo_colormap.rs @@ -0,0 +1,46 @@ +// Copyright 2019 Google LLC. +// SPDX-License-Identifier: Apache-2.0 + +// Author: Anton Mikhailov + +// The look-up tables contains 256 entries. Each entry is a an sRGB triplet. + +pub const TURBO_SRGB_BYTES: [u8; 256 * 3] = [ + 48, 18, 59, 50, 21, 67, 51, 24, 74, 52, 27, 81, 53, 30, 88, 54, 33, 95, 55, 36, 102, 56, 39, + 109, 57, 42, 115, 58, 45, 121, 59, 47, 128, 60, 50, 134, 61, 53, 139, 62, 56, 145, 63, 59, 151, + 63, 62, 156, 64, 64, 162, 65, 67, 167, 65, 70, 172, 66, 73, 177, 66, 75, 181, 67, 78, 186, 68, + 81, 191, 68, 84, 195, 68, 86, 199, 69, 89, 203, 69, 92, 207, 69, 94, 211, 70, 97, 214, 70, 100, + 218, 70, 102, 221, 70, 105, 224, 70, 107, 227, 71, 110, 230, 71, 113, 233, 71, 115, 235, 71, + 118, 238, 71, 120, 240, 71, 123, 242, 70, 125, 244, 70, 128, 246, 70, 130, 248, 70, 133, 250, + 70, 135, 251, 69, 138, 252, 69, 140, 253, 68, 143, 254, 67, 145, 254, 66, 148, 255, 65, 150, + 255, 64, 153, 255, 62, 155, 254, 61, 158, 254, 59, 160, 253, 58, 163, 252, 56, 165, 251, 55, + 168, 250, 53, 171, 248, 51, 173, 247, 49, 175, 245, 47, 178, 244, 46, 180, 242, 44, 183, 240, + 42, 185, 238, 40, 188, 235, 39, 190, 233, 37, 192, 231, 35, 195, 228, 34, 197, 226, 32, 199, + 223, 31, 201, 221, 30, 203, 218, 28, 205, 216, 27, 208, 213, 26, 210, 210, 26, 212, 208, 25, + 213, 205, 24, 215, 202, 24, 217, 200, 24, 219, 197, 24, 221, 194, 24, 222, 192, 24, 224, 189, + 25, 226, 187, 25, 227, 185, 26, 228, 182, 28, 230, 180, 29, 231, 178, 31, 233, 175, 32, 234, + 172, 34, 235, 170, 37, 236, 167, 39, 238, 164, 42, 239, 161, 44, 240, 158, 47, 241, 155, 50, + 242, 152, 53, 243, 148, 56, 244, 145, 60, 245, 142, 63, 246, 138, 67, 247, 135, 70, 248, 132, + 74, 248, 128, 78, 249, 125, 82, 250, 122, 85, 250, 118, 89, 251, 115, 93, 252, 111, 97, 252, + 108, 101, 253, 105, 105, 253, 102, 109, 254, 98, 113, 254, 95, 117, 254, 92, 121, 254, 89, 125, + 255, 86, 128, 255, 83, 132, 255, 81, 136, 255, 78, 139, 255, 75, 143, 255, 73, 146, 255, 71, + 150, 254, 68, 153, 254, 66, 156, 254, 64, 159, 253, 63, 161, 253, 61, 164, 252, 60, 167, 252, + 58, 169, 251, 57, 172, 251, 56, 175, 250, 55, 177, 249, 54, 180, 248, 54, 183, 247, 53, 185, + 246, 53, 188, 245, 52, 190, 244, 52, 193, 243, 52, 195, 241, 52, 198, 240, 52, 200, 239, 52, + 203, 237, 52, 205, 236, 52, 208, 234, 52, 210, 233, 53, 212, 231, 53, 215, 229, 53, 217, 228, + 54, 219, 226, 54, 221, 224, 55, 223, 223, 55, 225, 221, 55, 227, 219, 56, 229, 217, 56, 231, + 215, 57, 233, 213, 57, 235, 211, 57, 236, 209, 58, 238, 207, 58, 239, 205, 58, 241, 203, 58, + 242, 201, 58, 244, 199, 58, 245, 197, 58, 246, 195, 58, 247, 193, 58, 248, 190, 57, 249, 188, + 57, 250, 186, 57, 251, 184, 56, 251, 182, 55, 252, 179, 54, 252, 177, 54, 253, 174, 53, 253, + 172, 52, 254, 169, 51, 254, 167, 50, 254, 164, 49, 254, 161, 48, 254, 158, 47, 254, 155, 45, + 254, 153, 44, 254, 150, 43, 254, 147, 42, 254, 144, 41, 253, 141, 39, 253, 138, 38, 252, 135, + 37, 252, 132, 35, 251, 129, 34, 251, 126, 33, 250, 123, 31, 249, 120, 30, 249, 117, 29, 248, + 114, 28, 247, 111, 26, 246, 108, 25, 245, 105, 24, 244, 102, 23, 243, 99, 21, 242, 96, 20, 241, + 93, 19, 240, 91, 18, 239, 88, 17, 237, 85, 16, 236, 83, 15, 235, 80, 14, 234, 78, 13, 232, 75, + 12, 231, 73, 12, 229, 71, 11, 228, 69, 10, 226, 67, 10, 225, 65, 9, 223, 63, 8, 221, 61, 8, + 220, 59, 7, 218, 57, 7, 216, 55, 6, 214, 53, 6, 212, 51, 5, 210, 49, 5, 208, 47, 5, 206, 45, 4, + 204, 43, 4, 202, 42, 4, 200, 40, 3, 197, 38, 3, 195, 37, 3, 193, 35, 2, 190, 33, 2, 188, 32, 2, + 185, 30, 2, 183, 29, 2, 180, 27, 1, 178, 26, 1, 175, 24, 1, 172, 23, 1, 169, 22, 1, 167, 20, 1, + 164, 19, 1, 161, 18, 1, 158, 16, 1, 155, 15, 1, 152, 14, 1, 149, 13, 1, 146, 11, 1, 142, 10, 1, + 139, 9, 2, 136, 8, 2, 133, 7, 2, 129, 6, 2, 126, 5, 2, 122, 4, 3, +]; diff --git a/src/app/waterfall.rs b/src/app/waterfall.rs index 257fa99..ce8380d 100644 --- a/src/app/waterfall.rs +++ b/src/app/waterfall.rs @@ -1,5 +1,6 @@ -use eframe::glow::{self, PixelUnpackData}; +use eframe::glow::{self, PixelUnpackData, TEXTURE0, TEXTURE1, UNSIGNED_BYTE}; use glow::HasContext as _; +use glow::{NEAREST, TEXTURE_1D, TEXTURE_2D, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER}; use log; use std::mem::{size_of, transmute}; @@ -27,9 +28,12 @@ mod deadbeef_rand { } use deadbeef_rand::rand; +use crate::app::turbo_colormap; + pub struct Waterfall { program: glow::Program, texture: glow::Texture, + color_lut: glow::Texture, vao: glow::VertexArray, vbo: glow::Buffer, ebo: glow::Buffer, @@ -56,14 +60,24 @@ impl Waterfall { } unsafe { - // Bind our texture + // Bind our texturs + gl.active_texture(TEXTURE1); + check_for_gl_errors(&gl, "Active texture 1"); + gl.bind_texture(glow::TEXTURE_1D, Some(self.color_lut)); + check_for_gl_errors(&gl, "bind lut"); + + gl.active_texture(TEXTURE0); + check_for_gl_errors(&gl, "Active texture 0"); gl.bind_texture(glow::TEXTURE_2D, Some(self.texture)); + check_for_gl_errors(&gl, "bind texture"); // Use our shader program gl.use_program(Some(self.program)); + check_for_gl_errors(&gl, "use program"); // Bind our vertex array object gl.bind_vertex_array(Some(self.vao)); + check_for_gl_errors(&gl, "bind vao"); // Update texture gl.tex_sub_image_2d( @@ -77,11 +91,13 @@ impl Waterfall { glow::UNSIGNED_BYTE, PixelUnpackData::Slice(&new_data), ); + check_for_gl_errors(&gl, "update texture"); self.offset = (self.offset + 1) % 300; if let Some(uniform) = gl.get_uniform_location(self.program, "offset") { gl.uniform_1_f32(Some(&uniform), self.offset as f32 / 300.0); } + check_for_gl_errors(&gl, "update uniform"); // Draw the elements gl.draw_elements(glow::TRIANGLES, 6, glow::UNSIGNED_INT, 0); @@ -171,16 +187,8 @@ impl Waterfall { gl.bind_texture(glow::TEXTURE_2D, Some(texture)); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MIN_FILTER, - glow::NEAREST as i32, - ); - gl.tex_parameter_i32( - glow::TEXTURE_2D, - glow::TEXTURE_MAG_FILTER, - glow::NEAREST as i32, - ); + gl.tex_parameter_i32(TEXTURE_2D, TEXTURE_MIN_FILTER, NEAREST as i32); + gl.tex_parameter_i32(TEXTURE_2D, TEXTURE_MAG_FILTER, NEAREST as i32); check_for_gl_errors(&gl, "Set texture params"); //gl.tex_storage_2d(glow::TEXTURE_2D, 1, glow::R8, 300, 300); @@ -197,6 +205,25 @@ impl Waterfall { ); check_for_gl_errors(&gl, "Initializing Texture"); + let color_lut = gl + .create_texture() + .expect("Waterfall: could not create LUT"); + gl.bind_texture(TEXTURE_1D, Some(color_lut)); + gl.tex_parameter_i32(TEXTURE_1D, TEXTURE_MIN_FILTER, NEAREST as i32); + gl.tex_parameter_i32(TEXTURE_1D, TEXTURE_MAG_FILTER, NEAREST as i32); + check_for_gl_errors(&gl, "Set LUT params"); + gl.tex_image_1d( + TEXTURE_1D, + 0, + glow::SRGB as i32, + 256, + 0, + glow::RGB, + UNSIGNED_BYTE, + Some(&turbo_colormap::TURBO_SRGB_BYTES), + ); + check_for_gl_errors(&gl, "Initializing LUT"); + let program = gl.create_program().expect("Cannot create program"); let (vertex_shader_source, fragment_shader_source) = ( @@ -223,11 +250,13 @@ impl Waterfall { // texture sampler uniform sampler2D texture1; + uniform sampler1D LUT; uniform float offset; void main() { - FragColor = texture(texture1, vec2(TexCoord.x, TexCoord.y + offset)); + float val = texture(texture1, vec2(TexCoord.x, TexCoord.y + offset)).x; + FragColor = texture(LUT, val); } "#, ); @@ -268,11 +297,16 @@ impl Waterfall { gl.detach_shader(program, shader); gl.delete_shader(shader); } + + gl.use_program(Some(program)); + gl.uniform_1_i32(gl.get_uniform_location(program, "texture1").as_ref(), 0); + gl.uniform_1_i32(gl.get_uniform_location(program, "LUT").as_ref(), 1); check_for_gl_errors(&gl, "APP INIT"); Self { program, texture, + color_lut, vao, vbo, ebo,