refactoring
This commit is contained in:
parent
3a92f526a0
commit
552a36a146
7 changed files with 282 additions and 130 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -1028,6 +1028,7 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||||
name = "playground"
|
name = "playground"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"glium",
|
||||||
"moonhare_engine",
|
"moonhare_engine",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
129
moonhare_engine/src/game.rs
Normal file
129
moonhare_engine/src/game.rs
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use glium::{glutin::surface::WindowSurface, winit::{application::ApplicationHandler, event::{Event, WindowEvent}, event_loop::{self, EventLoop}, window::{self, Window}}, Display};
|
||||||
|
|
||||||
|
use crate::game_plugin::GamePlugin;
|
||||||
|
|
||||||
|
pub struct Game {
|
||||||
|
running: bool,
|
||||||
|
game_plugin: Option<Box<dyn GamePlugin>>,
|
||||||
|
window: Option<Window>,
|
||||||
|
display: Arc<Mutex<Option<glium::Display<WindowSurface>>>>,
|
||||||
|
event_loop: EventLoop<()>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Game {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
running: true,
|
||||||
|
game_plugin: None,
|
||||||
|
window: None,
|
||||||
|
display: Arc::new(Mutex::new(None)),
|
||||||
|
event_loop: init_event_loop(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_plugin(&mut self, plugin: Box<dyn GamePlugin>) {
|
||||||
|
self.game_plugin = Some(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(&mut self) {
|
||||||
|
if let Some(ref mut game_plugin) = self.game_plugin {
|
||||||
|
game_plugin.init();
|
||||||
|
} else {
|
||||||
|
todo!("Default Impl init")
|
||||||
|
}
|
||||||
|
|
||||||
|
let (_window, _display) = return_window(&self.event_loop);
|
||||||
|
self.window = Some(_window);
|
||||||
|
self.display = Arc::new(Mutex::new(Some(_display)));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self) {
|
||||||
|
if let Some(ref mut game_plugin) = self.game_plugin {
|
||||||
|
game_plugin.update();
|
||||||
|
} else {
|
||||||
|
todo!("Default Impl update")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&mut self) {
|
||||||
|
if let Some(ref display) = self.display.into() {
|
||||||
|
let mut target = display.draw();
|
||||||
|
|
||||||
|
if let Some(ref mut game_plugin) = self.game_plugin {
|
||||||
|
game_plugin.render(&mut target);
|
||||||
|
} else {
|
||||||
|
todo!("Default Impl render")
|
||||||
|
}
|
||||||
|
|
||||||
|
target.finish().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cleanup(&mut self) {
|
||||||
|
if let Some(ref mut game_plugin) = self.game_plugin {
|
||||||
|
game_plugin.cleanup();
|
||||||
|
} else {
|
||||||
|
todo!("Default Impl cleanup")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self) {
|
||||||
|
self.init();
|
||||||
|
|
||||||
|
while self.running {
|
||||||
|
self.update();
|
||||||
|
self.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApplicationHandler for Game {
|
||||||
|
fn resumed(&mut self, event_loop: &event_loop::ActiveEventLoop) {
|
||||||
|
self.window = Some(event_loop.create_window(Window::default_attributes()).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_event(
|
||||||
|
&mut self,
|
||||||
|
event_loop: &event_loop::ActiveEventLoop,
|
||||||
|
window_id: window::WindowId,
|
||||||
|
event: WindowEvent,
|
||||||
|
) {
|
||||||
|
|
||||||
|
match event {
|
||||||
|
|
||||||
|
WindowEvent::CloseRequested => {
|
||||||
|
event_loop.exit();
|
||||||
|
},
|
||||||
|
WindowEvent::Resized(window_size) => {
|
||||||
|
self.display.as_ref().unwrap().resize(window_size.into());
|
||||||
|
},
|
||||||
|
|
||||||
|
WindowEvent::RedrawRequested => {
|
||||||
|
self.window.as_ref().unwrap().request_redraw();
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_event_loop() -> EventLoop<()> {
|
||||||
|
let event_loop = glium::winit::event_loop::EventLoop::builder()
|
||||||
|
.build()
|
||||||
|
.expect("event loop building");
|
||||||
|
|
||||||
|
return event_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn return_window(event_loop: &EventLoop<()>) -> (Window, Display<WindowSurface>) {
|
||||||
|
let (_window, display) = glium::backend::glutin::SimpleWindowBuilder::new()
|
||||||
|
.with_title(crate::ENGINE_NAME)
|
||||||
|
.build(event_loop);
|
||||||
|
|
||||||
|
return (_window, display);
|
||||||
|
}
|
||||||
8
moonhare_engine/src/game_plugin.rs
Normal file
8
moonhare_engine/src/game_plugin.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
use glium::Frame;
|
||||||
|
|
||||||
|
pub trait GamePlugin {
|
||||||
|
fn init(&mut self);
|
||||||
|
fn update(&mut self);
|
||||||
|
fn render(&mut self, target: &mut Frame);
|
||||||
|
fn cleanup(&mut self);
|
||||||
|
}
|
||||||
|
|
@ -1,135 +1,17 @@
|
||||||
mod vertex;
|
pub mod vertex;
|
||||||
|
pub mod game;
|
||||||
|
pub mod game_plugin;
|
||||||
|
|
||||||
use glium::{uniform, uniforms, Surface};
|
use glium::{glutin::surface::WindowSurface, uniform, uniforms, winit::{event::{self, StartCause}, event_loop::{self, EventLoop, EventLoopBuilder}, window::{self, Window}}, Display, Surface};
|
||||||
|
|
||||||
use vertex::Vertex;
|
|
||||||
|
|
||||||
|
const ENGINE_NAME: &str = "Moonhare Engine";
|
||||||
|
|
||||||
// rescaling: position *= factor;
|
// rescaling: position *= factor;
|
||||||
// rotating: new_position = vec2(pos.x * cos(angle) - pos.y * sin(angle), pos.x * sin(single) + pos.y * cos(angle));
|
// rotating: new_position = vec2(pos.x * cos(angle) - pos.y * sin(angle), pos.x * sin(single) + pos.y * cos(angle));
|
||||||
// skewing: position.x += position.y * factor;
|
// skewing: position.x += position.y * factor;
|
||||||
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let event_loop = glium::winit::event_loop::EventLoop::builder()
|
|
||||||
.build()
|
|
||||||
.expect("event loop building");
|
|
||||||
|
|
||||||
let (_window, display) = glium::backend::glutin::SimpleWindowBuilder::new()
|
|
||||||
.with_title("Moonhare Engine")
|
|
||||||
.build(&event_loop);
|
|
||||||
|
|
||||||
let shape = vec![
|
|
||||||
Vertex { position: [-0.5, -0.5], color: [1.0, 0.0, 0.0] },
|
|
||||||
Vertex { position: [ 0.0, 0.5], color: [0.0, 1.0, 0.0] },
|
|
||||||
Vertex { position: [ 0.5, -0.25], color: [0.0, 0.0, 1.0] }
|
|
||||||
];
|
|
||||||
|
|
||||||
// "Upload" shape to the memory of the GPU (Vertex Buffer)
|
|
||||||
// Isn't strictly necessary but, makes tge drawing operation faster
|
|
||||||
let vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap();
|
|
||||||
|
|
||||||
// Complex shapes consist of hundreds/thousands of vertices -> need to have a list of vertices and tell OpenGL how to link these
|
|
||||||
// vertices together to obtain triangles.
|
|
||||||
// For only one triangle -> pass dummy marker to glium
|
|
||||||
// This line tells OpenGl that we don't use indices and instand want to draw a certain number of seperate triangles
|
|
||||||
let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);
|
|
||||||
|
|
||||||
// (Simplified) Render Pipeline:
|
|
||||||
// Vertex Shader -> Fragment (Pixel) Shader
|
|
||||||
// uniform:
|
|
||||||
// value is set when we draw by passing its value to the draw function
|
|
||||||
// (easiest way is uniform! macro)
|
|
||||||
// Important to write matrix * vertex -> Matrix operations produce different results depending on the order
|
|
||||||
// out: defines a variable that is going to be passed along to the fragment shader
|
|
||||||
let vertex_shader_src = r#"
|
|
||||||
#version 140
|
|
||||||
|
|
||||||
in vec2 position;
|
|
||||||
in vec3 color;
|
|
||||||
out vec3 vertex_color;
|
|
||||||
|
|
||||||
uniform mat4 matrix;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
vertex_color = color;
|
|
||||||
gl_Position = matrix * vec4(position, 0.0, 1.0);
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
let fragment_shader_src = r#"
|
|
||||||
#version 140
|
|
||||||
|
|
||||||
in vec3 vertex_color;
|
|
||||||
out vec4 color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
color = vec4(vertex_color, 1.0);
|
|
||||||
}
|
|
||||||
"#;
|
|
||||||
|
|
||||||
// send shader source code to glium
|
|
||||||
let program = glium::Program::from_source(
|
|
||||||
&display,
|
|
||||||
vertex_shader_src,
|
|
||||||
fragment_shader_src,
|
|
||||||
None
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let mut t: f32 = 0.0;
|
|
||||||
let _ = event_loop.run(move |event, window_target| {
|
|
||||||
match event {
|
|
||||||
glium::winit::event::Event::WindowEvent { event, .. } => match event {
|
|
||||||
glium::winit::event::WindowEvent::CloseRequested => window_target.exit(),
|
|
||||||
glium::winit::event::WindowEvent::Resized(window_size) => {
|
|
||||||
display.resize(window_size.into());
|
|
||||||
}
|
|
||||||
glium::winit::event::WindowEvent::RedrawRequested => {
|
|
||||||
t += 0.02;
|
|
||||||
// use 't' as an offset -> smooth animation
|
|
||||||
let x_offset = t.sin() * 0.5;
|
|
||||||
|
|
||||||
let mut target = display.draw();
|
|
||||||
|
|
||||||
target.clear_color(
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
1.0,
|
|
||||||
1.0);
|
|
||||||
|
|
||||||
// Note: In OpenGL matrices are column-major
|
|
||||||
// Standard mathematical notation is row major:
|
|
||||||
// 1.0 0.0 0.0 x_offset
|
|
||||||
// 0.0 1.0 0.0 0.0
|
|
||||||
// 0.0 0.0 1.0 0.0
|
|
||||||
// 0.0 0.0 0.0 1.0
|
|
||||||
let uniforms = uniform! {
|
|
||||||
matrix: [
|
|
||||||
[1.0, 0.0, 0.0, 0.0],
|
|
||||||
[0.0, 1.0, 0.0, 0.0],
|
|
||||||
[0.0, 0.0, 1.0, 0.0],
|
|
||||||
[x_offset, 0.0, 0.0, 1.0f32],
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
target.draw(
|
|
||||||
&vertex_buffer,
|
|
||||||
&indices,
|
|
||||||
&program,
|
|
||||||
&uniforms,
|
|
||||||
&Default::default()
|
|
||||||
).unwrap();
|
|
||||||
|
|
||||||
target.finish().unwrap();
|
|
||||||
},
|
|
||||||
_ => (),
|
|
||||||
},
|
|
||||||
// request a redraw ourselves once we've finished rendering
|
|
||||||
glium::winit::event::Event::AboutToWait => {
|
|
||||||
_window.request_redraw();
|
|
||||||
},
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,26 @@
|
||||||
use glium::implement_vertex;
|
use glium::implement_vertex;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub(crate) struct Vertex {
|
pub struct Vertex {
|
||||||
pub(crate) position: [f32; 2],
|
pub position: [f32; 2],
|
||||||
pub(crate) color: [f32; 3],
|
pub color: [f32; 3],
|
||||||
}
|
}
|
||||||
implement_vertex!(Vertex, position, color);
|
implement_vertex!(Vertex, position, color);
|
||||||
|
|
||||||
|
impl Vertex {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
position: [0.0, 0.0],
|
||||||
|
color: [0.0, 0.0, 0.0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn define_shape(v1: Vertex, v2: Vertex, v3: Vertex) -> Vec<Vertex> {
|
||||||
|
let shape = vec![
|
||||||
|
v1,
|
||||||
|
v2,
|
||||||
|
v3
|
||||||
|
];
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,3 +5,4 @@ edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
moonhare_engine = { path = "../moonhare_engine" }
|
moonhare_engine = { path = "../moonhare_engine" }
|
||||||
|
glium = "0.36.0"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,116 @@
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
|
||||||
|
use glium::{index::NoIndices, Frame, Program, VertexBuffer};
|
||||||
|
use glium::{program, uniform, Display, Surface};
|
||||||
|
use moonhare_engine::{game::Game, game_plugin::GamePlugin, vertex::Vertex};
|
||||||
|
|
||||||
|
struct PlaygroundGame {
|
||||||
|
t: f32,
|
||||||
|
shape: Vec<Vertex>,
|
||||||
|
vertex_buffer: VertexBuffer<Vertex>,
|
||||||
|
indices: NoIndices,
|
||||||
|
program: Program,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GamePlugin for PlaygroundGame {
|
||||||
|
fn init(&mut self) {
|
||||||
|
self.t = 0.0;
|
||||||
|
}
|
||||||
|
fn update(&mut self) {
|
||||||
|
self.t += 0.02;
|
||||||
|
// use 't' as an offset -> smooth animation
|
||||||
|
|
||||||
|
}
|
||||||
|
fn render(&mut self, target: &mut Frame) {
|
||||||
|
|
||||||
|
target.clear_color(
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
1.0
|
||||||
|
);
|
||||||
|
let x_offset = self.t.sin() * 0.5;
|
||||||
|
|
||||||
|
// Note: In OpenGL matrices are column-major
|
||||||
|
// Standard mathematical notation is row major:
|
||||||
|
// 1.0 0.0 0.0 x_offset
|
||||||
|
// 0.0 1.0 0.0 0.0
|
||||||
|
// 0.0 0.0 1.0 0.0
|
||||||
|
// 0.0 0.0 0.0 1.0
|
||||||
|
let uniforms = uniform! {
|
||||||
|
matrix: [
|
||||||
|
[1.0, 0.0, 0.0, 0.0],
|
||||||
|
[0.0, 1.0, 0.0, 0.0],
|
||||||
|
[0.0, 0.0, 1.0, 0.0],
|
||||||
|
[x_offset, 0.0, 0.0, 1.0f32],
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
target.draw(
|
||||||
|
&self.vertex_buffer,
|
||||||
|
&self.indices,
|
||||||
|
&self.program,
|
||||||
|
&uniforms,
|
||||||
|
&Default::default()
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
target.finish().unwrap();
|
||||||
|
}
|
||||||
|
fn cleanup(&mut self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("Hello World");
|
|
||||||
|
let mut game: Game = Game::new();
|
||||||
|
|
||||||
|
let shape = Vertex::define_shape(
|
||||||
|
Vertex { position: [-0.5, -0.5], color: [1.0, 0.0, 0.0] },
|
||||||
|
Vertex { position: [ 0.0, 0.5], color: [0.0, 1.0, 0.0] },
|
||||||
|
Vertex { position: [ 0.5, -0.25], color: [0.0, 0.0, 1.0] }
|
||||||
|
);
|
||||||
|
|
||||||
|
// "Upload" shape to the memory of the GPU (Vertex Buffer)
|
||||||
|
// Isn't strictly necessary but, makes tge drawing operation faster
|
||||||
|
let vertex_buffer = glium::VertexBuffer::new(&display, &shape).unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
// Complex shapes consist of hundreds/thousands of vertices -> need to have a list of vertices and tell OpenGL how to link these
|
||||||
|
// vertices together to obtain triangles.
|
||||||
|
// For only one triangle -> pass dummy marker to glium
|
||||||
|
// This line tells OpenGl that we don't use indices and instand want to draw a certain number of seperate triangles
|
||||||
|
let indices = glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList);
|
||||||
|
|
||||||
|
// (Simplified) Render Pipeline:
|
||||||
|
// Vertex Shader -> Fragment (Pixel) Shader
|
||||||
|
// uniform:
|
||||||
|
// value is set when we draw by passing its value to the draw function
|
||||||
|
// (easiest way is uniform! macro)
|
||||||
|
// Important to write matrix * vertex -> Matrix operations produce different results depending on the order
|
||||||
|
// out: defines a variable that is going to be passed along to the fragment shader
|
||||||
|
|
||||||
|
let vertex_shader_src = read_to_string("./shaders/vertex_shader.glsl").unwrap();
|
||||||
|
let fragment_shader_src = read_to_string("./shaders/fragment_shader.glsl").unwrap();
|
||||||
|
|
||||||
|
// send shader source code to glium
|
||||||
|
let program = glium::Program::from_source(
|
||||||
|
glium::Display::new(context, surface),
|
||||||
|
&vertex_shader_src,
|
||||||
|
&fragment_shader_src,
|
||||||
|
None
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
let mut pg_game = PlaygroundGame {
|
||||||
|
t: 0.0,
|
||||||
|
shape: shape,
|
||||||
|
vertex_buffer: vertex_buffer,
|
||||||
|
indices: indices,
|
||||||
|
program: program,
|
||||||
|
};
|
||||||
|
|
||||||
|
game.register_plugin(Box::new(pg_game));
|
||||||
|
|
||||||
|
game.run();
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue