1
0
Fork 0
mirror of https://github.com/doukutsu-rs/doukutsu-rs synced 2024-11-22 21:52:46 +00:00

graphics::imgui_texture_id and soundness fixes

This commit is contained in:
Alula 2022-01-05 11:42:39 +01:00
parent ebe3c2f2af
commit e2afafdfa3
No known key found for this signature in database
GPG key ID: 3E00485503A1D8BA
5 changed files with 136 additions and 69 deletions

View file

@ -1,3 +1,4 @@
use std::any::Any;
use imgui::DrawData;
use crate::common::{Color, Rect};
@ -17,7 +18,7 @@ pub struct VertexData {
#[derive(Copy, Clone, PartialEq)]
pub enum BackendShader {
Fill,
Texture
Texture,
}
pub trait Backend {
@ -57,13 +58,20 @@ pub trait BackendRenderer {
fn imgui(&self) -> GameResult<&mut imgui::Context>;
fn imgui_texture_id(&self, texture: &Box<dyn BackendTexture>) -> GameResult<imgui::TextureId>;
fn render_imgui(&mut self, draw_data: &DrawData) -> GameResult;
fn supports_vertex_draw(&self) -> bool {
false
}
fn draw_triangle_list(&mut self, vertices: Vec<VertexData>, texture: Option<&Box<dyn BackendTexture>>, shader: BackendShader) -> GameResult;
fn draw_triangle_list(
&mut self,
vertices: Vec<VertexData>,
texture: Option<&Box<dyn BackendTexture>>,
shader: BackendShader,
) -> GameResult;
}
pub trait BackendTexture {
@ -74,6 +82,8 @@ pub trait BackendTexture {
fn clear(&mut self);
fn draw(&mut self) -> GameResult;
fn as_any(&self) -> &dyn Any;
}
#[allow(unreachable_code)]

View file

@ -1,7 +1,8 @@
use std::any::Any;
use std::cell::RefCell;
use std::mem;
use imgui::DrawData;
use imgui::{DrawData, TextureId};
use crate::common::{Color, Rect};
use crate::framework::backend::{
@ -79,6 +80,10 @@ impl BackendTexture for NullTexture {
fn draw(&mut self) -> GameResult<()> {
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
pub struct NullRenderer(RefCell<imgui::Context>);
@ -126,6 +131,10 @@ impl BackendRenderer for NullRenderer {
unsafe { Ok(&mut *self.0.as_ptr()) }
}
fn imgui_texture_id(&self, _texture: &Box<dyn BackendTexture>) -> GameResult<TextureId> {
Ok(TextureId::from(0))
}
fn render_imgui(&mut self, _draw_data: &DrawData) -> GameResult {
Ok(())
}

View file

@ -1,7 +1,10 @@
use core::mem;
use std::any::Any;
use std::borrow::Borrow;
use std::cell::{RefCell, UnsafeCell};
use std::collections::HashMap;
use std::ffi::c_void;
use std::ops::Deref;
use std::ptr::null_mut;
use std::rc::Rc;
use std::time::Duration;
@ -11,7 +14,7 @@ use sdl2::event::{Event, WindowEvent};
use sdl2::keyboard::Scancode;
use sdl2::mouse::{Cursor, SystemCursor};
use sdl2::pixels::PixelFormatEnum;
use sdl2::render::{Texture, TextureCreator, WindowCanvas};
use sdl2::render::{Texture, TextureCreator, TextureQuery, WindowCanvas};
use sdl2::video::GLProfile;
use sdl2::video::WindowContext;
use sdl2::{keyboard, pixels, EventPump, Sdl, VideoSubsystem};
@ -27,6 +30,7 @@ use crate::framework::keyboard::ScanCode;
use crate::framework::render_opengl::{GLContext, OpenGLRenderer};
use crate::framework::ui::init_imgui;
use crate::Game;
use crate::GameError::RenderError;
use crate::GAME_SUSPENDED;
pub struct SDL2Backend {
@ -119,7 +123,7 @@ impl BackendEventLoop for SDL2EventLoop {
};
{
let (width, height) = self.refs.borrow().canvas.window().size();
let (width, height) = self.refs.deref().borrow().canvas.window().size();
ctx.screen_size = (width.max(1) as f32, height.max(1) as f32);
imgui.io_mut().display_size = [ctx.screen_size.0, ctx.screen_size.1];
@ -230,7 +234,7 @@ impl BackendEventLoop for SDL2EventLoop {
imgui_sdl2.prepare_frame(
imgui.io_mut(),
self.refs.borrow().canvas.window(),
self.refs.deref().borrow().canvas.window(),
&self.event_pump.mouse_state(),
);
game.draw(ctx).unwrap();
@ -300,20 +304,18 @@ struct SDL2Renderer {
refs: Rc<RefCell<SDL2Context>>,
imgui: Rc<RefCell<imgui::Context>>,
imgui_event: Rc<RefCell<ImguiSdl2>>,
imgui_textures: HashMap<TextureId, SDL2Texture>,
imgui_font_tex: SDL2Texture,
}
impl SDL2Renderer {
#[allow(clippy::new_ret_no_self)]
pub fn new(refs: Rc<RefCell<SDL2Context>>) -> GameResult<Box<dyn BackendRenderer>> {
let mut imgui = init_imgui()?;
let mut imgui_textures = HashMap::new();
imgui.set_renderer_name("SDL2Renderer".to_owned());
{
let imgui_font_tex = {
let refs = refs.clone();
let mut fonts = imgui.fonts();
let id = fonts.tex_id;
let font_tex = fonts.build_rgba32_texture();
let mut texture = refs
@ -339,17 +341,15 @@ impl SDL2Renderer {
})
.map_err(|e| GameError::RenderError(e.to_string()))?;
imgui_textures.insert(
id,
SDL2Texture {
refs: refs.clone(),
texture: Some(texture),
width: font_tex.width as u16,
height: font_tex.height as u16,
commands: vec![],
},
);
}
SDL2Texture {
refs: refs.clone(),
texture: Some(texture),
width: font_tex.width as u16,
height: font_tex.height as u16,
commands: vec![],
}
};
imgui.fonts().tex_id = TextureId::new(imgui_font_tex.texture.as_ref().unwrap().raw() as usize);
let imgui_sdl2 = unsafe {
let refs = &mut *refs.as_ptr();
@ -360,7 +360,7 @@ impl SDL2Renderer {
refs,
imgui: Rc::new(RefCell::new(imgui)),
imgui_event: Rc::new(RefCell::new(imgui_sdl2)),
imgui_textures,
imgui_font_tex,
}))
}
}
@ -426,7 +426,6 @@ impl BackendRenderer for SDL2Renderer {
let mut refs = self.refs.borrow_mut();
refs.canvas.set_clip_rect(Some(sdl2::rect::Rect::new(0, 0, width as u32, height as u32)));
//refs.canvas.set_clip_rect(None);
Ok(())
}
@ -483,19 +482,23 @@ impl BackendRenderer for SDL2Renderer {
}
fn set_render_target(&mut self, texture: Option<&Box<dyn BackendTexture>>) -> GameResult {
let renderer = self.refs.borrow().canvas.raw();
let renderer = self.refs.deref().borrow().canvas.raw();
// todo: horribly unsafe
match texture {
Some(texture) => unsafe {
let sdl2_texture: &Box<SDL2Texture> = std::mem::transmute(texture);
Some(texture) => {
let sdl2_texture = texture
.as_any()
.downcast_ref::<SDL2Texture>()
.ok_or(RenderError("This texture was not created by OpenGL backend.".to_string()))?;
if let Some(target) = sdl2_texture.texture.as_ref() {
set_raw_target(renderer, target.raw())?;
} else {
set_raw_target(renderer, std::ptr::null_mut())?;
unsafe {
if let Some(target) = sdl2_texture.texture.as_ref() {
set_raw_target(renderer, target.raw())?;
} else {
set_raw_target(renderer, std::ptr::null_mut())?;
}
}
},
}
None => unsafe {
set_raw_target(renderer, std::ptr::null_mut())?;
},
@ -591,6 +594,15 @@ impl BackendRenderer for SDL2Renderer {
unsafe { Ok(&mut *self.imgui.as_ptr()) }
}
fn imgui_texture_id(&self, texture: &Box<dyn BackendTexture>) -> GameResult<TextureId> {
let sdl_texture = texture
.as_any()
.downcast_ref::<SDL2Texture>()
.ok_or(GameError::RenderError("This texture was not created by SDL backend.".to_string()))?;
Ok(TextureId::new(sdl_texture.texture.as_ref().map(|t| t.raw()).unwrap_or(null_mut()) as usize))
}
fn render_imgui(&mut self, draw_data: &DrawData) -> GameResult {
let mut refs = self.refs.borrow_mut();
@ -668,13 +680,17 @@ impl BackendRenderer for SDL2Renderer {
}
}
if let Some(surf) = self.imgui_textures.get_mut(&cmd_params.texture_id) {
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] * surf.width as f32) as i32,
(tex_pos[1] * surf.height as f32) as i32,
((tex_pos[2] - tex_pos[0]) * surf.width as f32) as u32,
((tex_pos[3] - tex_pos[1]) * surf.height as f32) as u32,
(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,
@ -683,12 +699,11 @@ impl BackendRenderer for SDL2Renderer {
(max[1] - min[1]) as u32,
);
let tex = surf.texture.as_mut().unwrap();
tex.set_color_mod(v1.col[0], v1.col[1], v1.col[2]);
tex.set_alpha_mod(v1.col[3]);
surf.set_color_mod(v1.col[0], v1.col[1], v1.col[2]);
surf.set_alpha_mod(v1.col[3]);
refs.canvas
.copy(tex, src, dest)
.copy(&surf, src, dest)
.map_err(|e| GameError::RenderError(e.to_string()))?;
} else {
/*sdl2::sys::gfx::primitives::filledPolygonRGBA(
@ -835,6 +850,10 @@ impl BackendTexture for SDL2Texture {
}
}
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl Drop for SDL2Texture {

View file

@ -120,6 +120,14 @@ pub fn imgui_context(ctx: &Context) -> GameResult<&mut imgui::Context> {
Err(GameError::RenderError("Rendering backend hasn't been initialized yet.".to_string()))
}
pub fn imgui_texture_id(ctx: &Context, texture: &Box<dyn BackendTexture>) -> GameResult<imgui::TextureId> {
if let Some(renderer) = ctx.renderer.as_ref() {
return renderer.imgui_texture_id(texture);
}
Err(GameError::RenderError("Rendering backend hasn't been initialized yet.".to_string()))
}
pub fn render_imgui(ctx: &mut Context, draw_data: &imgui::DrawData) -> GameResult {
if let Some(renderer) = ctx.renderer.as_mut() {
return renderer.render_imgui(draw_data);

View file

@ -1,3 +1,4 @@
use std::any::Any;
use std::cell::{RefCell, UnsafeCell};
use std::ffi::{c_void, CStr};
use std::mem;
@ -5,7 +6,7 @@ use std::mem::MaybeUninit;
use std::ptr::null;
use std::sync::Arc;
use imgui::{DrawCmd, DrawCmdParams, DrawData, DrawIdx, DrawVert};
use imgui::{DrawCmd, DrawCmdParams, DrawData, DrawIdx, DrawVert, TextureId};
use crate::common::{Color, Rect};
use crate::framework::backend::{BackendRenderer, BackendShader, BackendTexture, SpriteBatchCommand, VertexData};
@ -232,6 +233,10 @@ impl BackendTexture for OpenGLTexture {
}
}
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl Drop for OpenGLTexture {
@ -882,7 +887,10 @@ impl BackendRenderer for OpenGLRenderer {
if let Some((_, gl)) = self.get_context() {
unsafe {
if let Some(texture) = texture {
let gl_texture: &Box<OpenGLTexture> = std::mem::transmute(texture);
let gl_texture = texture
.as_any()
.downcast_ref::<OpenGLTexture>()
.ok_or(RenderError("This texture was not created by OpenGL backend.".to_string()))?;
self.curr_matrix = [
[2.0 / (gl_texture.width as f32), 0.0, 0.0, 0.0],
@ -1015,10 +1023,36 @@ impl BackendRenderer for OpenGLRenderer {
Ok(())
}
fn set_clip_rect(&mut self, rect: Option<Rect>) -> GameResult {
if let Some((_, gl)) = self.get_context() {
unsafe {
if let Some(rect) = &rect {
gl.gl.Enable(gl::SCISSOR_TEST);
gl.gl.Scissor(rect.left as GLint, rect.top as GLint, rect.width() as GLint, rect.height() as GLint);
} else {
gl.gl.Disable(gl::SCISSOR_TEST);
}
}
Ok(())
} else {
Err(RenderError("No OpenGL context available!".to_string()))
}
}
fn imgui(&self) -> GameResult<&mut imgui::Context> {
unsafe { Ok(&mut *self.imgui.get()) }
}
fn imgui_texture_id(&self, texture: &Box<dyn BackendTexture>) -> GameResult<TextureId> {
let gl_texture = texture
.as_any()
.downcast_ref::<OpenGLTexture>()
.ok_or(RenderError("This texture was not created by OpenGL backend.".to_string()))?;
Ok(TextureId::new(gl_texture.texture_id as usize))
}
fn render_imgui(&mut self, draw_data: &DrawData) -> GameResult {
// https://github.com/michaelfairley/rust-imgui-opengl-renderer
if let Some((_, gl)) = self.get_context() {
@ -1147,39 +1181,22 @@ impl BackendRenderer for OpenGLRenderer {
Ok(())
}
fn supports_vertex_draw(&self) -> bool {
true
}
fn draw_triangle_list(
&mut self,
vertices: Vec<VertexData>,
texture: Option<&Box<dyn BackendTexture>>,
shader: BackendShader,
) -> GameResult<()> {
unsafe { self.draw_arrays(gl::TRIANGLES, vertices, texture, shader) }
}
fn supports_vertex_draw(&self) -> bool {
true
}
fn set_clip_rect(&mut self, rect: Option<Rect>) -> GameResult {
if let Some((_, gl)) = self.get_context() {
unsafe {
if let Some(rect) = &rect {
gl.gl.Enable(gl::SCISSOR_TEST);
gl.gl.Scissor(rect.left as GLint, rect.top as GLint, rect.width() as GLint, rect.height() as GLint);
} else {
gl.gl.Disable(gl::SCISSOR_TEST);
}
}
Ok(())
} else {
Err(RenderError("No OpenGL context available!".to_string()))
}
self.draw_arrays(gl::TRIANGLES, vertices, texture, shader)
}
}
impl OpenGLRenderer {
unsafe fn draw_arrays(
fn draw_arrays(
&mut self,
vert_type: GLenum,
vertices: Vec<VertexData>,
@ -1191,13 +1208,17 @@ impl OpenGLRenderer {
}
let texture_id = if let Some(texture) = texture {
let gl_texture: &Box<OpenGLTexture> = std::mem::transmute(texture);
let gl_texture = texture
.as_any()
.downcast_ref::<OpenGLTexture>()
.ok_or(RenderError("This texture was not created by OpenGL backend.".to_string()))?;
gl_texture.texture_id
} else {
0
};
self.draw_arrays_tex_id(vert_type, vertices, texture_id, shader)
unsafe { self.draw_arrays_tex_id(vert_type, vertices, texture_id, shader) }
}
unsafe fn draw_arrays_tex_id(