From e2161108648ecec34453c7a3a46e49300b2062ec Mon Sep 17 00:00:00 2001 From: Alula <6276139+alula@users.noreply.github.com> Date: Sun, 27 Feb 2022 03:43:14 +0100 Subject: [PATCH] water improvements --- src/components/water_renderer.rs | 112 ++++--- src/framework/backend.rs | 2 + src/framework/backend_sdl2.rs | 3 + src/framework/graphics.rs | 1 + src/framework/render_opengl.rs | 556 ++++++++++++++++--------------- src/map.rs | 35 +- src/scene/game_scene.rs | 3 +- 7 files changed, 388 insertions(+), 324 deletions(-) diff --git a/src/components/water_renderer.rs b/src/components/water_renderer.rs index 22769f3..806936d 100644 --- a/src/components/water_renderer.rs +++ b/src/components/water_renderer.rs @@ -1,15 +1,18 @@ +use std::cell::RefCell; + use crate::common::{Color, Rect}; use crate::entity::GameEntity; use crate::frame::Frame; -use crate::framework::backend::{BackendShader, VertexData}; +use crate::framework::backend::{BackendShader, SpriteBatchCommand, VertexData}; use crate::framework::context::Context; use crate::framework::error::GameResult; use crate::framework::graphics; -use crate::map::WaterRegionType; +use crate::graphics::BlendMode; +use crate::map::{WaterParamEntry, WaterParams, WaterRegionType}; +use crate::npc::list::NPCList; +use crate::physics::PhysicalEntity; use crate::player::Player; use crate::shared_game_state::SharedGameState; -use crate::physics::PhysicalEntity; -use crate::npc::list::NPCList; const TENSION: f32 = 0.03; const DAMPENING: f32 = 0.01; @@ -37,10 +40,11 @@ pub struct DynamicWater { y: u16, end_x: u16, columns: Vec, + color: WaterParamEntry, } impl DynamicWater { - pub fn new(x: u16, y: u16, length: u16) -> DynamicWater { + pub fn new(x: u16, y: u16, length: u16, color: WaterParamEntry) -> DynamicWater { let mut columns = Vec::new(); let count = length as usize * 8 + 1; @@ -48,7 +52,7 @@ impl DynamicWater { columns.push(DynamicWaterColumn::new()); } - DynamicWater { x, y, end_x: x + length, columns } + DynamicWater { x, y, end_x: x + length, columns, color } } pub fn tick(&mut self) { @@ -92,25 +96,26 @@ impl DynamicWater { } pub struct WaterRenderer { - depth_regions: Vec>, - surf_regions: Vec>, + depth_regions: Vec<(Rect, WaterParamEntry)>, water_surfaces: Vec, + t: RefCell, } impl WaterRenderer { pub fn new() -> WaterRenderer { - WaterRenderer { depth_regions: Vec::new(), surf_regions: Vec::new(), water_surfaces: Vec::new() } + WaterRenderer { depth_regions: Vec::new(), water_surfaces: Vec::new(), t: RefCell::new(0.0) } } - pub fn initialize(&mut self, regions: Vec<(WaterRegionType, Rect)>) { - for (reg_type, bounds) in regions { + pub fn initialize(&mut self, regions: Vec<(WaterRegionType, Rect, u8)>, water_params: &WaterParams) { + for (reg_type, bounds, color_idx) in regions { + let color = water_params.get_entry(color_idx); + match reg_type { WaterRegionType::WaterLine => { - self.surf_regions.push(bounds); - self.water_surfaces.push(DynamicWater::new(bounds.left, bounds.top, bounds.width() + 1)); + self.water_surfaces.push(DynamicWater::new(bounds.left, bounds.top, bounds.width() + 1, *color)); } WaterRegionType::WaterDepth => { - self.depth_regions.push(bounds); + self.depth_regions.push((bounds, *color)); } } } @@ -119,10 +124,6 @@ impl WaterRenderer { impl GameEntity<(&[&Player], &NPCList)> for WaterRenderer { fn tick(&mut self, state: &mut SharedGameState, (players, npc_list): (&[&Player], &NPCList)) -> GameResult<()> { - if !state.settings.shader_effects { - return Ok(()); - } - for surf in &mut self.water_surfaces { let line_x = surf.x as f32 * 16.0; let line_y = surf.y as f32 * 16.0; @@ -169,39 +170,48 @@ impl GameEntity<(&[&Player], &NPCList)> for WaterRenderer { } fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, frame: &Frame) -> GameResult<()> { - let mut out_rect = Rect::new(0, 0, 0, 0); - let (o_x, o_y) = frame.xy_interpolated(state.frame_time); - let water_color_top = Color::from_rgba(102, 153, 204, 150); - let water_color = Color::from_rgba(102, 153, 204, 75); - - for region in &self.depth_regions { - out_rect.left = ((region.left as f32 * 16.0 - o_x - 8.0) * state.scale) as isize; - out_rect.top = ((region.top as f32 * 16.0 - o_y - 8.0) * state.scale) as isize; - out_rect.right = ((region.right as f32 * 16.0 - o_x + 8.0) * state.scale) as isize; - out_rect.bottom = ((region.bottom as f32 * 16.0 - o_y + 8.0) * state.scale) as isize; - graphics::draw_rect(ctx, out_rect, water_color)?; - } - - if !state.settings.shader_effects || !graphics::supports_vertex_draw(ctx)? { - for region in &self.surf_regions { - out_rect.left = ((region.left as f32 * 16.0 - o_x - 8.0) * state.scale) as isize; - out_rect.top = ((region.top as f32 * 16.0 - o_y - 5.0) * state.scale) as isize; - out_rect.right = ((region.right as f32 * 16.0 - o_x + 8.0) * state.scale) as isize; - out_rect.bottom = ((region.bottom as f32 * 16.0 - o_y + 8.0) * state.scale) as isize; - graphics::draw_rect(ctx, out_rect, water_color)?; - } - + if !graphics::supports_vertex_draw(ctx)? { return Ok(()); } - let uv = (0.0, 0.0); - let color_top_rgba = water_color_top.to_rgba(); - let color_mid_rgba = water_color.to_rgba(); - let color_btm_rgba = water_color.to_rgba(); + graphics::set_render_target(ctx, state.lightmap_canvas.as_ref())?; + graphics::clear(ctx, Color::from_rgba(0, 0, 0, 0)); + graphics::set_blend_mode(ctx, BlendMode::None)?; + + let (o_x, o_y) = frame.xy_interpolated(state.frame_time); + let uv = (0.5, 0.5); + let mut t_ref = self.t.borrow_mut(); + let t = *t_ref; + *t_ref += state.frame_time as f32; + let shader = BackendShader::WaterFill(state.scale, t, (o_x, o_y)); + + for (region, color) in &self.depth_regions { + let color_mid_rgba = color.color_middle.to_rgba(); + let color_btm_rgba = color.color_bottom.to_rgba(); + let mut vertices = vec![]; + vertices.reserve(6); + + let left = (region.left as f32 * 16.0 - o_x - 8.0) * state.scale; + let top = (region.top as f32 * 16.0 - o_y - 8.0) * state.scale; + let right = (region.right as f32 * 16.0 - o_x + 8.0) * state.scale; + let bottom = (region.bottom as f32 * 16.0 - o_y + 8.0) * state.scale; + + vertices.push(VertexData { position: (left, bottom), uv, color: color_btm_rgba }); + vertices.push(VertexData { position: (left, top), uv, color: color_mid_rgba }); + vertices.push(VertexData { position: (right, top), uv, color: color_mid_rgba }); + vertices.push(VertexData { position: (left, bottom), uv, color: color_btm_rgba }); + vertices.push(VertexData { position: (right, top), uv, color: color_mid_rgba }); + vertices.push(VertexData { position: (right, bottom), uv, color: color_btm_rgba }); + + graphics::draw_triangle_list(ctx, vertices, None, shader)?; + } for surf in &self.water_surfaces { let pos_x = surf.x as f32 * 16.0; let pos_y = surf.y as f32 * 16.0; + let color_top_rgba = surf.color.color_top.to_rgba(); + let color_mid_rgba = surf.color.color_middle.to_rgba(); + let color_btm_rgba = surf.color.color_bottom.to_rgba(); if (pos_x - o_x - 16.0) > state.canvas_size.0 || (pos_x - o_x + 16.0 + surf.end_x as f32 * 16.0) < 0.0 @@ -238,7 +248,19 @@ impl GameEntity<(&[&Player], &NPCList)> for WaterRenderer { vertices.push(VertexData { position: (x_right, bottom), uv, color: color_btm_rgba }); } - graphics::draw_triangle_list(ctx, vertices, None, BackendShader::Fill)?; + graphics::draw_triangle_list(ctx, vertices, None, shader)?; + } + + graphics::set_blend_mode(ctx, BlendMode::Alpha)?; + graphics::set_render_target(ctx, None)?; + + { + let canvas = state.lightmap_canvas.as_mut().unwrap(); + let rect = Rect { left: 0.0, top: 0.0, right: state.screen_size.0, bottom: state.screen_size.1 }; + + canvas.clear(); + canvas.add(SpriteBatchCommand::DrawRect(rect, rect)); + canvas.draw()?; } Ok(()) diff --git a/src/framework/backend.rs b/src/framework/backend.rs index ecd8b6e..cee4c20 100644 --- a/src/framework/backend.rs +++ b/src/framework/backend.rs @@ -17,6 +17,8 @@ pub struct VertexData { #[derive(Copy, Clone, PartialEq)] pub enum BackendShader { + /// (scale, t, (frame_x, frame_y)) + WaterFill(f32, f32, (f32, f32)), Fill, Texture, } diff --git a/src/framework/backend_sdl2.rs b/src/framework/backend_sdl2.rs index 40fcfe7..d1695d1 100644 --- a/src/framework/backend_sdl2.rs +++ b/src/framework/backend_sdl2.rs @@ -538,6 +538,7 @@ impl BackendRenderer for SDL2Renderer { BlendMode::Add => sdl2::render::BlendMode::Add, BlendMode::Alpha => sdl2::render::BlendMode::Blend, BlendMode::Multiply => sdl2::render::BlendMode::Mod, + BlendMode::None => sdl2::render::BlendMode::None, }; Ok(()) @@ -738,6 +739,8 @@ impl BackendRenderer for SDL2Renderer { let mut refs = self.refs.borrow_mut(); if shader == BackendShader::Fill { texture = None; + } else if let BackendShader::WaterFill(..) = shader { + texture = None; } let texture_ptr = if let Some(texture) = texture { diff --git a/src/framework/graphics.rs b/src/framework/graphics.rs index d0e24a4..b9a60e0 100644 --- a/src/framework/graphics.rs +++ b/src/framework/graphics.rs @@ -10,6 +10,7 @@ pub enum FilterMode { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum BlendMode { + None, /// When combining two fragments, add their values together, saturating /// at 1.0 Add, diff --git a/src/framework/render_opengl.rs b/src/framework/render_opengl.rs index 24e41df..ee91ea3 100644 --- a/src/framework/render_opengl.rs +++ b/src/framework/render_opengl.rs @@ -16,6 +16,7 @@ use crate::framework::gl; use crate::framework::gl::types::*; use crate::framework::graphics::BlendMode; use crate::framework::util::{field_offset, return_param}; +use crate::GameError; pub struct GLContext { pub gles2_mode: bool, @@ -29,8 +30,7 @@ pub struct OpenGLTexture { height: u16, texture_id: u32, framebuffer_id: u32, - locs: Locs, - program: GLuint, + shader: RenderShader, vbo: GLuint, vertices: Vec, context_active: Arc>, @@ -181,41 +181,9 @@ impl BackendTexture for OpenGLTexture { gl.gl.Enable(gl::BLEND); gl.gl.Disable(gl::DEPTH_TEST); + self.shader.bind_attrib_pointer(gl, self.vbo); + gl.gl.BindTexture(gl::TEXTURE_2D, self.texture_id); - gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.vbo); - gl.gl.UseProgram(self.program); - gl.gl.EnableVertexAttribArray(self.locs.position); - gl.gl.EnableVertexAttribArray(self.locs.uv); - gl.gl.EnableVertexAttribArray(self.locs.color); - - gl.gl.VertexAttribPointer( - self.locs.position, - 2, - gl::FLOAT, - gl::FALSE, - mem::size_of::() as _, - field_offset::(|v| &v.position) as _, - ); - - gl.gl.VertexAttribPointer( - self.locs.uv, - 2, - gl::FLOAT, - gl::FALSE, - mem::size_of::() as _, - field_offset::(|v| &v.uv) as _, - ); - - gl.gl.VertexAttribPointer( - self.locs.color, - 4, - gl::UNSIGNED_BYTE, - gl::TRUE, - mem::size_of::() as _, - field_offset::(|v| &v.color) as _, - ); - - gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.vbo); gl.gl.BufferData( gl::ARRAY_BUFFER, (self.vertices.len() * mem::size_of::()) as _, @@ -257,7 +225,7 @@ impl Drop for OpenGLTexture { } } -fn check_shader_compile_status(shader: u32, gl: &Gl) -> bool { +fn check_shader_compile_status(shader: u32, gl: &Gl) -> GameResult { unsafe { let mut status: GLint = 0; gl.gl.GetShaderiv(shader, gl::COMPILE_STATUS, (&mut status) as *mut _); @@ -276,13 +244,11 @@ fn check_shader_compile_status(shader: u32, gl: &Gl) -> bool { ); let data = String::from_utf8_lossy(&data); - log::error!("Failed to compile shader {}: {}", shader, data); - - return false; + return Err(GameError::RenderError(format!("Failed to compile shader {}: {}", shader, data))); } } - true + Ok(()) } const VERTEX_SHADER_BASIC: &str = r" @@ -331,6 +297,51 @@ void main() "; +const FRAGMENT_SHADER_WATER: &str = r" +#version 110 + +uniform mat4 ProjMtx; +uniform sampler2D Texture; +uniform float Time; +uniform float Scale; +uniform vec2 FrameOffset; +varying vec4 Frag_Color; + +void main() +{ + vec2 resolution_inv = vec2(ProjMtx[0][0], -ProjMtx[1][1]) * 0.5; + vec2 uv = gl_FragCoord.xy * resolution_inv; + vec2 wave = uv; + wave.x += sin((-FrameOffset.y * resolution_inv.y + uv.x * 16.0) + Time / 20.0) * Scale * resolution_inv.x; + wave.y -= cos((-FrameOffset.x * resolution_inv.x + uv.y * 16.0) + Time / 5.0) * Scale * resolution_inv.y; + float off = 0.35 * Scale * resolution_inv.y; + float off2 = 2.0 * off; + + vec3 color = texture2D(Texture, wave).rgb * 0.25; + color += texture2D(Texture, wave + vec2(0, off)).rgb * 0.125; + color += texture2D(Texture, wave + vec2(0, -off)).rgb * 0.125; + + color.rg += texture2D(Texture, wave + vec2(-off, -off)).rg * 0.0625; + color.rg += texture2D(Texture, wave + vec2(-off, 0)).rg * 0.125; + color.rg += texture2D(Texture, wave + vec2(-off, off)).rg * 0.0625; + color.b += texture2D(Texture, wave + vec2(-off2, -off)).b * 0.0625; + color.b += texture2D(Texture, wave + vec2(-off2, 0)).b * 0.125; + color.b += texture2D(Texture, wave + vec2(-off2, off)).b * 0.0625; + + color.rg += texture2D(Texture, wave + vec2(off, off)).gb * 0.0625; + color.rg += texture2D(Texture, wave + vec2(off, 0)).gb * 0.125; + color.rg += texture2D(Texture, wave + vec2(off, -off)).gb * 0.0625; + color.b += texture2D(Texture, wave + vec2(off2, off)).r * 0.0625; + color.b += texture2D(Texture, wave + vec2(off2, 0)).r * 0.125; + color.b += texture2D(Texture, wave + vec2(off2, -off)).r * 0.0625; + + color *= (1.0 - Frag_Color.a); + color += Frag_Color.rgb * Frag_Color.a; + gl_FragColor = vec4(color, 1.0); +} + +"; + const VERTEX_SHADER_BASIC_GLES: &str = r" #version 100 @@ -384,20 +395,131 @@ void main() "; #[derive(Copy, Clone)] -struct Locs { +struct RenderShader { + program_id: GLuint, texture: GLint, proj_mtx: GLint, + scale: GLint, + time: GLint, + frame_offset: GLint, position: GLuint, uv: GLuint, color: GLuint, } -struct ImguiData { +impl Default for RenderShader { + fn default() -> Self { + Self { program_id: 0, texture: 0, proj_mtx: 0, scale: 0, time: 0, frame_offset: 0, position: 0, uv: 0, color: 0 } + } +} + +impl RenderShader { + fn compile(gl: &Gl, vertex_shader: &str, fragment_shader: &str) -> GameResult { + let mut shader = RenderShader::default(); + unsafe { + shader.program_id = gl.gl.CreateProgram(); + + unsafe fn cleanup(shader: &mut RenderShader, gl: &Gl, vert: GLuint, frag: GLuint) { + if vert != 0 { + gl.gl.DeleteShader(vert); + } + + if frag != 0 { + gl.gl.DeleteShader(frag); + } + + if shader.program_id != 0 { + gl.gl.DeleteProgram(shader.program_id); + shader.program_id = 0; + } + + *shader = RenderShader::default(); + } + + let vert_shader = gl.gl.CreateShader(gl::VERTEX_SHADER); + let frag_shader = gl.gl.CreateShader(gl::FRAGMENT_SHADER); + + let vert_sources = [vertex_shader.as_ptr() as *const GLchar]; + let frag_sources = [fragment_shader.as_ptr() as *const GLchar]; + let vert_sources_len = [vertex_shader.len() as GLint - 1]; + let frag_sources_len = [fragment_shader.len() as GLint - 1]; + + gl.gl.ShaderSource(vert_shader, 1, vert_sources.as_ptr(), vert_sources_len.as_ptr()); + gl.gl.ShaderSource(frag_shader, 1, frag_sources.as_ptr(), frag_sources_len.as_ptr()); + + gl.gl.CompileShader(vert_shader); + gl.gl.CompileShader(frag_shader); + + if let Err(e) = check_shader_compile_status(vert_shader, gl) { + cleanup(&mut shader, gl, vert_shader, frag_shader); + return Err(e); + } + + if let Err(e) = check_shader_compile_status(frag_shader, gl) { + cleanup(&mut shader, gl, vert_shader, frag_shader); + return Err(e); + } + + gl.gl.AttachShader(shader.program_id, vert_shader); + gl.gl.AttachShader(shader.program_id, frag_shader); + gl.gl.LinkProgram(shader.program_id); + + shader.texture = gl.gl.GetUniformLocation(shader.program_id, b"Texture\0".as_ptr() as _); + shader.proj_mtx = gl.gl.GetUniformLocation(shader.program_id, b"ProjMtx\0".as_ptr() as _); + shader.scale = gl.gl.GetUniformLocation(shader.program_id, b"Scale\0".as_ptr() as _) as _; + shader.time = gl.gl.GetUniformLocation(shader.program_id, b"Time\0".as_ptr() as _) as _; + shader.frame_offset = gl.gl.GetUniformLocation(shader.program_id, b"FrameOffset\0".as_ptr() as _) as _; + shader.position = gl.gl.GetAttribLocation(shader.program_id, b"Position\0".as_ptr() as _) as _; + shader.uv = gl.gl.GetAttribLocation(shader.program_id, b"UV\0".as_ptr() as _) as _; + shader.color = gl.gl.GetAttribLocation(shader.program_id, b"Color\0".as_ptr() as _) as _; + } + + Ok(shader) + } + + unsafe fn bind_attrib_pointer(&self, gl: &Gl, vbo: GLuint) -> GameResult { + gl.gl.UseProgram(self.program_id); + gl.gl.BindBuffer(gl::ARRAY_BUFFER, vbo); + gl.gl.EnableVertexAttribArray(self.position); + gl.gl.EnableVertexAttribArray(self.uv); + gl.gl.EnableVertexAttribArray(self.color); + + gl.gl.VertexAttribPointer( + self.position, + 2, + gl::FLOAT, + gl::FALSE, + mem::size_of::() as _, + field_offset::(|v| &v.position) as _, + ); + + gl.gl.VertexAttribPointer( + self.uv, + 2, + gl::FLOAT, + gl::FALSE, + mem::size_of::() as _, + field_offset::(|v| &v.uv) as _, + ); + + gl.gl.VertexAttribPointer( + self.color, + 4, + gl::UNSIGNED_BYTE, + gl::TRUE, + mem::size_of::() as _, + field_offset::(|v| &v.color) as _, + ); + + Ok(()) + } +} + +struct RenderData { initialized: bool, - program_tex: GLuint, - program_fill: GLuint, - tex_locs: Locs, - fill_locs: Locs, + tex_shader: RenderShader, + fill_shader: RenderShader, + fill_water_shader: RenderShader, vbo: GLuint, ebo: GLuint, font_texture: GLuint, @@ -407,14 +529,13 @@ struct ImguiData { last_size: (u32, u32), } -impl ImguiData { +impl RenderData { fn new() -> Self { - ImguiData { + RenderData { initialized: false, - program_tex: 0, - program_fill: 0, - tex_locs: Locs { texture: 0, proj_mtx: 0, position: 0, uv: 0, color: 0 }, - fill_locs: Locs { texture: 0, proj_mtx: 0, position: 0, uv: 0, color: 0 }, + tex_shader: RenderShader::default(), + fill_shader: RenderShader::default(), + fill_water_shader: RenderShader::default(), vbo: 0, ebo: 0, font_texture: 0, @@ -431,76 +552,23 @@ impl ImguiData { let vshdr_basic = if gles2_mode { VERTEX_SHADER_BASIC_GLES } else { VERTEX_SHADER_BASIC }; let fshdr_tex = if gles2_mode { FRAGMENT_SHADER_TEXTURED_GLES } else { FRAGMENT_SHADER_TEXTURED }; let fshdr_fill = if gles2_mode { FRAGMENT_SHADER_COLOR_GLES } else { FRAGMENT_SHADER_COLOR }; - - let vert_sources = [vshdr_basic.as_ptr() as *const GLchar]; - let frag_sources_tex = [fshdr_tex.as_ptr() as *const GLchar]; - let frag_sources_fill = [fshdr_fill.as_ptr() as *const GLchar]; - let vert_sources_len = [vshdr_basic.len() as GLint - 1]; - let frag_sources_tex_len = [fshdr_tex.len() as GLint - 1]; - let frag_sources_fill_len = [fshdr_fill.len() as GLint - 1]; + let fshdr_fill_water = if gles2_mode { FRAGMENT_SHADER_COLOR_GLES } else { FRAGMENT_SHADER_WATER }; unsafe { - self.program_tex = gl.gl.CreateProgram(); - self.program_fill = gl.gl.CreateProgram(); - let vert_shader = gl.gl.CreateShader(gl::VERTEX_SHADER); - let frag_shader_tex = gl.gl.CreateShader(gl::FRAGMENT_SHADER); - let frag_shader_fill = gl.gl.CreateShader(gl::FRAGMENT_SHADER); - - gl.gl.ShaderSource(vert_shader, 1, vert_sources.as_ptr(), vert_sources_len.as_ptr()); - gl.gl.ShaderSource(frag_shader_tex, 1, frag_sources_tex.as_ptr(), frag_sources_tex_len.as_ptr()); - gl.gl.ShaderSource(frag_shader_fill, 1, frag_sources_fill.as_ptr(), frag_sources_fill_len.as_ptr()); - - gl.gl.CompileShader(vert_shader); - gl.gl.CompileShader(frag_shader_tex); - gl.gl.CompileShader(frag_shader_fill); - - if !check_shader_compile_status(vert_shader, gl) { - gl.gl.DeleteShader(vert_shader); - } - - if !check_shader_compile_status(frag_shader_tex, gl) { - gl.gl.DeleteShader(frag_shader_tex); - } - - if !check_shader_compile_status(frag_shader_fill, gl) { - gl.gl.DeleteShader(frag_shader_fill); - } - - gl.gl.AttachShader(self.program_tex, vert_shader); - gl.gl.AttachShader(self.program_tex, frag_shader_tex); - gl.gl.LinkProgram(self.program_tex); - - gl.gl.AttachShader(self.program_fill, vert_shader); - gl.gl.AttachShader(self.program_fill, frag_shader_fill); - gl.gl.LinkProgram(self.program_fill); - - self.tex_locs = Locs { - texture: gl.gl.GetUniformLocation(self.program_tex, b"Texture\0".as_ptr() as _), - proj_mtx: gl.gl.GetUniformLocation(self.program_tex, b"ProjMtx\0".as_ptr() as _), - position: gl.gl.GetAttribLocation(self.program_tex, b"Position\0".as_ptr() as _) as _, - uv: gl.gl.GetAttribLocation(self.program_tex, b"UV\0".as_ptr() as _) as _, - color: gl.gl.GetAttribLocation(self.program_tex, b"Color\0".as_ptr() as _) as _, - }; - - self.fill_locs = Locs { - texture: gl.gl.GetUniformLocation(self.program_fill, b"Texture\0".as_ptr() as _), - proj_mtx: gl.gl.GetUniformLocation(self.program_fill, b"ProjMtx\0".as_ptr() as _), - position: gl.gl.GetAttribLocation(self.program_fill, b"Position\0".as_ptr() as _) as _, - uv: gl.gl.GetAttribLocation(self.program_fill, b"UV\0".as_ptr() as _) as _, - color: gl.gl.GetAttribLocation(self.program_fill, b"Color\0".as_ptr() as _) as _, - }; + self.tex_shader = + RenderShader::compile(gl, vshdr_basic, fshdr_tex).unwrap_or_else(|_| RenderShader::default()); + self.fill_shader = + RenderShader::compile(gl, vshdr_basic, fshdr_fill).unwrap_or_else(|_| RenderShader::default()); + self.fill_water_shader = + RenderShader::compile(gl, vshdr_basic, fshdr_fill_water).unwrap_or_else(|_| RenderShader::default()); self.vbo = return_param(|x| gl.gl.GenBuffers(1, x)); self.ebo = return_param(|x| gl.gl.GenBuffers(1, x)); - let mut current_texture = 0; - gl.gl.GetIntegerv(gl::TEXTURE_BINDING_2D, &mut current_texture); - self.font_texture = return_param(|x| gl.gl.GenTextures(1, x)); gl.gl.BindTexture(gl::TEXTURE_2D, self.font_texture); gl.gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as _); gl.gl.TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as _); - //gl.gl.PixelStorei(gl::UNPACK_ROW_LENGTH, 0); { let mut atlas = imgui.fonts(); @@ -591,7 +659,7 @@ pub fn load_gl(gl_context: &mut GLContext) -> &'static Gl { pub struct OpenGLRenderer { refs: GLContext, imgui: UnsafeCell, - imgui_data: ImguiData, + render_data: RenderData, context_active: Arc>, def_matrix: [[f32; 4]; 4], curr_matrix: [[f32; 4]; 4], @@ -602,7 +670,7 @@ impl OpenGLRenderer { OpenGLRenderer { refs, imgui, - imgui_data: ImguiData::new(), + render_data: RenderData::new(), context_active: Arc::new(RefCell::new(true)), def_matrix: [[0.0; 4]; 4], curr_matrix: [[0.0; 4]; 4], @@ -615,8 +683,8 @@ impl OpenGLRenderer { let gles2 = self.refs.gles2_mode; let gl = load_gl(&mut self.refs); - if !self.imgui_data.initialized { - self.imgui_data.init(gles2, imgui, gl); + if !self.render_data.initialized { + self.render_data.init(gles2, imgui, gl); } Some((&mut self.refs, gl)) @@ -649,8 +717,6 @@ impl BackendRenderer for OpenGLRenderer { } } - let ImguiData { program_tex, surf_texture, tex_locs: Locs { proj_mtx, .. }, .. } = self.imgui_data; - unsafe { if let Some((_, gl)) = self.get_context() { gl.gl.BindFramebuffer(gl::FRAMEBUFFER, 0); @@ -660,8 +726,8 @@ impl BackendRenderer for OpenGLRenderer { let matrix = [[2.0f32, 0.0, 0.0, 0.0], [0.0, -2.0, 0.0, 0.0], [0.0, 0.0, -1.0, 0.0], [-1.0, 1.0, 0.0, 1.0]]; - gl.gl.UseProgram(program_tex); - gl.gl.UniformMatrix4fv(proj_mtx, 1, gl::FALSE, matrix.as_ptr() as _); + self.render_data.tex_shader.bind_attrib_pointer(gl, self.render_data.vbo); + gl.gl.UniformMatrix4fv(self.render_data.tex_shader.proj_mtx, 1, gl::FALSE, matrix.as_ptr() as _); let color = (255, 255, 255, 255); let vertices = vec![ @@ -673,7 +739,12 @@ impl BackendRenderer for OpenGLRenderer { VertexData { position: (1.0, 1.0), uv: (1.0, 0.0), color }, ]; - self.draw_arrays_tex_id(gl::TRIANGLES, vertices, surf_texture, BackendShader::Texture)?; + self.draw_arrays_tex_id( + gl::TRIANGLES, + vertices, + self.render_data.surf_texture, + BackendShader::Texture, + )?; gl.gl.Finish(); } @@ -690,10 +761,10 @@ impl BackendRenderer for OpenGLRenderer { if let Some((_, gl)) = self.get_context() { unsafe { let (width_u, height_u) = (width as u32, height as u32); - if self.imgui_data.last_size != (width_u, height_u) { - self.imgui_data.last_size = (width_u, height_u); + if self.render_data.last_size != (width_u, height_u) { + self.render_data.last_size = (width_u, height_u); gl.gl.BindFramebuffer(gl::FRAMEBUFFER, 0); - gl.gl.BindTexture(gl::TEXTURE_2D, self.imgui_data.surf_texture); + gl.gl.BindTexture(gl::TEXTURE_2D, self.render_data.surf_texture); gl.gl.TexImage2D( gl::TEXTURE_2D, @@ -710,7 +781,7 @@ impl BackendRenderer for OpenGLRenderer { gl.gl.BindTexture(gl::TEXTURE_2D, 0 as _); } - gl.gl.BindFramebuffer(gl::FRAMEBUFFER, self.imgui_data.surf_framebuffer); + gl.gl.BindFramebuffer(gl::FRAMEBUFFER, self.render_data.surf_framebuffer); gl.gl.ClearColor(0.0, 0.0, 0.0, 0.0); gl.gl.Clear(gl::COLOR_BUFFER_BIT); @@ -730,11 +801,29 @@ impl BackendRenderer for OpenGLRenderer { gl.gl.BindBuffer(gl::ARRAY_BUFFER, 0); gl.gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0); - gl.gl.UseProgram(self.imgui_data.program_fill); - gl.gl.UniformMatrix4fv(self.imgui_data.fill_locs.proj_mtx, 1, gl::FALSE, self.def_matrix.as_ptr() as _); - gl.gl.UseProgram(self.imgui_data.program_tex); - gl.gl.Uniform1i(self.imgui_data.tex_locs.texture, 0); - gl.gl.UniformMatrix4fv(self.imgui_data.tex_locs.proj_mtx, 1, gl::FALSE, self.def_matrix.as_ptr() as _); + gl.gl.UseProgram(self.render_data.fill_shader.program_id); + gl.gl.UniformMatrix4fv( + self.render_data.fill_shader.proj_mtx, + 1, + gl::FALSE, + self.curr_matrix.as_ptr() as _, + ); + gl.gl.UseProgram(self.render_data.fill_water_shader.program_id); + gl.gl.Uniform1i(self.render_data.fill_water_shader.texture, 0); + gl.gl.UniformMatrix4fv( + self.render_data.fill_water_shader.proj_mtx, + 1, + gl::FALSE, + self.curr_matrix.as_ptr() as _, + ); + gl.gl.UseProgram(self.render_data.tex_shader.program_id); + gl.gl.Uniform1i(self.render_data.tex_shader.texture, 0); + gl.gl.UniformMatrix4fv( + self.render_data.tex_shader.proj_mtx, + 1, + gl::FALSE, + self.curr_matrix.as_ptr() as _, + ); } Ok(()) @@ -787,9 +876,8 @@ impl BackendRenderer for OpenGLRenderer { width, height, vertices: Vec::new(), - locs: self.imgui_data.tex_locs, - program: self.imgui_data.program_tex, - vbo: self.imgui_data.vbo, + shader: self.render_data.tex_shader, + vbo: self.render_data.vbo, context_active: self.context_active.clone(), })) } @@ -827,9 +915,8 @@ impl BackendRenderer for OpenGLRenderer { width, height, vertices: Vec::new(), - locs: self.imgui_data.tex_locs, - program: self.imgui_data.program_tex, - vbo: self.imgui_data.vbo, + shader: self.render_data.tex_shader, + vbo: self.render_data.vbo, context_active: self.context_active.clone(), })) } @@ -842,17 +929,23 @@ impl BackendRenderer for OpenGLRenderer { if let Some((_, gl)) = self.get_context() { match blend { BlendMode::Add => unsafe { + gl.gl.Enable(gl::BLEND); gl.gl.BlendEquation(gl::FUNC_ADD); gl.gl.BlendFunc(gl::ONE, gl::ONE); }, BlendMode::Alpha => unsafe { + gl.gl.Enable(gl::BLEND); gl.gl.BlendEquation(gl::FUNC_ADD); gl.gl.BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); }, BlendMode::Multiply => unsafe { + gl.gl.Enable(gl::BLEND); gl.gl.BlendEquation(gl::FUNC_ADD); gl.gl.BlendFuncSeparate(gl::ZERO, gl::SRC_COLOR, gl::ZERO, gl::SRC_ALPHA); }, + BlendMode::None => unsafe { + gl.gl.Disable(gl::BLEND); + }, } Ok(()) @@ -877,17 +970,24 @@ impl BackendRenderer for OpenGLRenderer { [-1.0, -1.0, 0.0, 1.0], ]; - gl.gl.UseProgram(self.imgui_data.program_fill); + gl.gl.UseProgram(self.render_data.fill_shader.program_id); gl.gl.UniformMatrix4fv( - self.imgui_data.fill_locs.proj_mtx, + self.render_data.fill_shader.proj_mtx, 1, gl::FALSE, self.curr_matrix.as_ptr() as _, ); - gl.gl.UseProgram(self.imgui_data.program_tex); - gl.gl.Uniform1i(self.imgui_data.tex_locs.texture, 0); + gl.gl.UseProgram(self.render_data.fill_water_shader.program_id); gl.gl.UniformMatrix4fv( - self.imgui_data.tex_locs.proj_mtx, + self.render_data.fill_water_shader.proj_mtx, + 1, + gl::FALSE, + self.curr_matrix.as_ptr() as _, + ); + gl.gl.UseProgram(self.render_data.tex_shader.program_id); + gl.gl.Uniform1i(self.render_data.tex_shader.texture, 0); + gl.gl.UniformMatrix4fv( + self.render_data.tex_shader.proj_mtx, 1, gl::FALSE, self.curr_matrix.as_ptr() as _, @@ -898,23 +998,30 @@ impl BackendRenderer for OpenGLRenderer { } else { self.curr_matrix = self.def_matrix; - gl.gl.UseProgram(self.imgui_data.program_fill); + gl.gl.UseProgram(self.render_data.fill_shader.program_id); gl.gl.UniformMatrix4fv( - self.imgui_data.fill_locs.proj_mtx, + self.render_data.fill_shader.proj_mtx, 1, gl::FALSE, - self.def_matrix.as_ptr() as _, + self.curr_matrix.as_ptr() as _, ); - gl.gl.UseProgram(self.imgui_data.program_tex); - gl.gl.Uniform1i(self.imgui_data.tex_locs.texture, 0); + gl.gl.UseProgram(self.render_data.fill_water_shader.program_id); gl.gl.UniformMatrix4fv( - self.imgui_data.tex_locs.proj_mtx, + self.render_data.fill_water_shader.proj_mtx, 1, gl::FALSE, - self.def_matrix.as_ptr() as _, + self.curr_matrix.as_ptr() as _, ); - gl.gl.BindFramebuffer(gl::FRAMEBUFFER, self.imgui_data.surf_framebuffer); - gl.gl.Viewport(0, 0, self.imgui_data.last_size.0 as _, self.imgui_data.last_size.1 as _); + gl.gl.UseProgram(self.render_data.tex_shader.program_id); + gl.gl.Uniform1i(self.render_data.tex_shader.texture, 0); + gl.gl.UniformMatrix4fv( + self.render_data.tex_shader.proj_mtx, + 1, + gl::FALSE, + self.curr_matrix.as_ptr() as _, + ); + gl.gl.BindFramebuffer(gl::FRAMEBUFFER, self.render_data.surf_framebuffer); + gl.gl.Viewport(0, 0, self.render_data.last_size.0 as _, self.render_data.last_size.1 as _); } } @@ -928,7 +1035,7 @@ impl BackendRenderer for OpenGLRenderer { unsafe { if let Some(gl) = &GL_PROC { let color = color.to_rgba(); - let mut uv = self.imgui_data.font_tex_size; + let mut uv = self.render_data.font_tex_size; uv.0 = 0.0 / uv.0; uv.1 = 0.0 / uv.1; @@ -941,45 +1048,10 @@ impl BackendRenderer for OpenGLRenderer { VertexData { position: (rect.right as _, rect.bottom as _), uv, color }, ]; - if gl.gl.BindSampler.is_loaded() { - gl.gl.BindSampler(0, 0); - } + self.render_data.fill_shader.bind_attrib_pointer(gl, self.render_data.vbo); - gl.gl.UseProgram(self.imgui_data.program_fill); - gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.imgui_data.vbo); - gl.gl.EnableVertexAttribArray(self.imgui_data.fill_locs.position); - gl.gl.EnableVertexAttribArray(self.imgui_data.fill_locs.uv); - gl.gl.EnableVertexAttribArray(self.imgui_data.fill_locs.color); - - gl.gl.VertexAttribPointer( - self.imgui_data.fill_locs.position, - 2, - gl::FLOAT, - gl::FALSE, - mem::size_of::() as _, - field_offset::(|v| &v.position) as _, - ); - - gl.gl.VertexAttribPointer( - self.imgui_data.fill_locs.uv, - 2, - gl::FLOAT, - gl::FALSE, - mem::size_of::() as _, - field_offset::(|v| &v.uv) as _, - ); - - gl.gl.VertexAttribPointer( - self.imgui_data.fill_locs.color, - 4, - gl::UNSIGNED_BYTE, - gl::TRUE, - mem::size_of::() as _, - field_offset::(|v| &v.color) as _, - ); - - gl.gl.BindTexture(gl::TEXTURE_2D, self.imgui_data.font_texture); - gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.imgui_data.vbo); + gl.gl.BindTexture(gl::TEXTURE_2D, self.render_data.font_texture); + gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.render_data.vbo); gl.gl.BufferData( gl::ARRAY_BUFFER, (vertices.len() * mem::size_of::()) as _, @@ -1010,7 +1082,7 @@ impl BackendRenderer for OpenGLRenderer { gl.gl.Enable(gl::SCISSOR_TEST); gl.gl.Scissor( rect.left as GLint, - self.imgui_data.last_size.1 as GLint - rect.bottom as GLint, + self.render_data.last_size.1 as GLint - rect.bottom as GLint, rect.width() as GLint, rect.height() as GLint, ); @@ -1069,23 +1141,21 @@ impl BackendRenderer for OpenGLRenderer { [-1.0, 1.0, 0.0, 1.0], ]; - gl.gl.UseProgram(self.imgui_data.program_tex); - gl.gl.Uniform1i(self.imgui_data.tex_locs.texture, 0); - gl.gl.UniformMatrix4fv(self.imgui_data.tex_locs.proj_mtx, 1, gl::FALSE, matrix.as_ptr() as _); + gl.gl.UseProgram(self.render_data.tex_shader.program_id); + gl.gl.Uniform1i(self.render_data.tex_shader.texture, 0); + gl.gl.UniformMatrix4fv(self.render_data.tex_shader.proj_mtx, 1, gl::FALSE, matrix.as_ptr() as _); if gl.gl.BindSampler.is_loaded() { gl.gl.BindSampler(0, 0); } - // let vao = return_param(|x| gl.gl.GenVertexArrays(1, x)); - //gl.gl.BindVertexArray(vao); - gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.imgui_data.vbo); - gl.gl.EnableVertexAttribArray(self.imgui_data.tex_locs.position); - gl.gl.EnableVertexAttribArray(self.imgui_data.tex_locs.uv); - gl.gl.EnableVertexAttribArray(self.imgui_data.tex_locs.color); + gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.render_data.vbo); + gl.gl.EnableVertexAttribArray(self.render_data.tex_shader.position); + gl.gl.EnableVertexAttribArray(self.render_data.tex_shader.uv); + gl.gl.EnableVertexAttribArray(self.render_data.tex_shader.color); gl.gl.VertexAttribPointer( - self.imgui_data.tex_locs.position, + self.render_data.tex_shader.position, 2, gl::FLOAT, gl::FALSE, @@ -1094,7 +1164,7 @@ impl BackendRenderer for OpenGLRenderer { ); gl.gl.VertexAttribPointer( - self.imgui_data.tex_locs.uv, + self.render_data.tex_shader.uv, 2, gl::FLOAT, gl::FALSE, @@ -1103,7 +1173,7 @@ impl BackendRenderer for OpenGLRenderer { ); gl.gl.VertexAttribPointer( - self.imgui_data.tex_locs.color, + self.render_data.tex_shader.color, 4, gl::UNSIGNED_BYTE, gl::TRUE, @@ -1115,7 +1185,7 @@ impl BackendRenderer for OpenGLRenderer { let vtx_buffer = draw_list.vtx_buffer(); let idx_buffer = draw_list.idx_buffer(); - gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.imgui_data.vbo); + gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.render_data.vbo); gl.gl.BufferData( gl::ARRAY_BUFFER, (vtx_buffer.len() * mem::size_of::()) as _, @@ -1123,7 +1193,7 @@ impl BackendRenderer for OpenGLRenderer { gl::STREAM_DRAW, ); - gl.gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.imgui_data.ebo); + gl.gl.BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.render_data.ebo); gl.gl.BufferData( gl::ELEMENT_ARRAY_BUFFER, (idx_buffer.len() * mem::size_of::()) as _, @@ -1163,7 +1233,6 @@ impl BackendRenderer for OpenGLRenderer { } gl.gl.Disable(gl::SCISSOR_TEST); - //gl.gl.DeleteVertexArrays(1, &vao); } } @@ -1214,78 +1283,23 @@ impl OpenGLRenderer { &mut self, vert_type: GLenum, vertices: Vec, - texture: u32, + mut texture: u32, shader: BackendShader, ) -> GameResult<()> { if let Some(gl) = &GL_PROC { match shader { BackendShader::Fill => { - gl.gl.UseProgram(self.imgui_data.program_fill); - gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.imgui_data.vbo); - gl.gl.EnableVertexAttribArray(self.imgui_data.fill_locs.position); - gl.gl.EnableVertexAttribArray(self.imgui_data.fill_locs.uv); - gl.gl.EnableVertexAttribArray(self.imgui_data.fill_locs.color); - - gl.gl.VertexAttribPointer( - self.imgui_data.fill_locs.position, - 2, - gl::FLOAT, - gl::FALSE, - mem::size_of::() as _, - field_offset::(|v| &v.position) as _, - ); - - gl.gl.VertexAttribPointer( - self.imgui_data.fill_locs.uv, - 2, - gl::FLOAT, - gl::FALSE, - mem::size_of::() as _, - field_offset::(|v| &v.uv) as _, - ); - - gl.gl.VertexAttribPointer( - self.imgui_data.fill_locs.color, - 4, - gl::UNSIGNED_BYTE, - gl::TRUE, - mem::size_of::() as _, - field_offset::(|v| &v.color) as _, - ); + self.render_data.fill_shader.bind_attrib_pointer(gl, self.render_data.vbo)?; } BackendShader::Texture => { - gl.gl.UseProgram(self.imgui_data.program_tex); - gl.gl.BindBuffer(gl::ARRAY_BUFFER, self.imgui_data.vbo); - gl.gl.EnableVertexAttribArray(self.imgui_data.tex_locs.position); - gl.gl.EnableVertexAttribArray(self.imgui_data.tex_locs.uv); - gl.gl.EnableVertexAttribArray(self.imgui_data.tex_locs.color); - - gl.gl.VertexAttribPointer( - self.imgui_data.tex_locs.position, - 2, - gl::FLOAT, - gl::FALSE, - mem::size_of::() as _, - field_offset::(|v| &v.position) as _, - ); - - gl.gl.VertexAttribPointer( - self.imgui_data.tex_locs.uv, - 2, - gl::FLOAT, - gl::FALSE, - mem::size_of::() as _, - field_offset::(|v| &v.uv) as _, - ); - - gl.gl.VertexAttribPointer( - self.imgui_data.tex_locs.color, - 4, - gl::UNSIGNED_BYTE, - gl::TRUE, - mem::size_of::() as _, - field_offset::(|v| &v.color) as _, - ); + self.render_data.tex_shader.bind_attrib_pointer(gl, self.render_data.vbo)?; + } + BackendShader::WaterFill(scale, t, frame_pos) => { + self.render_data.fill_water_shader.bind_attrib_pointer(gl, self.render_data.vbo)?; + gl.gl.Uniform1f(self.render_data.fill_water_shader.scale, scale); + gl.gl.Uniform1f(self.render_data.fill_water_shader.time, t); + gl.gl.Uniform2f(self.render_data.fill_water_shader.frame_offset, frame_pos.0, frame_pos.1); + texture = self.render_data.surf_texture; } } diff --git a/src/map.rs b/src/map.rs index 23423d4..10af5d4 100644 --- a/src/map.rs +++ b/src/map.rs @@ -302,7 +302,7 @@ impl Map { self.attrib[*self.tiles.get(self.width as usize * y + x).unwrap_or(&0u8) as usize] } - pub fn find_water_regions(&self) -> Vec<(WaterRegionType, Rect)> { + pub fn find_water_regions(&self, water_params: &WaterParams) -> Vec<(WaterRegionType, Rect, u8)> { let mut result = Vec::new(); if self.height == 0 || self.width == 0 { @@ -310,7 +310,7 @@ impl Map { } let mut walked = vec![false; self.width as usize * self.height as usize]; - let mut rects = Vec::>::new(); + let mut rects = Vec::<(Rect, u8)>::new(); for x in 0..self.width { for y in 0..self.height { @@ -325,6 +325,9 @@ impl Map { continue; } + let color_tile_idx = self.tiles[idx]; + let region_color = water_params.get_entry(color_tile_idx).color_middle; + walked[idx] = true; let mut rect = Rect::new(x, y, x, y); let mut queue = vec![(0b1100, x, y)]; @@ -371,7 +374,12 @@ impl Map { return; } - if walked[self.width as usize * ey as usize + ex as usize] { + let idx = self.width as usize * ey as usize + ex as usize; + if walked[idx] { + return; + } + + if water_params.get_entry(self.tiles[idx]).color_middle != region_color { return; } @@ -395,20 +403,20 @@ impl Map { } } - rects.push(rect); + rects.push((rect, color_tile_idx)); } } walked.fill(false); - for mut rect in rects { + for (mut rect, color_idx) in rects { let line = rect.top; let line_up = rect.top - 1; let min_x = rect.left; let max_x = rect.right; rect.top += 1; - result.push((WaterRegionType::WaterDepth, rect)); + result.push((WaterRegionType::WaterDepth, rect, color_idx)); let mut x = min_x; let mut length = 0; @@ -430,6 +438,7 @@ impl Map { result.push(( if make_water_line { WaterRegionType::WaterLine } else { WaterRegionType::WaterDepth }, bounds, + color_idx, )); length = 0; } else { @@ -445,6 +454,7 @@ impl Map { result.push(( if make_water_line { WaterRegionType::WaterLine } else { WaterRegionType::WaterDepth }, bounds, + color_idx, )); } @@ -512,6 +522,16 @@ pub struct WaterParamEntry { pub color_bottom: Color, } +impl Default for WaterParamEntry { + fn default() -> Self { + Self { + color_top: Color::from_rgba(102, 153, 204, 150), + color_middle: Color::from_rgba(102, 153, 204, 75), + color_bottom: Color::from_rgba(102, 153, 204, 75), + } + } +} + pub struct WaterParams { entries: HashMap, } @@ -572,7 +592,8 @@ impl WaterParams { let entry = WaterParamEntry { color_top, color_middle, color_bottom }; for i in tile_min..=tile_max { - self.entries.insert(i, entry); + let e = self.entries.entry(i); + e.or_insert(entry); } } Err(e) => return Err(GameError::IOError(Arc::new(e))), diff --git a/src/scene/game_scene.rs b/src/scene/game_scene.rs index 10c824e..805efee 100644 --- a/src/scene/game_scene.rs +++ b/src/scene/game_scene.rs @@ -121,7 +121,8 @@ impl GameScene { water_params.load_from(water_param_file)?; info!("Loaded water parameters file."); - water_renderer.initialize(stage.map.find_water_regions()); + let regions = stage.map.find_water_regions(&water_params); + water_renderer.initialize(regions, &water_params); } }