diff --git a/Cargo.toml b/Cargo.toml index c80b734..67ba23c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ category = "Game" osx_minimum_system_version = "10.12" [features] -default = ["default-base", "backend-sdl", "render-opengl", "exe", "editor"] +default = ["default-base", "backend-sdl", "render-opengl", "exe"] default-base = ["scripting-lua", "ogg-playback", "netplay"] ogg-playback = ["lewton"] backend-sdl = ["sdl2", "sdl2-sys"] @@ -49,6 +49,8 @@ android = [] #glutin = { path = "./3rdparty/glutin/glutin", optional = true } #lua-ffi = { path = "./3rdparty/luajit-rs", optional = true } #winit = { path = "./3rdparty/winit", optional = true, default_features = false, features = ["x11"] } +#sdl2 = { path = "./3rdparty/rust-sdl2", optional = true, features = ["unsafe_textures", "bundled", "static-link"] } +#sdl2-sys = { path = "./3rdparty/rust-sdl2/sdl2-sys", optional = true, features = ["bundled", "static-link"] } bitvec = "0.20" byteorder = "1.4" case_insensitive_hashmap = "1.0.0" @@ -69,8 +71,8 @@ lua-ffi = { git = "https://github.com/doukutsu-rs/lua-ffi.git", rev = "e0b2ff596 num-derive = "0.3.2" num-traits = "0.2.12" paste = "1.0.0" -sdl2 = { git = "https://github.com/Rust-SDL2/rust-sdl2.git", rev = "f01b240e14cd23a089daffbb7abf14d55b3b2129", optional = true, features = ["unsafe_textures", "bundled", "static-link"] } -sdl2-sys = { git = "https://github.com/Rust-SDL2/rust-sdl2.git", rev = "f01b240e14cd23a089daffbb7abf14d55b3b2129", optional = true, features = ["bundled", "static-link"] } +sdl2 = { git = "https://github.com/doukutsu-rs/rust-sdl2.git", rev = "95bcf63768abf422527f86da41da910649b9fcc9", optional = true, features = ["unsafe_textures", "bundled", "static-link"] } +sdl2-sys = { git = "https://github.com/doukutsu-rs/rust-sdl2.git", rev = "95bcf63768abf422527f86da41da910649b9fcc9", optional = true, features = ["bundled", "static-link"] } serde = { version = "1", features = ["derive"] } serde_derive = "1" serde_cbor = { version = "0.11.2", optional = true } diff --git a/src/framework/backend.rs b/src/framework/backend.rs index 1dffe93..ecd8b6e 100644 --- a/src/framework/backend.rs +++ b/src/framework/backend.rs @@ -11,8 +11,8 @@ use crate::Game; #[derive(Copy, Clone)] pub struct VertexData { pub position: (f32, f32), - pub uv: (f32, f32), pub color: (u8, u8, u8, u8), + pub uv: (f32, f32), } #[derive(Copy, Clone, PartialEq)] diff --git a/src/framework/backend_sdl2.rs b/src/framework/backend_sdl2.rs index 0bc3bbb..de7301d 100644 --- a/src/framework/backend_sdl2.rs +++ b/src/framework/backend_sdl2.rs @@ -3,12 +3,12 @@ use std::any::Any; use std::cell::{RefCell, UnsafeCell}; use std::ffi::c_void; use std::ops::Deref; -use std::ptr::null_mut; +use std::ptr::{null, null_mut}; use std::rc::Rc; use std::time::Duration; use imgui::internal::RawWrapper; -use imgui::{ConfigFlags, DrawCmd, DrawData, Key, MouseCursor, TextureId, Ui}; +use imgui::{ConfigFlags, DrawCmd, DrawData, DrawIdx, DrawVert, Key, MouseCursor, TextureId, Ui}; use sdl2::event::{Event, WindowEvent}; use sdl2::keyboard::Scancode; use sdl2::mouse::{Cursor, SystemCursor}; @@ -486,7 +486,7 @@ impl BackendRenderer for SDL2Renderer { let sdl2_texture = texture .as_any() .downcast_ref::() - .ok_or(RenderError("This texture was not created by OpenGL backend.".to_string()))?; + .ok_or(RenderError("This texture was not created by SDL2 backend.".to_string()))?; unsafe { if let Some(target) = &sdl2_texture.texture { @@ -621,107 +621,28 @@ impl BackendRenderer for SDL2Renderer { (cmd_params.clip_rect[3] - cmd_params.clip_rect[1]) as u32, ))); + let vtx_buffer = draw_list.vtx_buffer(); let idx_buffer = draw_list.idx_buffer(); - let mut vert_x = [0i16; 6]; - let mut vert_y = [0i16; 6]; - let mut min = [0f32; 2]; - let mut max = [0f32; 2]; - let mut tex_pos = [0f32; 4]; - let mut is_rect = false; - for i in (0..count).step_by(3) { - if is_rect { - is_rect = false; - continue; - } + let tex_ptr = cmd_params.texture_id.id() as *mut sdl2::sys::SDL_Texture; - let v1 = draw_list.vtx_buffer() - [cmd_params.vtx_offset + idx_buffer[cmd_params.idx_offset + i] as usize]; - let v2 = draw_list.vtx_buffer() - [cmd_params.vtx_offset + idx_buffer[cmd_params.idx_offset + i + 1] as usize]; - let v3 = draw_list.vtx_buffer() - [cmd_params.vtx_offset + idx_buffer[cmd_params.idx_offset + i + 2] as usize]; + unsafe { + let v0 = vtx_buffer.get_unchecked(cmd_params.vtx_offset); - vert_x[0] = (v1.pos[0] - 0.5) as i16; - vert_y[0] = (v1.pos[1] - 0.5) as i16; - vert_x[1] = (v2.pos[0] - 0.5) as i16; - vert_y[1] = (v2.pos[1] - 0.5) as i16; - vert_x[2] = (v3.pos[0] - 0.5) as i16; - vert_y[2] = (v3.pos[1] - 0.5) as i16; - - #[allow(clippy::float_cmp)] - if i < count - 3 { - let v4 = draw_list.vtx_buffer() - [cmd_params.vtx_offset + idx_buffer[cmd_params.idx_offset + i + 3] as usize]; - let v5 = draw_list.vtx_buffer() - [cmd_params.vtx_offset + idx_buffer[cmd_params.idx_offset + i + 4] as usize]; - let v6 = draw_list.vtx_buffer() - [cmd_params.vtx_offset + idx_buffer[cmd_params.idx_offset + i + 5] as usize]; - - min[0] = min3(v1.pos[0], v2.pos[0], v3.pos[0]); - min[1] = min3(v1.pos[1], v2.pos[1], v3.pos[1]); - max[0] = max3(v1.pos[0], v2.pos[0], v3.pos[0]); - max[1] = max3(v1.pos[1], v2.pos[1], v3.pos[1]); - - is_rect = (v1.pos[0] == min[0] || v1.pos[0] == max[0]) - && (v1.pos[1] == min[1] || v1.pos[1] == max[1]) - && (v2.pos[0] == min[0] || v2.pos[0] == max[0]) - && (v2.pos[1] == min[1] || v2.pos[1] == max[1]) - && (v3.pos[0] == min[0] || v3.pos[0] == max[0]) - && (v3.pos[1] == min[1] || v3.pos[1] == max[1]) - && (v4.pos[0] == min[0] || v4.pos[0] == max[0]) - && (v4.pos[1] == min[1] || v4.pos[1] == max[1]) - && (v5.pos[0] == min[0] || v5.pos[0] == max[0]) - && (v5.pos[1] == min[1] || v5.pos[1] == max[1]) - && (v6.pos[0] == min[0] || v6.pos[0] == max[0]) - && (v6.pos[1] == min[1] || v6.pos[1] == max[1]); - - if is_rect { - tex_pos[0] = min3(v1.uv[0], v2.uv[0], v3.uv[0]); - tex_pos[1] = min3(v1.uv[1], v2.uv[1], v3.uv[1]); - tex_pos[2] = max3(v1.uv[0], v2.uv[0], v3.uv[0]); - tex_pos[3] = max3(v1.uv[1], v2.uv[1], v3.uv[1]); - } - } - - let ptr = cmd_params.texture_id.id() as *mut sdl2::sys::SDL_Texture; - if !ptr.is_null() { - let mut surf = unsafe { refs.texture_creator.raw_create_texture(ptr) }; - let TextureQuery { width, height, .. } = surf.query(); - - if is_rect { - let src = sdl2::rect::Rect::new( - (tex_pos[0] * width as f32) as i32, - (tex_pos[1] * height as f32) as i32, - ((tex_pos[2] - tex_pos[0]) * width as f32) as u32, - ((tex_pos[3] - tex_pos[1]) * height as f32) as u32, - ); - let dest = sdl2::rect::Rect::new( - min[0] as i32, - min[1] as i32, - (max[0] - min[0]) as u32, - (max[1] - min[1]) as u32, - ); - - surf.set_color_mod(v1.col[0], v1.col[1], v1.col[2]); - surf.set_alpha_mod(v1.col[3]); - - refs.canvas - .copy(&surf, src, dest) - .map_err(|e| GameError::RenderError(e.to_string()))?; - } else { - /*sdl2::sys::gfx::primitives::filledPolygonRGBA( - refs.canvas.raw(), - vert_x.as_ptr(), - vert_y.as_ptr(), - 3, - v1.col[0], - v1.col[1], - v1.col[2], - v1.col[3], - );*/ - } - } + sdl2_sys::SDL_RenderGeometryRaw( + refs.canvas.raw(), + tex_ptr, + v0.pos.as_ptr(), + mem::size_of::() as _, + v0.col.as_ptr() as *const _, + mem::size_of::() as _, + v0.uv.as_ptr(), + mem::size_of::() as _, + vtx_buffer.len().saturating_sub(cmd_params.vtx_offset) as i32, + idx_buffer.as_ptr().add(cmd_params.idx_offset) as *const _, + count as i32, + mem::size_of::() as _, + ); } refs.canvas.set_clip_rect(None); @@ -735,13 +656,46 @@ impl BackendRenderer for SDL2Renderer { Ok(()) } + fn supports_vertex_draw(&self) -> bool { + true + } + fn draw_triangle_list( &mut self, - _vertices: Vec, - _texture: Option<&Box>, - _shader: BackendShader, + vertices: Vec, + mut texture: Option<&Box>, + shader: BackendShader, ) -> GameResult<()> { - Err(GameError::RenderError("Unsupported operation".to_string())) + let mut refs = self.refs.borrow_mut(); + if shader == BackendShader::Fill { + texture = None; + } + + let texture_ptr = if let Some(texture) = texture { + texture + .as_any() + .downcast_ref::() + .ok_or(RenderError("This texture was not created by SDL2 backend.".to_string()))? + .texture + .as_ref() + .map_or(null_mut(), |t| t.raw()) + } else { + null_mut::() + }; + + unsafe { + // potential danger: we assume that the layout of VertexData is the same as SDL_Vertex + sdl2_sys::SDL_RenderGeometry( + refs.canvas.raw(), + texture_ptr, + vertices.as_ptr() as *const sdl2_sys::SDL_Vertex, + vertices.len() as i32, + null(), + 0, + ); + } + + Ok(()) } } diff --git a/src/framework/mod.rs b/src/framework/mod.rs index da091b3..ac54730 100644 --- a/src/framework/mod.rs +++ b/src/framework/mod.rs @@ -16,4 +16,5 @@ pub mod keyboard; #[cfg(feature = "render-opengl")] pub mod render_opengl; pub mod ui; +pub mod util; pub mod vfs; diff --git a/src/framework/render_opengl.rs b/src/framework/render_opengl.rs index 8182231..03e4e5e 100644 --- a/src/framework/render_opengl.rs +++ b/src/framework/render_opengl.rs @@ -15,6 +15,7 @@ use crate::framework::error::GameResult; use crate::framework::gl; use crate::framework::gl::types::*; use crate::framework::graphics::BlendMode; +use crate::framework::util::{field_offset, return_param}; pub struct GLContext { pub gles2_mode: bool, @@ -622,30 +623,6 @@ impl OpenGLRenderer { } } -fn field_offset FnOnce(&'a T) -> &'a U>(f: F) -> usize { - unsafe { - let instance = MaybeUninit::uninit().assume_init(); - - let offset = { - let field: &U = f(&instance); - field as *const U as usize - &instance as *const T as usize - }; - - mem::forget(instance); - - offset - } -} - -fn return_param(f: F) -> T -where - F: FnOnce(&mut T), -{ - let mut val = unsafe { mem::zeroed() }; - f(&mut val); - val -} - impl BackendRenderer for OpenGLRenderer { fn renderer_name(&self) -> String { if self.refs.gles2_mode { diff --git a/src/framework/util.rs b/src/framework/util.rs new file mode 100644 index 0000000..5e5cff0 --- /dev/null +++ b/src/framework/util.rs @@ -0,0 +1,26 @@ +use std::mem; +use std::mem::MaybeUninit; + +pub fn field_offset FnOnce(&'a T) -> &'a U>(f: F) -> usize { + unsafe { + let instance = MaybeUninit::uninit().assume_init(); + + let offset = { + let field: &U = f(&instance); + field as *const U as usize - &instance as *const T as usize + }; + + mem::forget(instance); + + offset + } +} + +pub fn return_param(f: F) -> T + where + F: FnOnce(&mut T), +{ + let mut val = unsafe { mem::zeroed() }; + f(&mut val); + val +}