aboutsummaryrefslogtreecommitdiff
path: root/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'renderer')
-rw-r--r--renderer/Cargo.toml18
-rw-r--r--renderer/src/main.rs278
-rw-r--r--renderer/src/map.rs161
-rw-r--r--renderer/src/tee.rs206
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,
-};