diff options
Diffstat (limited to 'renderer')
-rw-r--r-- | renderer/Cargo.toml | 18 | ||||
-rw-r--r-- | renderer/src/main.rs | 278 | ||||
-rw-r--r-- | renderer/src/map.rs | 161 | ||||
-rw-r--r-- | renderer/src/tee.rs | 206 |
4 files changed, 0 insertions, 663 deletions
diff --git a/renderer/Cargo.toml b/renderer/Cargo.toml deleted file mode 100644 index d78190d..0000000 --- a/renderer/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "twrenderer" -version = "0.1.0" -edition = "2021" -authors = [ - "metamuffin <metamuffin@disroot.org>", - "heinrich5991 <heinrich5991@gmail.com>", -] -license = "AGPL-3.0-only" - -[dependencies] -twclient = { path = "../client", features = ["gamenet_ddnet_0_6"]} -skia-safe = { version = "0.52.0", features = ["gl", "wayland"] } -glutin = "0.28.0" -gl = "0.14.0" -log = "0.4.17" -env_logger = "0.9.0" -signal-hook = "0.3.14" diff --git a/renderer/src/main.rs b/renderer/src/main.rs deleted file mode 100644 index 186b773..0000000 --- a/renderer/src/main.rs +++ /dev/null @@ -1,278 +0,0 @@ -pub mod map; -pub mod tee; - -use glutin::{ - event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, - event_loop::{ControlFlow, EventLoop}, - window::{Window, WindowBuilder}, - ContextWrapper, GlProfile, PossiblyCurrent, -}; -use log::{error, info, warn}; -use map::MapRenderer; -use signal_hook::{ - consts::{SIGINT, SIGTERM}, - iterator::Signals, -}; -use skia_safe::{ - gpu::{gl::FramebufferInfo, BackendRenderTarget, SurfaceOrigin}, - Canvas, Color, ColorType, Surface, -}; -use std::{ - collections::HashSet, convert::TryInto, net::IpAddr, process::exit, str::FromStr, - sync::atomic::Ordering, thread, time::Duration, -}; -use tee::TeeRenderer; -use twclient::{ - client::{Client, ClientConfig, ClientInterface, ClientMesgIn, PlayerInput}, - world::World, - SHOULD_EXIT, -}; - -fn main() { - env_logger::init(); - - let event_loop = EventLoop::new(); - let wb = WindowBuilder::new().with_title("teeworlds"); - - let cb = glutin::ContextBuilder::new() - .with_depth_buffer(0) - .with_stencil_buffer(8) - .with_pixel_format(24, 8) - .with_gl_profile(GlProfile::Core); - - // TODO - // #[cfg(not(feature = "wayland"))] - // let cb = cb.with_double_buffer(Some(true)); - - let windowed_context = cb.build_windowed(wb, &event_loop).unwrap(); - - let windowed_context = unsafe { windowed_context.make_current().unwrap() }; - - gl::load_with(|s| windowed_context.get_proc_address(s)); - - let mut gr_context = skia_safe::gpu::DirectContext::new_gl(None, None).unwrap(); - - let fb_info = { - use gl::types::GLint; - let mut fboid: GLint = 0; - unsafe { gl::GetIntegerv(gl::FRAMEBUFFER_BINDING, &mut fboid) }; - - FramebufferInfo { - fboid: fboid.try_into().unwrap(), - format: skia_safe::gpu::gl::Format::RGBA8.into(), - } - }; - - windowed_context - .window() - .set_inner_size(glutin::dpi::Size::new(glutin::dpi::LogicalSize::new( - 1024.0, 1024.0, - ))); - - let surface = create_surface(&windowed_context, &fb_info, &mut gr_context); - - struct Env { - surface: Surface, - gr_context: skia_safe::gpu::DirectContext, - windowed_context: ContextWrapper<PossiblyCurrent, Window>, - } - - let mut env = Env { - surface, - gr_context, - windowed_context, - }; - - let mut args = std::env::args().skip(1); - let ip = IpAddr::from_str(args.next().unwrap().as_str()).unwrap(); - let port = u16::from_str(args.next().unwrap().as_str()).unwrap(); - let mut evloop = Client::new_evloop(); - let (client, client_interface) = Client::new( - &mut evloop, - ip, - port, - ClientConfig { - nick: "metamuffin".to_string(), - clan: "rustacean".to_string(), - timeout: "sdfhaiusdfhus".to_string(), - }, - ); - let mut network_thread = Some(std::thread::spawn(move || client.run(evloop))); - - let mut signals = Signals::new(&[SIGTERM, SIGINT]).unwrap(); - info!("setting up signal handlers"); - thread::spawn(move || { - for sig in signals.forever() { - warn!("received signal {:?}", sig); - SHOULD_EXIT.store(true, Ordering::Relaxed); - thread::sleep(Duration::from_secs(3)); - error!("exit timeout!"); - exit(1); - } - }); - - let mut renderer = Renderer { - client_interface, - tee_renderer: TeeRenderer::new(), - map_renderer: MapRenderer::new(), - world: World::new(), - input: PlayerInput::default(), - }; - - let mut keys_down = HashSet::<VirtualKeyCode>::new(); - - event_loop.run(move |event, _, control_flow| { - *control_flow = ControlFlow::Wait; - - #[allow(deprecated)] - match event { - Event::LoopDestroyed => {} - Event::RedrawEventsCleared => { - if SHOULD_EXIT.load(Ordering::Relaxed) { - warn!("waiting for network thread to finish"); - network_thread.take().unwrap().join().unwrap(); - warn!("exiting renderer"); - exit(0); - } - renderer.tick(); - env.windowed_context.window().request_redraw(); - } - Event::WindowEvent { event, .. } => match event { - WindowEvent::MouseInput { button, state, .. } => match state { - ElementState::Pressed => renderer.input.fire = 1, - ElementState::Released => renderer.input.fire = 0, - }, - WindowEvent::CursorMoved { position, .. } => {} - WindowEvent::Resized(physical_size) => { - env.surface = - create_surface(&env.windowed_context, &fb_info, &mut env.gr_context); - env.windowed_context.resize(physical_size) - } - WindowEvent::CloseRequested => { - warn!("renderer event loop stopped, telling the client to exit too"); - SHOULD_EXIT.store(true, Ordering::Relaxed); - *control_flow = ControlFlow::Exit - } - WindowEvent::KeyboardInput { - input: - KeyboardInput { - virtual_keycode, - state, - .. - }, - .. - } => { - if let Some(k) = virtual_keycode { - let sk = if state == ElementState::Pressed { - 1 - } else { - -1 - }; - let sa = if state == ElementState::Pressed { 1 } else { 0 }; - - let repeat = match state { - ElementState::Pressed => !keys_down.insert(k), - ElementState::Released => !keys_down.remove(&k), - }; - if !repeat { - match k { - VirtualKeyCode::A => { - renderer.input.direction -= sk; - } - VirtualKeyCode::D => { - renderer.input.direction += sk; - } - VirtualKeyCode::Space => { - renderer.input.jump = sa; - } - _ => (), - } - } - } - } - _ => (), - }, - Event::RedrawRequested(_) => { - { - let dims = (env.surface.width() as f32, env.surface.height() as f32); - let canvas = env.surface.canvas(); - renderer.draw(canvas, dims) - } - env.surface.canvas().flush(); - env.windowed_context.swap_buffers().unwrap(); - } - _ => (), - } - }); -} - -pub struct Renderer { - client_interface: ClientInterface, - map_renderer: MapRenderer, - tee_renderer: TeeRenderer, - world: World, - input: PlayerInput, -} - -impl Renderer { - pub fn tick(&mut self) { - self.client_interface - .send - .send(ClientMesgIn::Input(self.input)) - .unwrap(); - for m in self.client_interface.receive.try_iter() { - self.world.update(&m); - match m { - twclient::client::ClientMesgOut::MapChange { .. } => { - self.map_renderer.map_changed(&self.world) - } - _ => (), - } - } - } - pub fn draw(&mut self, canvas: &mut Canvas, dims: (f32, f32)) { - canvas.clear(Color::TRANSPARENT); - let center = self - .world - .tees - .local() - .map(|t| (t.x, t.y)) - .unwrap_or((0, 0)); - - canvas.save(); - canvas.translate((dims.0 / 2.0, dims.1 / 2.0)); - canvas.translate((-center.0 as f32, -center.1 as f32)); - // canvas.scale((0.1, 0.1)); - self.map_renderer.draw(&self.world, canvas); - self.tee_renderer.draw(&self.world, canvas); - - canvas.restore(); - } -} - -fn create_surface( - windowed_context: &ContextWrapper<PossiblyCurrent, Window>, - fb_info: &FramebufferInfo, - gr_context: &mut skia_safe::gpu::DirectContext, -) -> skia_safe::Surface { - let pixel_format = windowed_context.get_pixel_format(); - let size = windowed_context.window().inner_size(); - let backend_render_target = BackendRenderTarget::new_gl( - ( - size.width.try_into().unwrap(), - size.height.try_into().unwrap(), - ), - pixel_format.multisampling.map(|s| s.try_into().unwrap()), - pixel_format.stencil_bits.try_into().unwrap(), - *fb_info, - ); - Surface::from_backend_render_target( - gr_context, - &backend_render_target, - SurfaceOrigin::BottomLeft, - ColorType::RGBA8888, - None, - None, - ) - .unwrap() -} diff --git a/renderer/src/map.rs b/renderer/src/map.rs deleted file mode 100644 index db5dd53..0000000 --- a/renderer/src/map.rs +++ /dev/null @@ -1,161 +0,0 @@ -use std::collections::HashMap; - -use log::info; -use skia_safe::{ - canvas::SrcRectConstraint, Canvas, Color4f, ColorSpace, ISize, Image, Matrix, Paint, Rect, -}; -use twclient::world::{ - helper::Color, - map::{format, TILE_NUM}, - World, -}; - -pub struct MapRenderer { - tileset: HashMap<(Option<usize>, Color), Image>, -} - -const TILE_SIZE: f32 = 32.0; - -impl MapRenderer { - pub fn new() -> Self { - Self { - tileset: HashMap::new(), - } - } - - pub fn tick(&mut self) {} - pub fn map_changed(&mut self, world: &World) { - self.tileset.clear(); - for (key, t) in &world.map.tilesets { - for layer in world.map.layers.iter().filter(|l| l.image == *key) { - let tint = layer.color; - info!( - "loading tileset: (texture: {:?}, tint: {}) => {:?}", - key, - tint, - t.dim() - ); - let mut bytes: Vec<u8> = Vec::with_capacity(t.dim().0 * t.dim().1 * 4); - for ((_x, _y), c) in t.indexed_iter() { - bytes.push((c.r as u32/* * tint.r as u32*/) as u8); - bytes.push((c.g as u32/* * tint.g as u32*/) as u8); - bytes.push((c.b as u32/* * tint.b as u32*/) as u8); - bytes.push((c.a as u32/* * tint.a as u32*/) as u8); - } - let d = skia_safe::Data::new_copy(&bytes); - let v = skia_safe::Image::from_raster_data( - &skia_safe::ImageInfo::new( - ISize::new(t.dim().0 as i32, t.dim().1 as i32), - skia_safe::ColorType::RGBA8888, - skia_safe::AlphaType::Premul, - ColorSpace::new_srgb_linear(), - ), - d, - t.dim().0 * 4, - ) - .unwrap(); - self.tileset.insert((*key, tint), v); - } - } - } - - pub fn draw(&self, world: &World, canvas: &mut Canvas) { - let draw_distance = 40; - let rot90 = Matrix::rotate_deg(90.0); - let mut grid_paint = Paint::new( - Color4f { - a: 1.0, - r: 1.0, - g: 1.0, - b: 1.0, - }, - &ColorSpace::new_srgb(), - ); - grid_paint.set_style(skia_safe::PaintStyle::Stroke); - grid_paint.set_anti_alias(true); - - let center = world - .tees - .local() - .map(|t| (t.x / 32, t.y / 32)) - .unwrap_or((0, 0)); - - for l in &world.map.layers { - let tileset = self.tileset.get(&(l.image, l.color)).unwrap(); - - let mut layer_tint = Paint::new( - Color4f { - a: 1.0, - b: 1.0, - g: 1.0, - r: 1.0, - }, - &ColorSpace::new_srgb(), - ); - layer_tint.set_style(skia_safe::PaintStyle::Fill); - - for layer_y in (center.1 - draw_distance)..(center.1 + draw_distance) { - for layer_x in (center.0 - draw_distance)..(center.0 + draw_distance) { - let layer_x = layer_x.try_into().unwrap_or(0); - let layer_y = layer_y.try_into().unwrap_or(0); - - let tile = match l.tiles.get(( - ((layer_y as i32) + l.offset.1) as usize, - ((layer_y as i32) + l.offset.0) as usize, - )) { - Some(t) => t, - None => continue, - }; - - let rotate = tile.flags & format::TILEFLAG_ROTATE != 0; - let vflip = tile.flags & format::TILEFLAG_VFLIP != 0; - let hflip = tile.flags & format::TILEFLAG_HFLIP != 0; - let tile_x = tile.index as u32 % TILE_NUM; - let tile_y = tile.index as u32 / TILE_NUM; - - if tile_x == 0 && tile_y == 0 { - continue; - } - - canvas.save(); - canvas.translate(( - (layer_x as f32 + 0.5) * TILE_SIZE, - (layer_y as f32 + 0.5) * TILE_SIZE, - )); - if rotate { - canvas.concat(&rot90); - } - if vflip { - canvas.scale((-1.0, 1.0)); - } - if hflip { - canvas.scale((1.0, -1.0)); - } - - const TL: u32 = 64; - canvas.draw_image_rect( - tileset, - Some(( - &Rect { - top: (tile_y * TL) as f32, - left: (tile_x * TL) as f32, - bottom: ((tile_y + 1) * TL) as f32, - right: ((tile_x + 1) * TL) as f32, - }, - SrcRectConstraint::Strict, - )), - Rect { - top: -TILE_SIZE / 2.0, - bottom: TILE_SIZE / 2.0, - left: -TILE_SIZE / 2.0, - right: TILE_SIZE / 2.0, - }, - &layer_tint, - ); - - canvas.restore(); - } - } - } - } -} diff --git a/renderer/src/tee.rs b/renderer/src/tee.rs deleted file mode 100644 index 4d9d945..0000000 --- a/renderer/src/tee.rs +++ /dev/null @@ -1,206 +0,0 @@ -use std::{collections::BTreeMap, fs::File, io::Read}; - -use skia_safe::{ - canvas::SrcRectConstraint, utils::text_utils::Align, Canvas, Color4f, ColorSpace, Data, Font, - Image, Paint, Point, Rect, -}; -use twclient::world::{tee::Tee, World}; - -// const TEE_COLL_RADIUS: f32 = 16.0; -const TEE_REND_RADIUS: f32 = 32.0; -const TEE_EYE_ROTATION_RADIUS: f32 = 8.0; -const TEE_EYE_SIZE: f32 = 12.0; -const TEE_EYE_DISTANCE: f32 = 8.0; -const TEE_FOOT_SIZE: f32 = 14.0; -const TEE_EYE_OFFSET_Y: f32 = -2.0; - -pub struct TeeRenderer { - skins: BTreeMap<String, Image>, -} - -impl TeeRenderer { - pub fn new() -> Self { - Self { - skins: BTreeMap::new(), - } - } - - pub fn draw(&mut self, world: &World, canvas: &mut Canvas) { - for t in world.tees.inner.values() { - canvas.save(); - canvas.translate((t.x as f32, t.y as f32)); - self.draw_tee(canvas, t); - canvas.restore(); - } - } - - pub fn draw_tee(&mut self, canvas: &mut Canvas, tee: &Tee) { - let tee_paint = Paint::new( - Color4f { - a: 1.0, - r: 1.0, - g: 1.0, - b: 1.0, - }, - &ColorSpace::new_srgb(), - ); - let name_paint = Paint::new( - Color4f { - a: 1.0, - r: 1.0, - g: 1.0, - b: 0.0, - }, - &ColorSpace::new_srgb(), - ); - let skin_texture = self - .skins - .entry(tee.skin.clone()) - .or_insert_with(|| TeeRenderer::load_skin(tee.name.as_str()).unwrap()); - - let origin = Point { - x: tee.x as f32, - y: tee.y as f32, - }; - - { - canvas.save(); - - canvas.draw_image_rect( - &skin_texture, - Some((&SKIN_FOOT, SrcRectConstraint::Strict)), - Rect { - top: -TEE_FOOT_SIZE + TEE_REND_RADIUS * 0.5, - left: -TEE_FOOT_SIZE * 2.0 - TEE_FOOT_SIZE * 0.5, - right: TEE_FOOT_SIZE * 2.0 - TEE_FOOT_SIZE * 0.5, - bottom: TEE_FOOT_SIZE + TEE_REND_RADIUS * 0.5, - }, - &tee_paint, - ); - - canvas.restore(); - } - - canvas.draw_image_rect( - &skin_texture, - Some((&SKIN_BODY_SHADOW, SrcRectConstraint::Strict)), - Rect { - top: -TEE_REND_RADIUS, - left: -TEE_REND_RADIUS, - right: TEE_REND_RADIUS, - bottom: TEE_REND_RADIUS, - }, - &tee_paint, - ); - canvas.draw_image_rect( - &skin_texture, - Some((&SKIN_BODY, SrcRectConstraint::Strict)), - Rect { - top: -TEE_REND_RADIUS, - left: -TEE_REND_RADIUS, - right: TEE_REND_RADIUS, - bottom: TEE_REND_RADIUS, - }, - &tee_paint, - ); - - { - canvas.save(); - // println!("{}", tee.angle); - canvas.translate(( - tee.angle.cos() * TEE_EYE_ROTATION_RADIUS, - tee.angle.sin() * TEE_EYE_ROTATION_RADIUS, - )); - - canvas.draw_image_rect( - &skin_texture, - Some((&SKIN_EYE_NORMAL, SrcRectConstraint::Strict)), - Rect { - top: -TEE_EYE_SIZE + TEE_EYE_OFFSET_Y, - left: -TEE_EYE_SIZE - TEE_EYE_DISTANCE / 2.0, - right: TEE_EYE_SIZE - TEE_EYE_DISTANCE / 2.0, - bottom: TEE_EYE_SIZE + TEE_EYE_OFFSET_Y, - }, - &tee_paint, - ); - { - canvas.save(); - canvas.scale((-1.0, 1.0)); - canvas.draw_image_rect( - &skin_texture, - Some((&SKIN_EYE_NORMAL, SrcRectConstraint::Strict)), - Rect { - top: -TEE_EYE_SIZE + TEE_EYE_OFFSET_Y, - left: -TEE_EYE_SIZE - TEE_EYE_DISTANCE / 2.0, - right: TEE_EYE_SIZE - TEE_EYE_DISTANCE / 2.0, - bottom: TEE_EYE_SIZE + TEE_EYE_OFFSET_Y, - }, - &tee_paint, - ); - canvas.restore(); - } - - canvas.restore(); - } - { - canvas.save(); - - canvas.draw_image_rect( - &skin_texture, - Some((&SKIN_FOOT, SrcRectConstraint::Strict)), - Rect { - top: -TEE_FOOT_SIZE + TEE_REND_RADIUS * 0.5, - left: -TEE_FOOT_SIZE * 2.0 + TEE_FOOT_SIZE * 0.5, - right: TEE_FOOT_SIZE * 2.0 + TEE_FOOT_SIZE * 0.5, - bottom: TEE_FOOT_SIZE + TEE_REND_RADIUS * 0.5, - }, - &tee_paint, - ); - - canvas.restore(); - } - - canvas.draw_str_align( - tee.name.as_str(), - (origin.x, origin.y - 20.0), - &Font::default(), - &name_paint, - Align::Center, - ); - } - - pub fn load_skin(_name: &str) -> Option<Image> { - // let path = "/usr/share/ddnet/data/skins/limekitty.png"; - let path = "/home/muffin/.teeworlds/downloadedskins/limekittygirl.png"; - let mut file = File::open(path).unwrap(); - let mut data = Vec::new(); - file.read_to_end(&mut data).unwrap(); - let data = Data::new_copy(&data); - Image::from_encoded(data) - } -} - -const SKIN_BODY: Rect = Rect { - top: 0.0, - left: 0.0, - right: 96.0, - bottom: 96.0, -}; -const SKIN_BODY_SHADOW: Rect = Rect { - top: 0.0, - left: 96.0, - right: 192.0, - bottom: 96.0, -}; -const SKIN_FOOT: Rect = Rect { - left: 196.0, - right: 256.0, - top: 32.0, - bottom: 64.0, -}; -const SKIN_EYE_NORMAL: Rect = Rect { - left: 64.0, - right: 96.0, - top: 96.0, - bottom: 128.0, -}; |