worked on 3d rendering

This commit is contained in:
Mikkel Troels Kongsted 2026-03-24 15:49:32 +01:00
parent 2e14d79962
commit 67608a3aff
9 changed files with 309 additions and 82 deletions

1
game/.gitignore vendored
View File

@ -1 +1,2 @@
/target
.vscode

View File

@ -1,69 +1,58 @@
use std::time::Instant;
use sdl3::render::Canvas;
use sdl3::{EventPump, Sdl, VideoSubsystem};
use sdl3::video::Window;
use sdl3::pixels::Color;
use sdl3::event::Event;
use sdl3::keyboard::Keycode;
use crate::engine::math::{V2, V3};
use std::{marker::PhantomData, time::Duration};
use super::error::Error;
use super::object::Object;
pub struct Game<Io, O: Object> {
sdl_context: Sdl,
video_subsystem: VideoSubsystem,
canvas: Canvas<Window>,
event_pump: EventPump,
io: Io,
pub trait Object<R: Renderer> {
fn update(&mut self, delta: Duration);
fn render(&mut self, r: &mut R);
}
pub trait Io<R: Renderer, O: Object<R>> {
fn run(&mut self, game: &mut Game<R, O>);
}
pub trait Renderer {
fn draw_rect(&mut self, pos: V2, size: V2, color: Color);
fn point(&mut self, pos: V2, color: Color);
fn draw_line(&mut self, from: V2, to: V2, color: Color);
fn draw_cube(&mut self, pos: V3, size: V3, outline_colors: Color, fill_color: Color);
}
pub enum Event {
Exit,
}
pub struct Game<R: Renderer, O: Object<R>> {
_phantom_data: PhantomData<R>,
objects: Vec<O>,
}
impl<Io, O: Object> Game<Io, O> {
pub fn new(io: Io) -> Result<Self, Error> {
let sdl_context = sdl3::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem.window("Game", 1280, 720).position_centered().build().unwrap();
let mut canvas = window.into_canvas();
canvas.set_draw_color(Color::BLACK);
canvas.clear();
canvas.present();
let event_pump = sdl_context.event_pump().unwrap();
impl<R: Renderer, O: Object<R>> Game<R, O> {
pub fn new() -> Result<Self, Error> {
Ok(Self {
sdl_context,
video_subsystem,
canvas,
event_pump,
io,
objects: Vec::new()
_phantom_data: PhantomData,
objects: Vec::new(),
})
}
pub fn run(&mut self) {
let mut time_before = Instant::now();
let time_per_frame = 1_000_000_000 / 60;
'running: loop {
for event in self.event_pump.poll_iter() {
match event {
Event::Quit {..} |
Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
break 'running
},
_ => {}
}
}
let now = Instant::now();
let delta = now - time_before;
time_before = now;
for object in self.objects.iter_mut() {
object.update(delta);
}
pub fn spawn(&mut self, object: O) {
self.objects.push(object);
}
pub fn update(&mut self, delta_time: Duration) {
for object in self.objects.iter_mut() {
object.update(delta_time);
}
}
pub fn render(&mut self, r: &mut R) {
for object in self.objects.iter_mut() {
object.render(r);
}
}
pub fn event(&mut self, event: Event) {}
}

View File

@ -1,10 +0,0 @@
pub trait GameObject {
fn update(deltaTime: Duration);
fn render();
}
pub struct Game<GameObjectTypeetc: GameObject> {
}

View File

79
game/src/engine/math.rs Normal file
View File

@ -0,0 +1,79 @@
use std::ops::{Add, AddAssign, Mul, MulAssign};
pub struct V2(pub f64, pub f64);
#[derive(Copy, Clone)]
pub struct V3(pub f64, pub f64, pub f64);
impl Add for V3 {
type Output = V3;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2)
}
}
impl AddAssign for V3 {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl Mul<f64> for V3 {
type Output = V3;
fn mul(self, rhs: f64) -> Self::Output {
Self(self.0 * rhs, self.1 * rhs, self.2 * rhs)
}
}
impl MulAssign<f64> for V3 {
fn mul_assign(&mut self, rhs: f64) {
*self = *self * rhs;
}
}
impl V3 {
pub fn as_2d(&self) -> V2 {
V2(self.0 / self.2, self.1 / self.2)
}
}
pub struct Vertex(V3, V3, V3);
pub struct Cube {
vertices: [Vertex; 12],
}
impl Cube {
pub fn new(V3(x, y, z): V3, V3(w, h, d): V3) -> Self {
Self {
vertices: [
Vertex(V3(x, y, z), V3(x, y + h, z), V3(x + w, y + h, z)),
Vertex(V3(x + w, y + h, z), V3(x + w, y, z), V3(x, y + h, z)),
Vertex(V3(x + w, y, z), V3(x + w, y + h, z), V3(x + w, y, z + d)),
Vertex(
V3(x + w, y + h, z + d),
V3(x + w, y, z + d),
V3(x, y + h, z + d),
),
Vertex(V3(x, y + h, z), V3(x + w, y + h, z), V3(x, y + h, z + d)),
Vertex(
V3(x + w, y + h, z),
V3(x + w, y + h, z + d),
V3(x, y + h, z + d),
),
Vertex(V3(x, y, z), V3(x, y + h, z), V3(x, y, z + d)),
Vertex(V3(x, y + h, z), V3(x, y + h, z + d), V3(x, y, z + d)),
Vertex(V3(x, y, z), V3(x + w, y, z), V3(x, y, z + d)),
Vertex(V3(x + w, y, z), V3(x + w, y, z + d), V3(x, y, z + d)),
Vertex(V3(x, y, z + d), V3(x + w, y, z + d), V3(x, y + h, z + d)),
Vertex(
V3(x + w, y, z + d),
V3(x + w, y + h, z + d),
V3(x, y + h, z + d),
),
],
}
}
}

View File

@ -1,4 +1,9 @@
pub mod object;
pub mod game;
mod system;
mod error;
mod game;
pub mod math;
mod sdl_io;
mod system;
pub use game::{Event, Game, Io, Object, Renderer};
pub use math::V3;
pub use sdl_io::SdlIo;

View File

@ -1,8 +0,0 @@
use std::time::Duration;
pub trait Object {
fn update(&mut self, delta: Duration);
fn render(&mut self);
}

134
game/src/engine/sdl_io.rs Normal file
View File

@ -0,0 +1,134 @@
use std::time::Instant;
use sdl3::{
event::Event,
keyboard::Keycode,
pixels::{Color, PixelFormat},
render::{Canvas, FRect},
video::Window,
Sdl, VideoSubsystem,
};
use crate::engine::{
error::Error,
game,
math::{V2, V3},
Object,
};
static WIDTH: f64 = 1280.0;
static HEIGHT: f64 = 720.0;
pub struct SdlIo {
sdl_context: Sdl,
video_subsystem: VideoSubsystem,
canvas: Canvas<Window>,
}
impl SdlIo {
pub fn new() -> Result<Self, Error> {
let sdl_context = sdl3::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = video_subsystem
.window("Game", WIDTH as u32, HEIGHT as u32)
.position_centered()
.build()
.unwrap();
let mut canvas = window.into_canvas();
canvas.set_draw_color(Color::BLACK);
canvas.clear();
canvas.present();
Ok(Self {
sdl_context,
video_subsystem,
canvas,
})
}
pub fn run<O: game::Object<Self>>(&mut self, game: &mut game::Game<Self, O>) {
let mut event_pump = self.sdl_context.event_pump().unwrap();
let mut time_before = Instant::now();
let time_per_frame = 1_000_000_000 / 60;
'running: loop {
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => break 'running,
_ => {}
}
}
let time_now = Instant::now();
let delta_time = time_now - time_before;
time_before = time_now;
game.update(delta_time);
self.canvas.set_draw_color(Color::BLACK);
self.canvas.clear();
game.render(self);
self.canvas.present();
}
}
fn world_to_screen(&self, v: V2) -> V2 {
V2(v.0 + WIDTH / 2.0, HEIGHT / 2.0 - v.1)
}
}
impl game::Renderer for SdlIo {
fn draw_rect(&mut self, pos: V2, size: V2, color: Color) {
let pos = self.world_to_screen(pos);
self.canvas.set_draw_color(color);
self.canvas
.fill_rect(FRect::new(
(pos.0 - size.0 / 2.0) as _,
(pos.1 - size.1 / 2.0) as _,
size.0 as _,
size.1 as _,
))
.unwrap();
}
fn point(&mut self, pos: V2, color: Color) {
let pos = self.world_to_screen(pos);
let size = V2(10.0, 10.0);
self.canvas.set_draw_color(color);
self.canvas
.fill_rect(FRect::new(
(pos.0 - size.0 / 2.0) as _,
(pos.1 - size.1 / 2.0) as _,
10.0,
10.0,
))
.unwrap();
}
fn draw_line(&mut self, from: V2, to: V2, color: Color) {
todo!()
}
fn draw_cube(&mut self, pos: V3, size: V3, outline_color: Color, fill_color: Color) {
let V3(x, y, z) = pos;
let V3(w, h, d) = size;
let points = [
pos,
V3(x + w, y, z),
V3(x, y + h, z),
V3(x + w, y + h, z),
V3(x, y, z + d / 100.0),
V3(x + w, y, z + d / 100.0),
V3(x, y + h, z + d / 100.0),
V3(x + w, y + h, z + d / 100.0),
];
for point in points {
self.point(point.as_2d(), outline_color);
}
}
}

View File

@ -1,9 +1,46 @@
#![allow(dead_code)]
use std::time::Duration;
use sdl3::pixels::Color;
use crate::engine::math::{V2, V3};
mod engine;
use crate::engine::game::Game;
fn main() {
// let mut game: Game<(), _> = Game::new(todo!()).unwrap();
// game.run();
println!("Hello, world!");
enum Object {
Player { pos: V3, vel: V3 },
}
impl<R: engine::Renderer> engine::Object<R> for Object {
fn update(&mut self, delta_time: Duration) {
match self {
Object::Player { pos, vel } => {
*pos += *vel * delta_time.as_secs_f64();
}
}
}
fn render(&mut self, r: &mut R) {
match self {
Object::Player { pos, .. } => {
// r.draw_rect(V2(pos.0, pos.1), V2(400.0, 400.0));
r.draw_cube(*pos, V3(100.0, 100.0, 100.0), Color::GREEN, Color::WHITE);
}
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut sdl_io = engine::SdlIo::new()?;
let mut game = engine::Game::<engine::SdlIo, Object>::new()?;
let player = Object::Player {
pos: V3(-50.0, -50.0, 0.0),
vel: V3(0.0, 0.0, 1.0),
};
game.spawn(player);
sdl_io.run(&mut game);
Ok(())
}