#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
pub use nalgebra_glm as glm;
pub use egui_gl_glfw::egui;
pub use egui_gl_glfw::glfw;
use egui_gl_glfw::glfw::Context;
use game_context::node_manager::{Drawable, Node, NodeManager};
use game_context::nodes::camera::Camera3D;
use game_context::nodes::directional_light::DirectionalLight;
use game_context::nodes::model::Model;
use game_context::nodes::ui::UI;
use renderer::shader::Shader;
use renderer::Renderer;
pub mod game_context;
pub mod renderer;
use game_context::GameContext;
pub struct Engine {
pub context: GameContext,
}
const SAMPLES: u32 = 8;
impl Engine {
pub fn init(window_title: &str, window_width: u32, window_height: u32) -> Engine {
use glfw::fail_on_errors;
let mut glfw = glfw::init(fail_on_errors!()).unwrap();
glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3));
glfw.window_hint(glfw::WindowHint::OpenGlProfile(
glfw::OpenGlProfileHint::Core,
));
glfw.window_hint(glfw::WindowHint::DoubleBuffer(true));
glfw.window_hint(glfw::WindowHint::Resizable(false));
glfw.window_hint(glfw::WindowHint::Samples(Some(SAMPLES)));
let (mut window, events) = glfw
.create_window(
window_width,
window_height,
window_title,
glfw::WindowMode::Windowed,
)
.expect("Failed to create GLFW window.");
window.set_key_polling(true);
window.set_cursor_pos_polling(true);
window.set_mouse_button_polling(true);
window.set_scroll_polling(true);
window.set_framebuffer_size_polling(true);
window.make_current();
Renderer::context(&mut window);
Renderer::init();
Engine {
context: GameContext::new(events, glfw, window),
}
}
pub fn set_clear_color(&self, r: f32, g: f32, b: f32, a: f32) {
Renderer::set_clear_color([r, g, b, a]);
}
pub fn begin(&mut self) {
self.context.nodes.ready();
if self.context.nodes.active_camera.is_empty() {
eprintln!("Warning: No camera found in the scene");
}
if self.context.nodes.active_shader.is_empty() {
eprintln!("Warning: No shader found in the scene");
}
self.render_loop();
}
fn render_loop(&mut self) {
while !self.context.window.should_close() {
Renderer::clear();
{
let context = &mut self.context;
context.frame.update();
context.input.update();
}
{
let context = &mut self.context;
let lights: Vec<*mut DirectionalLight> = context
.nodes
.get_iter::<DirectionalLight>()
.map(|light| light as *const DirectionalLight as *mut DirectionalLight)
.collect();
for light in lights {
unsafe {
let nodes: &mut Vec<&mut Model> = &mut Vec::new();
for node in context.nodes.get_all_mut().values_mut() {
collect_models(&mut **node, nodes);
}
(*light).render_shadow_map(nodes);
let active_shader = context.nodes.active_shader.clone();
if let Some(shader) = context.nodes.shaders.get_mut(&active_shader) {
(*light).bind_uniforms(shader);
}
}
}
}
Renderer::viewport(
self.context.window.get_framebuffer_size().0,
self.context.window.get_framebuffer_size().1,
);
{
let nodes = self.context.nodes.get_iter::<UI>();
let nodes: Vec<*mut UI> = nodes.map(|node| node as *const UI as *mut UI).collect();
for ui in nodes {
unsafe {
(*ui).update(&mut self.context);
}
}
}
{
let nodes = &mut self.context.nodes as *mut NodeManager;
unsafe { (*nodes).behavior(&mut self.context) };
}
{
let context = &mut self.context;
let active_shader = context.nodes.active_shader.clone();
let active_camera = context.nodes.active_camera.clone();
let nodes: &mut Vec<*mut Model> = &mut Vec::new();
for node in context.nodes.get_all_mut().values_mut() {
collect_models(&mut **node, nodes);
}
let camera = context.nodes.get::<Camera3D>(&active_camera);
if let Some(camera) = camera {
let camera_ptr = camera as *const Camera3D as *mut Camera3D;
let shader_ptr = context
.nodes
.shaders
.get_mut(&active_shader)
.map(|s| &mut **s as *mut Shader);
if let Some(shader_ptr) = shader_ptr {
for model in nodes {
unsafe {
(**model).draw(&mut *shader_ptr, &*camera_ptr);
}
}
}
}
}
{
let nodes = self.context.nodes.get_iter::<UI>();
let nodes: Vec<*mut UI> = nodes.map(|node| node as *const UI as *mut UI).collect();
for ui in nodes {
unsafe {
(*ui).render(&mut self.context)
}
}
}
self.context.window.swap_buffers();
}
}
}
fn collect_models<T>(node: &mut dyn Node, models: &mut Vec<T>)
where
T: From<&'static mut Model>,
{
if let Some(model) = node.as_any_mut().downcast_mut::<Model>() {
models.push(T::from(unsafe { &mut *(model as *mut _) }));
}
for child in node.get_children().get_all_mut().values_mut() {
let child_node: &mut dyn Node = &mut **child;
collect_models(child_node, models);
}
}
impl From<&'static mut Model> for *mut Model {
fn from(model: &'static mut Model) -> Self {
model as *mut Model
}
}