Render: configurable target
parent
5651c58fcc
commit
19a29ea467
|
@ -133,7 +133,7 @@ name = "gamestate-traits"
|
|||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"gameplay",
|
||||
"render-traits",
|
||||
"render-target",
|
||||
"sdl2",
|
||||
"sound-traits",
|
||||
"wad",
|
||||
|
@ -398,16 +398,18 @@ version = "0.9.1"
|
|||
dependencies = [
|
||||
"gameplay",
|
||||
"glam",
|
||||
"render-traits",
|
||||
"render-target",
|
||||
"wad",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "render-traits"
|
||||
name = "render-target"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"gameplay",
|
||||
"golem",
|
||||
"sdl2",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -427,7 +429,7 @@ dependencies = [
|
|||
"intermission-doom",
|
||||
"menu-doom",
|
||||
"render-soft",
|
||||
"render-traits",
|
||||
"render-target",
|
||||
"serde",
|
||||
"sound-sdl2",
|
||||
"sound-traits",
|
||||
|
|
|
@ -9,7 +9,7 @@ members = [
|
|||
"statusbar/doom",
|
||||
"input",
|
||||
"menu/doom",
|
||||
"render/traits",
|
||||
"render/render-target",
|
||||
"render/software",
|
||||
"sound/traits",
|
||||
"sound/sdl2",
|
||||
|
@ -39,7 +39,7 @@ statusbar-doom = { path = "./statusbar/doom" }
|
|||
sound-traits = { path = "./sound/traits" }
|
||||
sound-sdl2 = { path = "./sound/sdl2" }
|
||||
sound-nosnd = { path = "./sound/nosnd" }
|
||||
render-traits = { path = "./render/traits" }
|
||||
render-target = { path = "./render/render-target" }
|
||||
render-soft = { path = "./render/software" }
|
||||
render-opengl = { path = "./render/opengl" }
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ statusbar-doom.workspace = true
|
|||
|
||||
sound-traits.workspace = true
|
||||
sound-sdl2.workspace = true
|
||||
render-traits.workspace = true
|
||||
render-target.workspace = true
|
||||
render-soft.workspace = true
|
||||
wad.workspace = true
|
||||
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
use gameplay::log::info;
|
||||
use gamestate_traits::{
|
||||
sdl2::{
|
||||
pixels,
|
||||
rect::Rect,
|
||||
render::{Canvas, TextureCreator},
|
||||
surface,
|
||||
video::{Window, WindowContext},
|
||||
},
|
||||
RenderTarget,
|
||||
};
|
||||
use render_traits::{PixelBuffer, RenderType};
|
||||
|
||||
use crate::shaders::{
|
||||
self, basic::Basic, cgwg_crt::Cgwgcrt, lottes_crt::LottesCRT, Drawer, Shaders,
|
||||
};
|
||||
|
||||
struct Shader {
|
||||
window: Window,
|
||||
shader: Box<dyn Drawer>,
|
||||
}
|
||||
|
||||
struct Software {
|
||||
canvas: Canvas<Window>,
|
||||
tex_creator: TextureCreator<WindowContext>,
|
||||
}
|
||||
|
||||
pub struct Blitter<'c> {
|
||||
_gl_ctx: &'c golem::Context,
|
||||
crop_rect: Rect,
|
||||
shader: Option<Shader>,
|
||||
soft: Option<Software>,
|
||||
}
|
||||
|
||||
impl<'c> Blitter<'c> {
|
||||
pub fn new(shader_option: Option<Shaders>, gl_ctx: &'c golem::Context, window: Window) -> Self {
|
||||
// TODO: sort this block of stuff out
|
||||
let wsize = window.drawable_size();
|
||||
let ratio = wsize.1 as f32 * 1.333;
|
||||
let xp = (wsize.0 as f32 - ratio) / 2.0;
|
||||
let crop_rect = Rect::new(xp as i32, 0, ratio as u32, wsize.1);
|
||||
|
||||
gl_ctx.set_viewport(
|
||||
crop_rect.x as u32,
|
||||
crop_rect.y as u32,
|
||||
crop_rect.width(),
|
||||
crop_rect.height(),
|
||||
);
|
||||
|
||||
let mut soft = None;
|
||||
let mut shader = None;
|
||||
let post_process: Option<Box<dyn Drawer>> = if let Some(shader) = shader_option {
|
||||
match shader {
|
||||
Shaders::None => None,
|
||||
Shaders::Basic => Some(Box::new(Basic::new(gl_ctx))),
|
||||
Shaders::Lottes => Some(Box::new(LottesCRT::new(gl_ctx))),
|
||||
Shaders::LottesBasic => {
|
||||
Some(Box::new(shaders::lottes_reduced::LottesCRT::new(gl_ctx)))
|
||||
}
|
||||
Shaders::Cgwg => Some(Box::new(Cgwgcrt::new(
|
||||
gl_ctx,
|
||||
crop_rect.width(),
|
||||
crop_rect.height(),
|
||||
))),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(post_process) = post_process {
|
||||
info!("Using a post-process shader");
|
||||
// post_process.set_tex_filter().unwrap();
|
||||
shader = Some(Shader {
|
||||
window,
|
||||
shader: post_process,
|
||||
});
|
||||
} else {
|
||||
info!("No shader selectd, using pure software");
|
||||
let canvas = window.into_canvas().accelerated().build().unwrap();
|
||||
let tex_creator = canvas.texture_creator();
|
||||
soft = Some(Software {
|
||||
canvas,
|
||||
tex_creator,
|
||||
})
|
||||
}
|
||||
|
||||
Self {
|
||||
_gl_ctx: gl_ctx,
|
||||
crop_rect,
|
||||
shader,
|
||||
soft,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn blit(&mut self, render_buffer: &mut RenderTarget) {
|
||||
if let Some(shader) = &mut self.shader {
|
||||
if matches!(render_buffer.render_type(), RenderType::SoftOpenGL) {
|
||||
let render_buffer = unsafe { render_buffer.soft_opengl_unchecked() };
|
||||
// shader.shader.clear();
|
||||
render_buffer.copy_softbuf_to_gl_texture();
|
||||
shader.shader.draw(render_buffer.gl_texture()).unwrap();
|
||||
shader.window.gl_swap_window();
|
||||
}
|
||||
} else if let Some(soft) = &mut self.soft {
|
||||
let w = render_buffer.width() as u32;
|
||||
let h = render_buffer.height() as u32;
|
||||
if matches!(render_buffer.render_type(), RenderType::Software) {
|
||||
let render_buffer = unsafe { render_buffer.software_unchecked() };
|
||||
let surf = surface::Surface::from_data(
|
||||
render_buffer.read_softbuf_pixels(),
|
||||
w,
|
||||
h,
|
||||
4 * w,
|
||||
pixels::PixelFormatEnum::RGBA32,
|
||||
)
|
||||
.unwrap()
|
||||
.as_texture(&soft.tex_creator)
|
||||
.unwrap();
|
||||
soft.canvas.copy(&surf, None, Some(self.crop_rect)).unwrap();
|
||||
soft.canvas.present();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,17 @@
|
|||
//! User configuration options.
|
||||
|
||||
use crate::{shaders::Shaders, CLIOptions, BASE_DIR};
|
||||
use crate::{CLIOptions, BASE_DIR};
|
||||
use dirs::config_dir;
|
||||
use gameplay::log::{error, info, warn};
|
||||
use input::config::InputConfig;
|
||||
use render_target::shaders::Shaders;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sound_sdl2::timidity::GusMemSize;
|
||||
use std::{
|
||||
fs::{create_dir, File, OpenOptions},
|
||||
io::{Read, Write},
|
||||
path::PathBuf,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
const LOG_TAG: &str = "UserConfig";
|
||||
|
@ -26,6 +28,37 @@ fn get_cfg_file() -> PathBuf {
|
|||
dir
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, PartialOrd, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum RenderType {
|
||||
/// Purely software. Typically used with blitting a framebuffer maintained in memory
|
||||
/// directly to screen using SDL2
|
||||
#[default]
|
||||
Software,
|
||||
/// Software framebuffer blitted to screen using OpenGL (and can use shaders)
|
||||
SoftOpenGL,
|
||||
/// OpenGL
|
||||
OpenGL,
|
||||
/// Vulkan
|
||||
Vulkan,
|
||||
}
|
||||
|
||||
impl FromStr for RenderType {
|
||||
type Err = std::io::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s.to_ascii_lowercase().as_str() {
|
||||
"software" => Ok(Self::Software),
|
||||
"softopengl" => Ok(Self::SoftOpenGL),
|
||||
"cgwg" => Ok(Self::OpenGL),
|
||||
"basic" => Ok(Self::Vulkan),
|
||||
_ => Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Unsupported,
|
||||
"Invalid rendering type",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct UserConfig {
|
||||
|
@ -34,6 +67,7 @@ pub struct UserConfig {
|
|||
pub height: u32,
|
||||
pub fullscreen: bool,
|
||||
pub hi_res: bool,
|
||||
pub renderer: RenderType,
|
||||
pub shader: Option<Shaders>,
|
||||
pub sfx_vol: i32,
|
||||
pub mus_vol: i32,
|
||||
|
@ -74,7 +108,7 @@ impl UserConfig {
|
|||
height: 480,
|
||||
hi_res: true,
|
||||
fullscreen: true,
|
||||
sfx_vol: 100,
|
||||
sfx_vol: 80,
|
||||
mus_vol: 70,
|
||||
..UserConfig::default()
|
||||
};
|
||||
|
@ -125,6 +159,14 @@ impl UserConfig {
|
|||
cli.double = Some(self.hi_res);
|
||||
}
|
||||
|
||||
if let Some(renderer) = cli.rendering {
|
||||
if renderer != self.renderer {
|
||||
self.renderer = renderer;
|
||||
}
|
||||
} else {
|
||||
cli.rendering = Some(self.renderer);
|
||||
}
|
||||
|
||||
if cli.shader.is_some() {
|
||||
if cli.shader != self.shader {
|
||||
self.shader = cli.shader;
|
||||
|
|
|
@ -11,7 +11,7 @@ use gameplay::{
|
|||
};
|
||||
use gamestate::{machination::Machinations, Game};
|
||||
use gamestate_traits::{
|
||||
sdl2::{keyboard::Scancode, video::Window},
|
||||
sdl2::{keyboard::Scancode, render::Canvas, video::Window},
|
||||
GameState, MachinationTrait,
|
||||
};
|
||||
use hud_doom::Messages;
|
||||
|
@ -19,14 +19,12 @@ use input::Input;
|
|||
use intermission_doom::Intermission;
|
||||
use menu_doom::MenuDoom;
|
||||
use render_soft::SoftwareRenderer;
|
||||
use render_traits::{PixelBuffer, PlayRenderer, RenderTarget, RenderType};
|
||||
use render_target::{PixelBuffer, PlayRenderer, RenderTarget, RenderType};
|
||||
use sound_traits::SoundAction;
|
||||
use statusbar_doom::Statusbar;
|
||||
use wad::lumps::{WadFlat, WadPatch};
|
||||
|
||||
use crate::{
|
||||
blit::Blitter, cheats::Cheats, shaders::Shaders, timestep::TimeStep, wipe::Wipe, CLIOptions,
|
||||
};
|
||||
use crate::{cheats::Cheats, timestep::TimeStep, wipe::Wipe, CLIOptions};
|
||||
|
||||
/// Never returns until `game.running` is set to false
|
||||
pub fn d_doom_loop(
|
||||
|
@ -55,17 +53,31 @@ pub fn d_doom_loop(
|
|||
matches!(options.verbose, log::LevelFilter::Debug),
|
||||
);
|
||||
|
||||
let mut render_buffer: RenderTarget;
|
||||
let mut render_buffer2: RenderTarget;
|
||||
let mut render_type = RenderType::Software;
|
||||
if let Some(shader) = options.shader {
|
||||
if !matches!(shader, Shaders::None) {
|
||||
render_type = RenderType::SoftOpenGL;
|
||||
let mut canvas = window.into_canvas().accelerated().build().unwrap();
|
||||
|
||||
match options.rendering.unwrap() {
|
||||
crate::config::RenderType::Software => {
|
||||
render_buffer = RenderTarget::new(screen_width, screen_height).with_software(&canvas);
|
||||
render_buffer2 = RenderTarget::new(screen_width, screen_height).with_software(&canvas);
|
||||
}
|
||||
};
|
||||
crate::config::RenderType::SoftOpenGL => {
|
||||
let shader = options.shader.unwrap_or_default();
|
||||
render_type = RenderType::SoftOpenGL;
|
||||
render_buffer =
|
||||
RenderTarget::new(screen_width, screen_height).with_gl(&canvas, &gl_ctx, shader);
|
||||
render_buffer2 =
|
||||
RenderTarget::new(screen_width, screen_height).with_gl(&canvas, &gl_ctx, shader);
|
||||
}
|
||||
crate::config::RenderType::OpenGL => todo!(),
|
||||
crate::config::RenderType::Vulkan => todo!(),
|
||||
}
|
||||
|
||||
info!("Using {render_type:?}");
|
||||
|
||||
let mut timestep = TimeStep::new();
|
||||
let mut render_buffer = RenderTarget::new(screen_width, screen_height, &gl_ctx, render_type);
|
||||
let mut render_buffer2 = RenderTarget::new(screen_width, screen_height, &gl_ctx, render_type);
|
||||
|
||||
if matches!(render_type, RenderType::SoftOpenGL) {
|
||||
let buf = unsafe { render_buffer.soft_opengl_unchecked() };
|
||||
|
@ -74,8 +86,6 @@ pub fn d_doom_loop(
|
|||
buf.set_gl_filter().unwrap();
|
||||
}
|
||||
|
||||
let mut blitter = Blitter::new(options.shader, &gl_ctx, window);
|
||||
|
||||
let mut pal_num = 0;
|
||||
let mut image_num = 0;
|
||||
let mut tex_num = 0;
|
||||
|
@ -151,7 +161,7 @@ pub fn d_doom_loop(
|
|||
&mut game,
|
||||
&mut render_buffer,
|
||||
&mut render_buffer2,
|
||||
&mut blitter,
|
||||
&mut canvas,
|
||||
&mut timestep,
|
||||
);
|
||||
|
||||
|
@ -179,7 +189,7 @@ pub fn d_doom_loop(
|
|||
// );
|
||||
// }
|
||||
|
||||
blitter.blit(&mut render_buffer);
|
||||
render_buffer.blit(&mut canvas);
|
||||
|
||||
// FPS rate updates every second
|
||||
if let Some(_fps) = timestep.frame_rate() {
|
||||
|
@ -290,7 +300,7 @@ fn d_display(
|
|||
game: &mut Game,
|
||||
disp_buf: &mut RenderTarget, // Display from this buffer
|
||||
draw_buf: &mut RenderTarget, // Draw to this buffer
|
||||
blitter: &mut Blitter,
|
||||
canvas: &mut Canvas<Window>,
|
||||
timestep: &mut TimeStep,
|
||||
) {
|
||||
let automap_active = false;
|
||||
|
@ -373,7 +383,7 @@ fn d_display(
|
|||
let mut done = false;
|
||||
timestep.run_this(|_| {
|
||||
done = wipe.do_melt(disp_buf, draw_buf);
|
||||
blitter.blit(disp_buf);
|
||||
disp_buf.blit(canvas);
|
||||
});
|
||||
|
||||
if done {
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
mod blit;
|
||||
mod cheats;
|
||||
mod config;
|
||||
mod d_main;
|
||||
mod shaders;
|
||||
// mod test_funcs;
|
||||
mod timestep;
|
||||
mod wipe;
|
||||
|
||||
use dirs::{cache_dir, data_dir};
|
||||
use gamestate_traits::sdl2;
|
||||
use shaders::Shaders;
|
||||
use render_target::shaders::Shaders;
|
||||
use std::{env::set_var, error::Error, fs::File, io::Write, path::PathBuf};
|
||||
|
||||
use d_main::d_doom_loop;
|
||||
|
@ -91,7 +89,8 @@ pub struct CLIOptions {
|
|||
pub flats_test: bool,
|
||||
#[options(help = "sprite test, cycle through the sprites")]
|
||||
pub sprites_test: bool,
|
||||
|
||||
#[options(meta = "", help = "Rendering type")]
|
||||
pub rendering: Option<config::RenderType>,
|
||||
#[options(meta = "", help = "Screen shader <none, cgwg, lottes, lottesbasic>")]
|
||||
pub shader: Option<Shaders>,
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use gameplay::WallPic;
|
||||
use gamestate::Game;
|
||||
|
||||
use render_traits::RenderTarget;
|
||||
use render_target::RenderTarget;
|
||||
use wad::lumps::{WadFlat, WadPalette, WadPatch};
|
||||
|
||||
pub(crate) fn palette_test(pal_num: usize, game: &mut Game, pixels: &mut RenderTarget) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use gameplay::m_random;
|
||||
use gamestate_traits::RenderTarget;
|
||||
use render_traits::PixelBuffer;
|
||||
use render_target::PixelBuffer;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Wipe {
|
||||
|
@ -74,18 +74,18 @@ impl Wipe {
|
|||
draw_buf: &mut RenderTarget, // Draw to this buffer
|
||||
) -> bool {
|
||||
match disp_buf.render_type() {
|
||||
render_traits::RenderType::Software => {
|
||||
render_target::RenderType::Software => {
|
||||
let disp_buf = unsafe { disp_buf.software_unchecked() };
|
||||
let draw_buf = unsafe { draw_buf.software_unchecked() };
|
||||
self.do_melt_pixels(disp_buf, draw_buf)
|
||||
}
|
||||
render_traits::RenderType::SoftOpenGL => {
|
||||
render_target::RenderType::SoftOpenGL => {
|
||||
let disp_buf = unsafe { disp_buf.soft_opengl_unchecked() };
|
||||
let draw_buf = unsafe { draw_buf.soft_opengl_unchecked() };
|
||||
self.do_melt_pixels(disp_buf, draw_buf)
|
||||
}
|
||||
render_traits::RenderType::OpenGL => todo!(),
|
||||
render_traits::RenderType::Vulkan => todo!(),
|
||||
render_target::RenderType::OpenGL => todo!(),
|
||||
render_target::RenderType::Vulkan => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,6 @@ edition = "2021"
|
|||
[dependencies]
|
||||
sdl2.workspace = true
|
||||
gameplay.workspace = true
|
||||
render-traits.workspace = true
|
||||
render-target.workspace = true
|
||||
sound-traits.workspace = true
|
||||
wad.workspace = true
|
||||
|
|
|
@ -7,7 +7,7 @@ pub use gameplay::{
|
|||
m_random, AmmoType, Card, GameMode, PlayerStatus, Skill, WBPlayerStruct, WBStartStruct,
|
||||
WeaponType, TICRATE, WEAPON_INFO,
|
||||
};
|
||||
pub use render_traits::{PixelBuffer, RenderTarget, RenderType};
|
||||
pub use render_target::{PixelBuffer, RenderTarget, RenderType};
|
||||
pub use sdl2::{self, keyboard::Scancode};
|
||||
pub use sound_traits::{MusTrack, SfxName};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::MachinationTrait;
|
||||
use render_traits::{PixelBuffer, RenderTarget};
|
||||
use render_target::{PixelBuffer, RenderTarget};
|
||||
use std::mem::MaybeUninit;
|
||||
use wad::{
|
||||
lumps::{WadPatch, WAD_PATCH},
|
||||
|
@ -76,15 +76,15 @@ pub fn draw_num(
|
|||
) -> i32 {
|
||||
// TODO: remove duplicated functionality
|
||||
match buffer.render_type() {
|
||||
render_traits::RenderType::Software => {
|
||||
render_target::RenderType::Software => {
|
||||
let pixels = unsafe { buffer.software_unchecked() };
|
||||
draw_num_pixels(p, x, y, pad, nums, drawer, pixels)
|
||||
}
|
||||
render_traits::RenderType::SoftOpenGL => {
|
||||
render_target::RenderType::SoftOpenGL => {
|
||||
let pixels = unsafe { buffer.soft_opengl_unchecked() };
|
||||
draw_num_pixels(p, x, y, pad, nums, drawer, pixels)
|
||||
}
|
||||
render_traits::RenderType::OpenGL => todo!(),
|
||||
render_traits::RenderType::Vulkan => todo!(),
|
||||
render_target::RenderType::OpenGL => todo!(),
|
||||
render_target::RenderType::Vulkan => todo!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ build = "../../build.rs"
|
|||
[dependencies]
|
||||
glam.workspace = true
|
||||
gameplay.workspace = true
|
||||
render-traits.workspace = true
|
||||
render-target.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
wad.workspace = true
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "render-traits"
|
||||
name = "render-target"
|
||||
version = "1.0.0"
|
||||
authors = ["Luke Jones <luke@ljones.dev>"]
|
||||
edition = "2021"
|
||||
|
@ -8,3 +8,5 @@ build = "../../build.rs"
|
|||
[dependencies]
|
||||
gameplay.workspace = true
|
||||
golem.workspace = true
|
||||
sdl2.workspace = true
|
||||
serde.workspace = true
|
|
@ -1,8 +1,18 @@
|
|||
//! A generic `PixelBuf` that can be drawn to and is blitted to screen by the game,
|
||||
//! and a generic `PlayRenderer` for rendering the players view of the level.
|
||||
|
||||
pub mod shaders;
|
||||
|
||||
use gameplay::{Level, Player};
|
||||
use golem::{ColorFormat, Context, GolemError, Texture, TextureFilter};
|
||||
use sdl2::{
|
||||
pixels,
|
||||
rect::Rect,
|
||||
render::{Canvas, TextureCreator},
|
||||
surface,
|
||||
video::{Window, WindowContext},
|
||||
};
|
||||
use shaders::{basic::Basic, cgwg_crt::Cgwgcrt, lottes_crt::LottesCRT, ShaderDraw, Shaders};
|
||||
|
||||
const CHANNELS: usize = 4;
|
||||
|
||||
|
@ -35,14 +45,23 @@ pub struct SoftFramebuffer {
|
|||
height: usize,
|
||||
/// Total length is width * height * CHANNELS, where CHANNELS is RGB bytes
|
||||
buffer: Vec<u8>,
|
||||
crop_rect: Rect,
|
||||
tex_creator: TextureCreator<WindowContext>,
|
||||
}
|
||||
|
||||
impl SoftFramebuffer {
|
||||
fn new(width: usize, height: usize) -> Self {
|
||||
fn new(width: usize, height: usize, canvas: &Canvas<Window>) -> Self {
|
||||
let wsize = canvas.window().drawable_size();
|
||||
let ratio = wsize.1 as f32 * 1.333;
|
||||
let xp = (wsize.0 as f32 - ratio) / 2.0;
|
||||
|
||||
let tex_creator = canvas.texture_creator();
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
buffer: vec![0; (width * height) * CHANNELS],
|
||||
crop_rect: Rect::new(xp as i32, 0, ratio as u32, wsize.1),
|
||||
tex_creator,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,27 +119,30 @@ impl PixelBuffer for SoftFramebuffer {
|
|||
pub struct SoftOpenGL {
|
||||
width: usize,
|
||||
height: usize,
|
||||
frame_buffer: SoftFramebuffer,
|
||||
buffer: Vec<u8>,
|
||||
gl_texture: Texture,
|
||||
screen_shader: Box<dyn ShaderDraw>,
|
||||
}
|
||||
|
||||
impl SoftOpenGL {
|
||||
fn new(width: usize, height: usize, ctx: &Context) -> Self {
|
||||
let mut gl_texture = Texture::new(ctx).unwrap();
|
||||
fn new(width: usize, height: usize, gl_ctx: &Context, screen_shader: Shaders) -> Self {
|
||||
let mut gl_texture = Texture::new(gl_ctx).unwrap();
|
||||
gl_texture.set_image(None, width as u32, height as u32, golem::ColorFormat::RGB);
|
||||
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
frame_buffer: SoftFramebuffer::new(width, height),
|
||||
buffer: vec![0; (width * height) * CHANNELS],
|
||||
gl_texture,
|
||||
screen_shader: match screen_shader {
|
||||
Shaders::Basic => Box::new(Basic::new(gl_ctx)),
|
||||
Shaders::Lottes => Box::new(LottesCRT::new(gl_ctx)),
|
||||
Shaders::LottesBasic => Box::new(shaders::lottes_reduced::LottesCRT::new(gl_ctx)),
|
||||
Shaders::Cgwg => Box::new(Cgwgcrt::new(gl_ctx, width as u32, height as u32)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn frame_buffer(&mut self) -> &mut SoftFramebuffer {
|
||||
&mut self.frame_buffer
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub const fn gl_texture(&self) -> &Texture {
|
||||
&self.gl_texture
|
||||
|
@ -133,7 +155,7 @@ impl SoftOpenGL {
|
|||
|
||||
pub fn copy_softbuf_to_gl_texture(&mut self) {
|
||||
self.gl_texture.set_image(
|
||||
Some(&self.frame_buffer.buffer),
|
||||
Some(&self.buffer),
|
||||
self.width as u32,
|
||||
self.height as u32,
|
||||
ColorFormat::RGBA,
|
||||
|
@ -144,34 +166,49 @@ impl SoftOpenGL {
|
|||
impl PixelBuffer for SoftOpenGL {
|
||||
#[inline]
|
||||
fn width(&self) -> usize {
|
||||
self.frame_buffer.width
|
||||
self.width
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn height(&self) -> usize {
|
||||
self.frame_buffer.height
|
||||
self.height
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn clear(&mut self) {
|
||||
self.frame_buffer.clear();
|
||||
self.buffer.iter_mut().for_each(|n| *n = 0);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_pixel(&mut self, x: usize, y: usize, rgba: (u8, u8, u8, u8)) {
|
||||
self.frame_buffer.set_pixel(x, y, rgba);
|
||||
// Shitty safeguard. Need to find actual cause of fail
|
||||
if x >= self.width || y >= self.height {
|
||||
return;
|
||||
}
|
||||
|
||||
let pos = y * (self.width * CHANNELS) + x * CHANNELS;
|
||||
self.buffer[pos] = rgba.0;
|
||||
self.buffer[pos + 1] = rgba.1;
|
||||
self.buffer[pos + 2] = rgba.2;
|
||||
self.buffer[pos + 3] = rgba.3;
|
||||
}
|
||||
|
||||
/// Read the colour of a single pixel at X|Y
|
||||
#[inline]
|
||||
fn read_softbuf_pixel(&self, x: usize, y: usize) -> (u8, u8, u8, u8) {
|
||||
self.frame_buffer.read_softbuf_pixel(x, y)
|
||||
let pos = y * (self.width * CHANNELS) + x * CHANNELS;
|
||||
(
|
||||
self.buffer[pos],
|
||||
self.buffer[pos + 1],
|
||||
self.buffer[pos + 2],
|
||||
self.buffer[pos + 3],
|
||||
)
|
||||
}
|
||||
|
||||
/// Read the full buffer
|
||||
#[inline]
|
||||
fn read_softbuf_pixels(&mut self) -> &mut [u8] {
|
||||
&mut self.frame_buffer.buffer
|
||||
&mut self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,26 +223,50 @@ pub struct RenderTarget {
|
|||
}
|
||||
|
||||
impl RenderTarget {
|
||||
pub fn new(width: usize, height: usize, ctx: &Context, render_type: RenderType) -> Self {
|
||||
let mut software = None;
|
||||
let mut soft_opengl = None;
|
||||
|
||||
match render_type {
|
||||
RenderType::Software => software = Some(SoftFramebuffer::new(width, height)),
|
||||
RenderType::SoftOpenGL => soft_opengl = Some(SoftOpenGL::new(width, height, ctx)),
|
||||
RenderType::OpenGL => todo!(),
|
||||
RenderType::Vulkan => todo!(),
|
||||
}
|
||||
|
||||
pub fn new(width: usize, height: usize) -> Self {
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
render_type,
|
||||
software,
|
||||
soft_opengl,
|
||||
render_type: RenderType::Software,
|
||||
software: None,
|
||||
soft_opengl: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_software(mut self, canvas: &Canvas<Window>) -> Self {
|
||||
if self.soft_opengl.is_some() {
|
||||
panic!("Rendering already set up for software-opengl");
|
||||
}
|
||||
self.software = Some(SoftFramebuffer::new(self.width, self.height, canvas));
|
||||
self.render_type = RenderType::Software;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_gl(
|
||||
mut self,
|
||||
canvas: &Canvas<Window>,
|
||||
gl_ctx: &Context,
|
||||
screen_shader: Shaders,
|
||||
) -> Self {
|
||||
if self.software.is_some() {
|
||||
panic!("Rendering already set up for software");
|
||||
}
|
||||
self.soft_opengl = Some(SoftOpenGL::new(
|
||||
self.width,
|
||||
self.height,
|
||||
gl_ctx,
|
||||
screen_shader,
|
||||
));
|
||||
self.render_type = RenderType::SoftOpenGL;
|
||||
|
||||
let wsize = canvas.window().drawable_size();
|
||||
let ratio = wsize.1 as f32 * 1.333;
|
||||
let xp = (wsize.0 as f32 - ratio) / 2.0;
|
||||
|
||||
gl_ctx.set_viewport(xp as u32, 0, ratio as u32, wsize.1);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn width(&self) -> usize {
|
||||
self.width
|
||||
|
@ -241,14 +302,39 @@ impl RenderTarget {
|
|||
self.soft_opengl.as_mut().unwrap_unchecked()
|
||||
}
|
||||
|
||||
// // /// Get the array of pixels. The layout of which is [Row<RGBA>]
|
||||
// pub fn softbuf_pixels(&self) -> &[u8] {
|
||||
// &self.software
|
||||
// }
|
||||
|
||||
// pub fn softbuf_pixels_mut(&mut self) -> &mut [u8] {
|
||||
// &mut self.software
|
||||
// }
|
||||
pub fn blit(&mut self, sdl_canvas: &mut Canvas<Window>) {
|
||||
match self.render_type {
|
||||
RenderType::SoftOpenGL => {
|
||||
let ogl = unsafe { self.soft_opengl.as_mut().unwrap_unchecked() };
|
||||
// shader.shader.clear();
|
||||
ogl.copy_softbuf_to_gl_texture();
|
||||
ogl.screen_shader.draw(&ogl.gl_texture).unwrap();
|
||||
sdl_canvas.window().gl_swap_window();
|
||||
}
|
||||
RenderType::Software => {
|
||||
let w = self.width() as u32;
|
||||
let h = self.height() as u32;
|
||||
let render_buffer = unsafe { self.software.as_mut().unwrap_unchecked() };
|
||||
let texc = &render_buffer.tex_creator;
|
||||
let surf = surface::Surface::from_data(
|
||||
&mut render_buffer.buffer,
|
||||
w,
|
||||
h,
|
||||
4 * w,
|
||||
pixels::PixelFormatEnum::RGBA32,
|
||||
)
|
||||
.unwrap()
|
||||
.as_texture(texc)
|
||||
.unwrap();
|
||||
sdl_canvas
|
||||
.copy(&surf, None, Some(render_buffer.crop_rect))
|
||||
.unwrap();
|
||||
sdl_canvas.present();
|
||||
}
|
||||
RenderType::OpenGL => todo!(),
|
||||
RenderType::Vulkan => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PlayRenderer {
|
|
@ -3,7 +3,7 @@ use std::f32::consts::FRAC_PI_4;
|
|||
use gameplay::glam::{Mat4, Vec3};
|
||||
use golem::{Dimension::*, *};
|
||||
|
||||
use super::{Drawer, GL_QUAD, GL_QUAD_INDICES};
|
||||
use super::{ShaderDraw, GL_QUAD, GL_QUAD_INDICES};
|
||||
|
||||
pub struct Basic {
|
||||
_quad: [f32; 16],
|
||||
|
@ -80,7 +80,7 @@ impl Basic {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drawer for Basic {
|
||||
impl ShaderDraw for Basic {
|
||||
fn draw(&mut self, texture: &Texture) -> Result<(), GolemError> {
|
||||
let bind_point = std::num::NonZeroU32::new(1).unwrap();
|
||||
texture.set_active(bind_point);
|
|
@ -3,7 +3,7 @@ use std::f32::consts::FRAC_PI_4;
|
|||
use gameplay::glam::{Mat4, Vec3};
|
||||
use golem::{Dimension::*, *};
|
||||
|
||||
use super::{Drawer, GL_QUAD, GL_QUAD_INDICES};
|
||||
use super::{ShaderDraw, GL_QUAD, GL_QUAD_INDICES};
|
||||
|
||||
/// CRT shader
|
||||
/// ```
|
||||
|
@ -102,7 +102,7 @@ impl Cgwgcrt {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drawer for Cgwgcrt {
|
||||
impl ShaderDraw for Cgwgcrt {
|
||||
fn draw(&mut self, texture: &Texture) -> Result<(), GolemError> {
|
||||
// Set the image to use
|
||||
let bind_point = std::num::NonZeroU32::new(1).unwrap();
|
|
@ -3,7 +3,7 @@ use std::f32::consts::FRAC_PI_4;
|
|||
use gameplay::glam::{Mat4, Vec3};
|
||||
use golem::{Dimension::*, *};
|
||||
|
||||
use super::{Drawer, GL_QUAD, GL_QUAD_INDICES};
|
||||
use super::{ShaderDraw, GL_QUAD, GL_QUAD_INDICES};
|
||||
|
||||
pub struct LottesCRT {
|
||||
_quad: [f32; 16],
|
||||
|
@ -82,7 +82,7 @@ impl LottesCRT {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drawer for LottesCRT {
|
||||
impl ShaderDraw for LottesCRT {
|
||||
fn draw(&mut self, texture: &Texture) -> Result<(), GolemError> {
|
||||
self.crt_shader.bind();
|
||||
self.crt_shader.prepare_draw(&self.vb, &self.eb)?;
|
|
@ -3,7 +3,7 @@ use std::f32::consts::FRAC_PI_4;
|
|||
use gameplay::glam::{Mat4, Vec3};
|
||||
use golem::{Dimension::*, *};
|
||||
|
||||
use super::{Drawer, GL_QUAD, GL_QUAD_INDICES};
|
||||
use super::{ShaderDraw, GL_QUAD, GL_QUAD_INDICES};
|
||||
|
||||
pub struct LottesCRT {
|
||||
_quad: [f32; 16],
|
||||
|
@ -126,7 +126,7 @@ impl LottesCRT {
|
|||
}
|
||||
}
|
||||
|
||||
impl Drawer for LottesCRT {
|
||||
impl ShaderDraw for LottesCRT {
|
||||
fn draw(&mut self, texture: &Texture) -> Result<(), GolemError> {
|
||||
// Set the image to use
|
||||
let bind_point = std::num::NonZeroU32::new(1).unwrap();
|
|
@ -13,7 +13,6 @@ pub enum Shaders {
|
|||
LottesBasic,
|
||||
Cgwg,
|
||||
Basic,
|
||||
None,
|
||||
}
|
||||
|
||||
impl Default for Shaders {
|
||||
|
@ -31,7 +30,6 @@ impl FromStr for Shaders {
|
|||
"lottesbasic" => Ok(Shaders::LottesBasic),
|
||||
"cgwg" => Ok(Shaders::Cgwg),
|
||||
"basic" => Ok(Shaders::Basic),
|
||||
"none" => Ok(Shaders::None),
|
||||
_ => Err(std::io::Error::new(std::io::ErrorKind::Unsupported, "Doh!")),
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +45,6 @@ const GL_QUAD: [f32; 16] = [
|
|||
|
||||
const GL_QUAD_INDICES: [u32; 6] = [0, 1, 2, 2, 3, 0];
|
||||
|
||||
pub trait Drawer {
|
||||
pub trait ShaderDraw {
|
||||
fn draw(&mut self, texture: &Texture) -> Result<(), GolemError>;
|
||||
}
|
|
@ -8,7 +8,7 @@ build = "../../build.rs"
|
|||
[dependencies]
|
||||
glam.workspace = true
|
||||
gameplay.workspace = true
|
||||
render-traits.workspace = true
|
||||
render-target.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
wad.workspace = true
|
||||
|
|
|
@ -10,7 +10,7 @@ use gameplay::{
|
|||
SubSector, IS_SSECTOR_MASK,
|
||||
};
|
||||
use glam::Vec2;
|
||||
use render_traits::{PixelBuffer, PlayRenderer, RenderTarget};
|
||||
use render_target::{PixelBuffer, PlayRenderer, RenderTarget};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
f32::consts::{FRAC_PI_2, FRAC_PI_4, PI},
|
||||
|
@ -74,7 +74,7 @@ impl PlayRenderer for SoftwareRenderer {
|
|||
|
||||
// TODO: pull duplicate functionality out to a function
|
||||
match pixels.render_type() {
|
||||
render_traits::RenderType::Software => {
|
||||
render_target::RenderType::Software => {
|
||||
let pixels = unsafe { pixels.software_unchecked() };
|
||||
self.clear(player, pixels.width() as f32);
|
||||
// TODO: netupdate
|
||||
|
@ -94,7 +94,7 @@ impl PlayRenderer for SoftwareRenderer {
|
|||
self.draw_masked(player, pixels);
|
||||
// TODO: netupdate again
|
||||
}
|
||||
render_traits::RenderType::SoftOpenGL => {
|
||||
render_target::RenderType::SoftOpenGL => {
|
||||
let pixels = unsafe { pixels.soft_opengl_unchecked() };
|
||||
self.clear(player, pixels.width() as f32);
|
||||
// TODO: netupdate
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::f32::consts::FRAC_PI_2;
|
|||
use crate::utilities::screen_to_x_view;
|
||||
use gameplay::{Angle, FlatPic, PicData};
|
||||
use glam::Vec2;
|
||||
use render_traits::PixelBuffer;
|
||||
use render_target::PixelBuffer;
|
||||
|
||||
use super::defs::Visplane;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::utilities::screen_to_x_view;
|
||||
use gameplay::{Angle, LineDefFlags, PicData, Player, Segment};
|
||||
use render_traits::PixelBuffer;
|
||||
use render_target::PixelBuffer;
|
||||
use std::{cell::RefCell, f32::consts::FRAC_PI_2, ptr::NonNull, rc::Rc};
|
||||
|
||||
use crate::utilities::{point_to_dist, scale_from_view_angle};
|
||||
|
|
|
@ -8,7 +8,7 @@ use gameplay::{
|
|||
PspDef, Sector,
|
||||
};
|
||||
use glam::Vec2;
|
||||
use render_traits::PixelBuffer;
|
||||
use render_target::PixelBuffer;
|
||||
|
||||
use super::{bsp::SoftwareRenderer, defs::DrawSeg};
|
||||
|
||||
|
|
Loading…
Reference in New Issue