mirror of
https://github.com/doukutsu-rs/doukutsu-rs.git
synced 2026-08-24 13:02:49 -07:00
Move rendering backend impls to framework/render
This commit is contained in:
@@ -21,13 +21,12 @@ use super::backend::{
|
||||
};
|
||||
use super::context::Context;
|
||||
use super::error::GameResult;
|
||||
use super::filesystem;
|
||||
use super::keyboard::ScanCode;
|
||||
use super::render_opengl::OpenGLRenderer;
|
||||
use super::{filesystem, render_opengl};
|
||||
use crate::common::Rect;
|
||||
use crate::framework::backend::get_scaled_size;
|
||||
use crate::framework::error::GameError;
|
||||
use crate::framework::render_opengl::GLContextType;
|
||||
use crate::framework::render::opengl_impl::{GLContextType, GLPlatformFunctions, OpenGLRenderer};
|
||||
use crate::game::shared_game_state::WindowMode;
|
||||
use crate::game::Game;
|
||||
use crate::input::touch_controls::TouchPoint;
|
||||
@@ -386,7 +385,7 @@ impl BackendEventLoop for GlutinEventLoop {
|
||||
fn new_renderer(&self, ctx: &mut Context) -> GameResult<Box<dyn BackendRenderer>> {
|
||||
struct GlutinGLPlatform(Refs);
|
||||
|
||||
impl render_opengl::GLPlatformFunctions for GlutinGLPlatform {
|
||||
impl GLPlatformFunctions for GlutinGLPlatform {
|
||||
fn get_proc_address(&self, name: &str) -> *const c_void {
|
||||
let window = self.0.borrow();
|
||||
if let Some(window) = window.as_ref() {
|
||||
|
||||
@@ -13,6 +13,7 @@ use crate::framework::backend::{
|
||||
use crate::framework::context::Context;
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::framework::graphics::BlendMode;
|
||||
use crate::framework::render::null_impl::NullRenderer;
|
||||
use crate::game::Game;
|
||||
|
||||
pub struct NullBackend;
|
||||
@@ -63,88 +64,3 @@ impl BackendEventLoop for NullEventLoop {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NullTexture(u16, u16);
|
||||
|
||||
impl BackendTexture for NullTexture {
|
||||
fn dimensions(&self) -> (u16, u16) {
|
||||
(self.0, self.1)
|
||||
}
|
||||
|
||||
fn add(&mut self, _command: SpriteBatchCommand) {}
|
||||
|
||||
fn clear(&mut self) {}
|
||||
|
||||
fn draw(&mut self) -> GameResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NullRenderer;
|
||||
|
||||
impl BackendRenderer for NullRenderer {
|
||||
fn renderer_name(&self) -> String {
|
||||
"Null".to_owned()
|
||||
}
|
||||
|
||||
fn clear(&mut self, _color: Color) {}
|
||||
|
||||
fn present(&mut self) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_texture_mutable(&mut self, width: u16, height: u16) -> GameResult<Box<dyn BackendTexture>> {
|
||||
Ok(Box::new(NullTexture(width, height)))
|
||||
}
|
||||
|
||||
fn create_texture(&mut self, width: u16, height: u16, _data: &[u8]) -> GameResult<Box<dyn BackendTexture>> {
|
||||
Ok(Box::new(NullTexture(width, height)))
|
||||
}
|
||||
|
||||
fn set_blend_mode(&mut self, _blend: BlendMode) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_render_target(&mut self, _texture: Option<&Box<dyn BackendTexture>>) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_rect(&mut self, _rect: Rect<isize>, _color: Color) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_outline_rect(&mut self, _rect: Rect<isize>, _line_width: usize, _color: Color) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_clip_rect(&mut self, _rect: Option<Rect>) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_triangles(
|
||||
&mut self,
|
||||
_vertices: &[VertexData],
|
||||
_texture: Option<&Box<dyn BackendTexture>>,
|
||||
_shader: BackendShader,
|
||||
) -> GameResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_triangles_indexed(
|
||||
&mut self,
|
||||
vertices: &[VertexData],
|
||||
indices: super::graphics::IndexData,
|
||||
texture: Option<&Box<dyn BackendTexture>>,
|
||||
shader: BackendShader,
|
||||
) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
+11
-500
File diff suppressed because it is too large
Load Diff
@@ -14,8 +14,7 @@ pub mod filesystem;
|
||||
pub mod gamepad;
|
||||
pub mod graphics;
|
||||
pub mod keyboard;
|
||||
#[cfg(feature = "render-opengl")]
|
||||
pub mod render_opengl;
|
||||
pub mod render;
|
||||
pub mod ui;
|
||||
pub mod util;
|
||||
pub mod vfs;
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
#![allow(unused)]
|
||||
|
||||
use crate::common::{Color, Rect};
|
||||
use crate::framework::backend::BackendTexture;
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::framework::graphics::{BlendMode, FilterMode};
|
||||
|
||||
pub trait SpriteRenderer {
|
||||
/// Set blending mode used for subsequent draws.
|
||||
fn set_blend_mode(&mut self, mode: BlendMode);
|
||||
|
||||
/// Set texture filtering used for subsequent textured draws.
|
||||
fn set_filter_mode(&mut self, mode: FilterMode);
|
||||
|
||||
/// Set scissor/clip rectangle in destination pixels; None disables clipping.
|
||||
fn set_clip_rect(&mut self, rect: Option<Rect>);
|
||||
|
||||
/// Save the current state (blend/filter/clip) and return an RAII guard that
|
||||
/// restores it when dropped.
|
||||
fn save<'a>(&'a mut self) -> StateGuard<'a>;
|
||||
|
||||
/// Restore the most recently saved state. Intended for RAII guard use.
|
||||
fn restore_state(&mut self, guard: &StateGuard);
|
||||
|
||||
/// Draw a filled rectangle in destination pixels with the current state.
|
||||
fn fill_rect(&mut self, rect: Rect, color: Color) -> GameResult;
|
||||
|
||||
/// Draw a rectangle outline with given line width in pixels.
|
||||
fn draw_rect(&mut self, rect: Rect, line_width: usize, color: Color) -> GameResult;
|
||||
|
||||
fn copy(&mut self, texture: &Box<dyn BackendTexture>, src: Option<Rect<u16>>, dst: Rect<f32>) -> GameResult;
|
||||
|
||||
fn copy_tinted(
|
||||
&mut self,
|
||||
texture: &Box<dyn BackendTexture>,
|
||||
src: Option<Rect<u16>>,
|
||||
dst: Rect<f32>,
|
||||
color: Color,
|
||||
) -> GameResult;
|
||||
|
||||
fn copy_ex(
|
||||
&mut self,
|
||||
texture: &Box<dyn BackendTexture>,
|
||||
src: Option<Rect<u16>>,
|
||||
dst: Rect<f32>,
|
||||
angle_deg: f32,
|
||||
center: Option<(f32, f32)>,
|
||||
flip_x: bool,
|
||||
flip_y: bool,
|
||||
color: Color,
|
||||
) -> GameResult;
|
||||
|
||||
/// Ensure any buffered draws are submitted to the underlying backend.
|
||||
fn flush(&mut self) -> GameResult;
|
||||
}
|
||||
|
||||
/// RAII guard that restores renderer state on drop.
|
||||
pub struct StateGuard<'a> {
|
||||
renderer: Option<&'a mut dyn SpriteRenderer>,
|
||||
state: SavedState,
|
||||
}
|
||||
|
||||
impl<'a> StateGuard<'a> {
|
||||
pub(crate) fn with_state(renderer: &'a mut dyn SpriteRenderer, state: SavedState) -> Self {
|
||||
Self { renderer: Some(renderer), state }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for StateGuard<'a> {
|
||||
fn drop(&mut self) {
|
||||
if let Some(renderer) = self.renderer.take() {
|
||||
renderer.restore_state(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) struct SavedState {
|
||||
blend: BlendMode,
|
||||
filter: FilterMode,
|
||||
clip: Option<Rect>,
|
||||
}
|
||||
|
||||
pub mod null_impl;
|
||||
|
||||
#[cfg(feature = "render-opengl")]
|
||||
pub mod opengl_impl;
|
||||
|
||||
#[cfg(feature = "backend-sdl")]
|
||||
pub mod sdl2_impl;
|
||||
@@ -0,0 +1,91 @@
|
||||
use std::any::Any;
|
||||
|
||||
use crate::common::{Color, Rect};
|
||||
use crate::framework::backend::{BackendRenderer, BackendShader, BackendTexture, SpriteBatchCommand, VertexData};
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::framework::graphics::{BlendMode, IndexData};
|
||||
|
||||
pub struct NullTexture(u16, u16);
|
||||
|
||||
impl BackendTexture for NullTexture {
|
||||
fn dimensions(&self) -> (u16, u16) {
|
||||
(self.0, self.1)
|
||||
}
|
||||
|
||||
fn add(&mut self, _command: SpriteBatchCommand) {}
|
||||
|
||||
fn clear(&mut self) {}
|
||||
|
||||
fn draw(&mut self) -> GameResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NullRenderer;
|
||||
|
||||
impl BackendRenderer for NullRenderer {
|
||||
fn renderer_name(&self) -> String {
|
||||
"Null".to_owned()
|
||||
}
|
||||
|
||||
fn clear(&mut self, _color: Color) {}
|
||||
|
||||
fn present(&mut self) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn create_texture_mutable(&mut self, width: u16, height: u16) -> GameResult<Box<dyn BackendTexture>> {
|
||||
Ok(Box::new(NullTexture(width, height)))
|
||||
}
|
||||
|
||||
fn create_texture(&mut self, width: u16, height: u16, _data: &[u8]) -> GameResult<Box<dyn BackendTexture>> {
|
||||
Ok(Box::new(NullTexture(width, height)))
|
||||
}
|
||||
|
||||
fn set_blend_mode(&mut self, _blend: BlendMode) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_render_target(&mut self, _texture: Option<&Box<dyn BackendTexture>>) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_rect(&mut self, _rect: Rect<isize>, _color: Color) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_outline_rect(&mut self, _rect: Rect<isize>, _line_width: usize, _color: Color) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_clip_rect(&mut self, _rect: Option<Rect>) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_triangles(
|
||||
&mut self,
|
||||
_vertices: &[VertexData],
|
||||
_texture: Option<&Box<dyn BackendTexture>>,
|
||||
_shader: BackendShader,
|
||||
) -> GameResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_triangles_indexed(
|
||||
&mut self,
|
||||
vertices: &[VertexData],
|
||||
indices: IndexData,
|
||||
texture: Option<&Box<dyn BackendTexture>>,
|
||||
shader: BackendShader,
|
||||
) -> GameResult {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -12,14 +12,14 @@ use std::sync::Arc;
|
||||
|
||||
use glow::{HasContext, PixelUnpackData};
|
||||
|
||||
use super::backend::{BackendRenderer, BackendShader, BackendTexture, SpriteBatchCommand, VertexData};
|
||||
use super::context::Context;
|
||||
use super::error::GameError;
|
||||
use super::error::GameError::RenderError;
|
||||
use super::error::GameResult;
|
||||
use super::graphics::{BlendMode, IndexData, ShaderStage, SwapMode};
|
||||
use super::util::{field_offset, return_param};
|
||||
use crate::common::{Color, Rect};
|
||||
use crate::framework::backend::{BackendRenderer, BackendShader, BackendTexture, SpriteBatchCommand, VertexData};
|
||||
use crate::framework::context::Context;
|
||||
use crate::framework::error::GameError;
|
||||
use crate::framework::error::GameError::RenderError;
|
||||
use crate::framework::error::GameResult;
|
||||
use crate::framework::graphics::{BlendMode, IndexData, ShaderStage, SwapMode};
|
||||
use crate::framework::util::{field_offset, return_param};
|
||||
|
||||
type GLResult<T = ()> = Result<T, String>;
|
||||
|
||||
@@ -324,14 +324,14 @@ fn check_shader_compile_status(shader: glow::Shader, gl: &glow::Context) -> GLRe
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const VERTEX_SHADER_BASIC: &str = include_str!("shaders/opengl/vertex_basic_110.glsl");
|
||||
const FRAGMENT_SHADER_TEXTURED: &str = include_str!("shaders/opengl/fragment_textured_110.glsl");
|
||||
const FRAGMENT_SHADER_COLOR: &str = include_str!("shaders/opengl/fragment_color_110.glsl");
|
||||
const FRAGMENT_SHADER_WATER: &str = include_str!("shaders/opengl/fragment_water_110.glsl");
|
||||
const VERTEX_SHADER_BASIC: &str = include_str!("../shaders/opengl/vertex_basic_110.glsl");
|
||||
const FRAGMENT_SHADER_TEXTURED: &str = include_str!("../shaders/opengl/fragment_textured_110.glsl");
|
||||
const FRAGMENT_SHADER_COLOR: &str = include_str!("../shaders/opengl/fragment_color_110.glsl");
|
||||
const FRAGMENT_SHADER_WATER: &str = include_str!("../shaders/opengl/fragment_water_110.glsl");
|
||||
|
||||
const VERTEX_SHADER_BASIC_GLES: &str = include_str!("shaders/opengles/vertex_basic_100.glsl");
|
||||
const FRAGMENT_SHADER_TEXTURED_GLES: &str = include_str!("shaders/opengles/fragment_textured_100.glsl");
|
||||
const FRAGMENT_SHADER_COLOR_GLES: &str = include_str!("shaders/opengles/fragment_color_100.glsl");
|
||||
const VERTEX_SHADER_BASIC_GLES: &str = include_str!("../shaders/opengles/vertex_basic_100.glsl");
|
||||
const FRAGMENT_SHADER_TEXTURED_GLES: &str = include_str!("../shaders/opengles/fragment_textured_100.glsl");
|
||||
const FRAGMENT_SHADER_COLOR_GLES: &str = include_str!("../shaders/opengles/fragment_color_100.glsl");
|
||||
|
||||
macro_rules! impl_rtti {
|
||||
($name:ident, $inner_type:ty, $create_method:ident, $delete_method:ident) => {
|
||||
@@ -415,6 +415,7 @@ impl Drop for RenderShaderObject {
|
||||
}
|
||||
|
||||
struct RenderShader {
|
||||
name: String,
|
||||
program_id: Option<glow::Program>,
|
||||
vertex_shader: Rc<RenderShaderObject>,
|
||||
fragment_shader: Rc<RenderShaderObject>,
|
||||
@@ -434,9 +435,11 @@ impl RenderShader {
|
||||
context: &GlContextHolder,
|
||||
vertex_shader: Rc<RenderShaderObject>,
|
||||
fragment_shader: Rc<RenderShaderObject>,
|
||||
name: String,
|
||||
) -> GLResult<Rc<RenderShader>> {
|
||||
unsafe {
|
||||
let mut shader = RenderShader {
|
||||
name,
|
||||
program_id: None,
|
||||
vertex_shader,
|
||||
fragment_shader,
|
||||
@@ -458,6 +461,8 @@ impl RenderShader {
|
||||
gl.attach_shader(program_id, shader.vertex_shader.shader);
|
||||
gl.attach_shader(program_id, shader.fragment_shader.shader);
|
||||
gl.link_program(program_id);
|
||||
// TODO: Error check?
|
||||
log::debug!("Linked shader '{0}', program ID: {program_id:?}", shader.name);
|
||||
|
||||
shader.texture = gl.get_uniform_location(program_id, "Texture");
|
||||
shader.proj_mtx = gl.get_uniform_location(program_id, "ProjMtx");
|
||||
@@ -570,9 +575,12 @@ impl RenderData {
|
||||
let mut surf_texture = TextureRAAI::new(gl)?;
|
||||
let mut surf_framebuffer = FramebufferRAAI::new(gl)?;
|
||||
|
||||
let tex_shader = RenderShader::compile(&context, vshdr_basic.clone(), fshdr_tex)?;
|
||||
let fill_shader = RenderShader::compile(&context, vshdr_basic.clone(), fshdr_fill)?;
|
||||
let fill_water_shader = RenderShader::compile(&context, vshdr_basic.clone(), fshdr_fill_water)?;
|
||||
let tex_shader =
|
||||
RenderShader::compile(&context, vshdr_basic.clone(), fshdr_tex, "builtin texture".to_owned())?;
|
||||
let fill_shader =
|
||||
RenderShader::compile(&context, vshdr_basic.clone(), fshdr_fill, "builtin fill".to_owned())?;
|
||||
let fill_water_shader =
|
||||
RenderShader::compile(&context, vshdr_basic.clone(), fshdr_fill_water, "builtin water".to_owned())?;
|
||||
|
||||
let vbo = vbo.take();
|
||||
let ebo = ebo.take();
|
||||
@@ -1144,11 +1152,34 @@ impl OpenGLRenderer {
|
||||
#[cfg(debug_assertions)]
|
||||
unsafe {
|
||||
if gl.supports_debug() {
|
||||
log::info!("Debug output is supported");
|
||||
gl.enable(glow::DEBUG_OUTPUT);
|
||||
gl.enable(glow::DEBUG_OUTPUT_SYNCHRONOUS);
|
||||
gl.debug_message_callback(|source, type_, id, severity, message| {
|
||||
log::info!("Debug message: {} {} {} {} {}", source, type_, id, severity, message);
|
||||
let type_str = match type_ {
|
||||
glow::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "DEPRECATED_BEHAVIOR",
|
||||
glow::DEBUG_TYPE_ERROR => "ERROR",
|
||||
glow::DEBUG_TYPE_MARKER => "MARKER",
|
||||
glow::DEBUG_TYPE_OTHER => "OTHER",
|
||||
glow::DEBUG_TYPE_PERFORMANCE => "PERFORMANCE",
|
||||
glow::DEBUG_TYPE_POP_GROUP => "POP_GROUP",
|
||||
glow::DEBUG_TYPE_PORTABILITY => "PORTABILITY",
|
||||
glow::DEBUG_TYPE_PUSH_GROUP => "PUSH_GROUP",
|
||||
glow::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "UNDEFINED_BEHAVIOR",
|
||||
_ => "UNKNOWN",
|
||||
};
|
||||
|
||||
if severity == glow::DEBUG_SEVERITY_NOTIFICATION {
|
||||
return; // too spammy
|
||||
}
|
||||
|
||||
let severity_str = match severity {
|
||||
glow::DEBUG_SEVERITY_NOTIFICATION => "NOTIFICATION",
|
||||
glow::DEBUG_SEVERITY_HIGH => "HIGH",
|
||||
glow::DEBUG_SEVERITY_MEDIUM => "MEDIUM",
|
||||
glow::DEBUG_SEVERITY_LOW => "LOW",
|
||||
_ => "UNKNOWN",
|
||||
};
|
||||
log::debug!("GLDebugOutput(type={type_str}, id={id}, severity={severity_str}): {message}");
|
||||
});
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user