This commit is contained in:
deepCurse 2025-02-07 18:50:49 -04:00
parent 4c0fa9e6ee
commit 4b70b6f59f
Signed by: u1
GPG key ID: AD770D25A908AFF4
8 changed files with 569 additions and 210 deletions

View file

@ -10,7 +10,7 @@ title_name = "MineMod"
# assets = "somewhere" # TODO make this a build.rs output folder so we can use build.rs to manage vita assets
[profile.release]
opt-level = 2
opt-level = 3
lto = true
codegen-units = 1
# panic = "abort" # Vita platform doesnt support abort currently

View file

@ -1,13 +1,26 @@
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Instant;
use glam::Vec3;
use resources::*;
use crate::graphics_engines::Renderable;
//use crate::graphics_engines::Renderable;
pub mod resources;
#[derive(Debug)]
pub struct Cataclysm {
pub chunks:HashMap<(u32, u32, u32), CataclysmChunk>,
pub creation_time:Instant,
textures: Arc<ResourceTable<GraphicsTexture>>,
vertex_objects: Arc<ResourceTable<GraphicsVBO>>,
shader_objects: Arc<ResourceTable<GraphicsShader>>,
sounds: Arc<ResourceTable<AudioSFX>>,
music: Arc<ResourceTable<AudioMusic>>,
pub chunks: HashMap<(u32, u32, u32), CataclysmChunk>,
}
#[derive(Debug, Clone)]
pub struct CataclysmChunk {
pub simple_blocks:HashMap<(u8, u8, u8), SimpleBlock>,
pub fancy_blocks: HashMap<Vec3, FancyBlock>,
@ -22,7 +35,13 @@ impl Cataclysm {
pub fn new() -> Self {
Self {
chunks: HashMap::new()
creation_time: Instant::now(),
textures: ResourceTable::new(),
vertex_objects:ResourceTable::new(),
shader_objects:ResourceTable::new(),
sounds: ResourceTable::new(),
music: ResourceTable::new(),
chunks: HashMap::new(),
}
}
}
@ -30,33 +49,31 @@ impl Cataclysm {
impl CataclysmChunk {
pub fn new() -> Self {
Self {
simple_blocks: HashMap::new(),
simple_blocks:HashMap::new(),
fancy_blocks: HashMap::new(),
smart_blocks: HashMap::new(),
entities: vec![],
}
}
}
#[derive(Debug, Clone)]
pub struct SimpleBlock {}
pub struct SimpleBlock {
}
impl Renderable for SimpleBlock {
#[rustfmt::skip]
fn vertext_data<'a>() -> (&'a [f32], &'a [u32]) {
//impl Renderable for SimpleBlock {
#[rustfmt::skip]
fn vertext_data<'a>() -> (&'a [f32], &'a [u32]) {
(&[
-1.0, -1.0, 0.5, //0
1.0, -1.0, 0.5, //1
-1.0, 1.0, 0.5, //2
1.0, 1.0, 0.5, //3
-1.0, -1.0, -0.5, //4
1.0, -1.0, -0.5, //5
1.0, -1.0, -0.5, //5
-1.0, 1.0, -0.5, //6
1.0, 1.0, -0.5 //7
],
&[
//Top
],
&[
//Top
2, 6, 7,
2, 3, 7,
@ -80,25 +97,18 @@ impl Renderable for SimpleBlock {
4, 6, 7,
4, 5, 7
]
)
}
)
}
//}
#[derive(Debug, Clone)]
pub struct FancyBlock {
pub pos:Vec3,
}
#[derive(Debug, Clone)]
pub struct SmartBlock {
pub pos:Vec3,
}
#[derive(Debug, Clone)]
pub struct Entity {
pub pos:Vec3,
}
//pub enum ModelKind {
// Cube,
// Complex(),
//}
//pub struct ResourceReference {}

View file

@ -0,0 +1,172 @@
use ::std::collections::HashMap;
use ::std::sync::Arc;
use ::std::sync::Weak;
use ::std::sync::atomic::AtomicBool;
/// You should prefer cloning a resource out and replacing the resource when it becomes stale
#[derive(Debug)]
pub struct ResourceTable<T> {
resources:HashMap<String, Resource<T>>,
}
pub const DEFAULT_RESOURCE_NAME:&&'static str = &"resource.default";
impl<T> ResourceTable<T> {
pub fn add_resource(self: &Arc<Self>, name:&dyn ToString, thing:T) {
let resource = Resource {
inner:Arc::new(ResourceInner::new(thing)),
name: Arc::new(name.to_string()),
table:Arc::downgrade(&self),
};
}
// could be a macro? id prefer if it could work on self like it does for add_resource
pub fn upgrade(table:&Weak<Self>) -> Arc<Self> {
if let Some(table) = table.upgrade() {
table
} else {
panic!(
"A resource replace was attempted but it appears the owning table doesnt exist? Please ensure the owning table is not dropped, this is not expected to occur."
);
}
}
///
pub fn get_resource(&self, name:&dyn ToString) -> Option<Resource<T>> { self.resources.get(&name.to_string()).cloned() }
///
pub fn get_resource_or_default(&self, name:&dyn ToString) -> Resource<T> {
let resource = self.resources.get(&name.to_string());
// we do this instead of .unwrap_or(T) because unwrap_or is not lazy
// and will calculate T immediately whether it is needed or not
if let Some(resource) = resource {
resource.clone()
} else {
if let Some(resource) = self.get_resource(DEFAULT_RESOURCE_NAME) {
resource
} else {
unreachable!(
"Since resource tables get created with the `{DEFAULT_RESOURCE_NAME}` resource and you cannot remove it, this situation is impossible to occur."
)
}
}
}
}
impl<T:Default> ResourceTable<T> {
pub fn new() -> Arc<Self> {
let table = Arc::new(Self { resources:HashMap::new() });
table.add_resource(&"default", T::default());
table
}
}
// make an enum when mutable resources pop up?
// mutable resources are very strange since they are global
// instead any mutable *instances* of resource should be just that, an instance
// there is currently no valid reason for a mutable resource
// game logic has no business here
#[derive(Debug)]
struct Resource<T> {
inner: Arc<ResourceInner<T>>,
name: Arc<String>,
/// Fast access to the table the resource belongs to
pub table:Weak<ResourceTable<T>>,
}
impl<T> Resource<T> {
pub fn is_stale(&self) -> bool { self.inner.stale.load(std::sync::atomic::Ordering::SeqCst) }
// This permanently marks this resource as stale and all usages of it should be upgraded via the replace function
pub fn expire(&mut self) {
//self.table
self.inner.stale.store(true, std::sync::atomic::Ordering::SeqCst);
}
// This function will fetch the new resource under the same name, or will return itself as an error if there is none
// Typically you should prefer replace_or_default unless you have a specific reason to handle the failure/need to keep using the original on failure
pub fn replace(self) -> Result<Self, Self> {
let table = ResourceTable::upgrade(&self.table);
if let Some(resource) = table.get_resource(&self.name) {
Ok(resource)
} else {
Err(self)
}
}
}
impl<T:Default> Resource<T> {
pub fn replace_or_default(self) -> Self {
if let Some(table) = self.table.upgrade() {
table.get_resource_or_default(&self.name)
} else {
panic!(
"A resource replace was attempted but it appears the owning table doesnt exist? Please ensure the owning table is not dropped, this is not expected to occur."
);
}
}
}
impl<T> Clone for Resource<T> {
fn clone(&self) -> Self {
Self {
inner:self.inner.clone(),
name: self.name.clone(),
table:self.table.clone(),
}
}
}
#[derive(Debug)]
struct ResourceInner<T> {
stale:AtomicBool,
thing:T,
}
impl<T> ResourceInner<T> {
fn new(thing:T) -> Self {
Self {
stale:AtomicBool::new(false),
thing,
}
}
}
// should contain both source and compiled version?
#[derive(Debug)]
pub struct GraphicsShader {}
impl Default for GraphicsShader {
fn default() -> Self { todo!() }
}
#[derive(Debug)]
pub struct GraphicsTexture {}
impl Default for GraphicsTexture {
fn default() -> Self { todo!() }
}
#[derive(Debug)]
pub struct GraphicsVBO {}
impl Default for GraphicsVBO {
fn default() -> Self { todo!() }
}
#[derive(Debug)]
pub struct AudioSFX {}
impl Default for AudioSFX {
fn default() -> Self { todo!() }
}
#[derive(Debug)]
pub struct AudioMusic {}
impl Default for AudioMusic {
fn default() -> Self { todo!() }
}

View file

@ -21,28 +21,66 @@ pub mod opengl;
#[cfg(target_os = "vita")] pub mod gxm;
pub trait Renderable {
fn vertext_data<'a>() -> (&'a [f32], &'a [u32]);
}
type Vec2f = cgmath::Vector2<f32>;
type Vec3f = cgmath::Vector3<f32>;
type Vec4f = cgmath::Vector4<f32>;
type Vec2d = cgmath::Vector2<f64>;
type Vec3d = cgmath::Vector3<f64>;
type Vec4d = cgmath::Vector4<f64>;
type Mat2f = cgmath::Matrix2<f32>;
type Mat3f = cgmath::Matrix3<f32>;
type Mat4f = cgmath::Matrix4<f32>;
type Mat2d = cgmath::Matrix2<f64>;
type Mat3d = cgmath::Matrix3<f64>;
type Mat4d = cgmath::Matrix4<f64>;
#[repr(C)]
#[derive(Debug, Clone, Default)]
pub struct VertexData {
verts: Box<[f32]>,
indices:Box<[u32]>,
pub verts: Box<[Vertex]>,
pub indices:Box<[u32]>,
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct Vertex {
pub pos: Vec2f,
pub color:Vec3f,
}
impl Vertex {
pub const fn new(pos:Vec2f, color:Vec3f) -> Self { Self { pos, color } }
}
#[allow(unused)]
pub trait GraphicsCommander {
/// Used to halt all render calls and calculations
/// May deallocate graphics memory
fn suspend_rendering(&mut self);
/// Used to resume all render calls and calculations
/// May allocate graphics memory
fn resume_rendering(&mut self);
/// The first called function, used to register self to window and collect needed info from the system
fn initialize_controller_system(&mut self, window: &mut PWindow);
/// Returns a formatted multiline string detailing various aspects of the render system, meant to be immediately presented to the user through the engine
fn get_renderer_information(&self) -> String;
/// Used to load and potentially compile a shader
fn load_shader_program(&mut self);
// TODO cataclysm render object
// will need a reference to game engine objects
// replace with generic draw call? draw call will draw instructions to image, image may be framebuffer or not, allows gpu accelerated dynamic texture stuff
fn render(&mut self, window:&mut PWindow, cataclysm:&mut Cataclysm) -> Result<()>;
/// This function will clear all existing vbos and replace them with its own.
fn register_vbos(&mut self, data:&[VertexData]);
fn create_vxos(&mut self, data:&[VertexData]);
fn destroy_vxos(&mut self);
// make generic for assets?
fn register_texture(&mut self);
fn destroy_texture(&mut self);
@ -52,6 +90,14 @@ pub trait GraphicsCommander {
fn exit(&mut self);
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
struct UniformBufferObject {
model:Mat4f,
view: Mat4f,
proj: Mat4f,
}
#[allow(unused)]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub enum GMode {

View file

@ -1,14 +1,15 @@
use crate::cataclysm::Cataclysm;
use crate::graphics_engines::Vertex;
use super::GraphicsCommander;
use super::Mat4f;
use super::UniformBufferObject;
use anyhow::Result;
use glam::vec2;
use glam::vec3;
use glam::Vec2;
use glam::Vec3;
use cgmath::point3;
use cgmath::vec3;
use cgmath::Deg;
use glfw::Context;
use glfw::PWindow;
@ -21,7 +22,7 @@ pub mod gl {
pub use Gles2 as Gl;
}
impl GraphicsCommander for Renderer {
impl GraphicsCommander for CataclysmOGL {
fn suspend_rendering(&mut self) {
}
@ -29,23 +30,51 @@ impl GraphicsCommander for Renderer {
}
fn render(&mut self, window:&mut glfw::PWindow, cataclysm:&mut Cataclysm) -> anyhow::Result<()> {
let model = Mat4f::from_axis_angle(vec3(0.0, 0.0, 1.0), Deg(45.0) * cataclysm.creation_time.elapsed().as_secs_f32());
let view = Mat4f::look_at_rh(point3(2.0, 5.0, 2.0), point3(0.0, 0.0, 0.0), vec3(0.0, 0.0, 1.0));
let mut proj = cgmath::perspective(
Deg(45.0),
self.data.swapchain_extent.width as f32 / self.data.swapchain_extent.height as f32,
0.1,
10.0,
);
// cgmath was made with opengl in mind, this fixes it to work with vulkan
proj[1][1] *= -1.0;
let ubo = UniformBufferObject { model, view, proj };
//let memory = self.device.map_memory(
// self.data.uniform_buffers_memory[image_index],
// 0,
// size_of::<UniformBufferObject>() as u64,
// vk::MemoryMapFlags::empty(),
//)?;
//memcpy(&ubo, memory.cast(), 1);
//self.device.unmap_memory(self.data.uniform_buffers_memory[image_index]);
let (red, green, blue, alpha) = (0.0125, 0.0094, 0.0071, 1.0);
trace!("Clearing screen with color {red}|{green}|{blue}|{alpha}.");
unsafe {
self.gl.UseProgram(self.program);
trace!("Bind.");
self.gl.BindVertexArray(self.vao);
self.gl.BindBuffer(gl::ARRAY_BUFFER, self.vbo);
trace!("ClearColor.");
//info!("Clearing screen with color {red}|{green}|{blue}|{alpha}.");
self.gl.ClearColor(red, green, blue, alpha);
trace!("Clear.");
self.gl.Clear(gl::COLOR_BUFFER_BIT);
trace!("DrawArrays.");
self.gl.DrawArrays(gl::TRIANGLES, 0, 3);
for vxo in &self.vxos {
//info!("Bind.");
self.gl.BindVertexArray(vxo.0);
for vbo in &vxo.1 {
self.gl.BindBuffer(gl::ARRAY_BUFFER, *vbo);
//info!("DrawArrays.");
self.gl.DrawArrays(gl::TRIANGLES, 0, 3);
}
}
}
trace!("Done clearing screen.");
window.swap_buffers();
@ -56,62 +85,75 @@ impl GraphicsCommander for Renderer {
fn destroy_texture(&mut self) { todo!() }
//fn cleanup(&mut self) { todo!() }
fn exit(&mut self) {
trace!("Destroying OpenGL instance.");
info!("Destroying OpenGL instance.");
unsafe {
self.gl.DeleteProgram(self.program);
for vbo in self.vbos.iter().take(self.vbos.len()) {
self.gl.DeleteBuffers(1, vbo);
}
self.gl.DeleteVertexArrays(1, &self.vao);
self.destroy_vxos();
}
}
fn register_vbos(&mut self, data:&[super::VertexData]) {
fn create_vxos(&mut self, data:&[super::VertexData]) {
for data in data {
trace!("Creating OpenGL VAO.");
unsafe {
info!("Creating OpenGL VAO.");
let vao = unsafe {
let mut vao = std::mem::zeroed();
self.gl.GenVertexArrays(1, &mut vao);
self.gl.BindVertexArray(vao);
}
trace!("Creating OpenGL VBO.");
unsafe {
vao
};
info!("Creating OpenGL VBO for vertices.");
let vbo = unsafe {
let mut vbo = std::mem::zeroed();
self.gl.GenBuffers(1, &mut vbo);
self.gl.BindBuffer(gl::ARRAY_BUFFER, vbo);
self.gl.BufferData(
gl::ARRAY_BUFFER,
(VERTEX_DATA.len() * std::mem::size_of::<Vertex>()) as gl::types::GLsizeiptr,
VERTEX_DATA.as_ptr() as *const _,
dbg!(data.verts.len() * std::mem::size_of::<Vertex>()) as gl::types::GLsizeiptr,
data.verts.as_ptr() as *const _,
gl::STATIC_DRAW,
);
}
vbo
};
unsafe {
trace!("Applying shader attributes.");
let pos_attrib = self.gl.GetAttribLocation( self.program, b"position\0".as_ptr() as *const _);
let color_attrib = self.gl.GetAttribLocation(self.program, b"color\0".as_ptr() as *const _);
let (pos, col) = unsafe {
info!("Applying shader attributes.");
let pos_attrib = self.gl.GetAttribLocation(self.program, b"position\0".as_ptr() as *const _);
self.gl.EnableVertexAttribArray(pos_attrib as gl::types::GLuint);
self.gl.VertexAttribPointer(
pos_attrib as gl::types::GLuint,
2,
gl::FLOAT,
0,
std::mem::size_of::<Vertex>() as gl::types::GLsizei,
gl::FALSE,
std::mem::size_of::<f32>() as gl::types::GLsizei,
std::ptr::null(),
);
let color_attrib = self.gl.GetAttribLocation(self.program, b"color\0".as_ptr() as *const _);
self.gl.EnableVertexAttribArray(color_attrib as gl::types::GLuint);
self.gl.VertexAttribPointer(
color_attrib as gl::types::GLuint,
3,
gl::FLOAT,
0,
5 * std::mem::size_of::<f32>() as gl::types::GLsizei,
gl::FALSE,
std::mem::size_of::<f32>() as gl::types::GLsizei,
(2 * std::mem::size_of::<f32>()) as *const () as *const _,
);
self.gl.EnableVertexAttribArray(pos_attrib as gl::types::GLuint);
self.gl.EnableVertexAttribArray(color_attrib as gl::types::GLuint);
(pos_attrib, color_attrib)
};
self.vxos.push((vao, vec![vbo]));
}
}
fn destroy_vxos(&mut self) {
unsafe {
for _ in 0..self.vxos.len() {
let vxo = self.vxos.remove(0);
self.gl.DeleteVertexArrays(1, &vxo.0);
for vbo in vxo.1.iter().take(vxo.1.len()) {
self.gl.DeleteBuffers(1, vbo);
}
}
}
}
@ -120,17 +162,18 @@ impl GraphicsCommander for Renderer {
use std::ffi::CStr;
use std::ops::Deref;
pub struct Renderer {
type VAO = gl::types::GLuint;
type VBO = gl::types::GLuint;
pub struct CataclysmOGL {
program:gl::types::GLuint,
vao: gl::types::GLuint,
vbos: Vec<gl::types::GLuint>,
//vbo: gl::types::GLuint,
vxos: Vec<(VAO, Vec<VBO>)>,
gl: gl::Gl,
}
impl Renderer {
impl CataclysmOGL {
pub fn create(window:&mut PWindow) -> Result<Self> {
trace!("Creating OpenGL renderer instance.");
info!("Creating OpenGL renderer instance.");
unsafe {
let gl = gl::Gl::load_with(|symbol| window.get_proc_address(symbol));
@ -146,26 +189,29 @@ impl Renderer {
info!("Shaders version on {}", shaders_version.to_string_lossy());
}
trace!("Loading shaders.");
info!("Loading shaders.");
let vertex_shader = create_shader(&gl, gl::VERTEX_SHADER, VERTEX_SHADER_SOURCE);
let fragment_shader = create_shader(&gl, gl::FRAGMENT_SHADER, FRAGMENT_SHADER_SOURCE);
trace!("Creating OpenGL shader program.");
info!("Creating OpenGL shader program.");
let program = gl.CreateProgram();
gl.AttachShader(program, vertex_shader);
gl.AttachShader(program, fragment_shader);
gl.LinkProgram(program);
gl.UseProgram(program);
trace!("Deleting shader objects.");
info!("Deleting shader objects.");
gl.DeleteShader(vertex_shader);
gl.DeleteShader(fragment_shader);
trace!("OpenGL renderer instance created.");
Ok(Self { program, vao, vbos:vec![], gl })
info!("Linking shader program.");
gl.LinkProgram(program);
info!("OpenGL renderer instance created.");
Ok(Self {
program,
vxos:vec![/*(vao, vec![vbo])*/],
gl,
})
}
}
@ -176,7 +222,7 @@ impl Renderer {
}
}
impl Deref for Renderer {
impl Deref for CataclysmOGL {
type Target = gl::Gl;
fn deref(&self) -> &Self::Target { &self.gl }
@ -196,53 +242,6 @@ fn get_gl_string(gl:&gl::Gl, variant:gl::types::GLenum) -> Option<&'static CStr>
}
}
#[repr(C)]
#[derive(Copy, Clone, Debug)]
struct Vertex {
pos: Vec2,
color:Vec3,
}
#[rustfmt::skip]
static VERTEX_DATA: [Vertex; 3] = [
//-0.5, -0.5, 1.0, 0.0, 0.0,
// 0.0, 0.5, 0.0, 1.0, 0.0,
// 0.5, -0.5, 0.0, 0.0, 1.0,
Vertex::new(vec2(-0.5, -0.5), vec3(0.3, 0.0, 1.0)),
Vertex::new(vec2(0.5, 0.5), vec3(0.3, 0.0, 1.0)),
Vertex::new(vec2(0.5, -0.5), vec3(0.3, 0.0, 1.0)),
//Vertex::new(vec2(-0.5, 0.5), vec3(0.3, 0.0, 1.0)),
];
impl Vertex {
const fn new(pos:Vec2, color:Vec3) -> Self { Self { pos, color } }
//fn binding_description() -> vk::VertexInputBindingDescription {
// vk::VertexInputBindingDescription::builder()
// .binding(0)
// .stride(size_of::<Vertex>() as u32)
// .input_rate(vk::VertexInputRate::VERTEX)
// .build()
//}
//fn attribute_descriptions() -> [vk::VertexInputAttributeDescription; 2] {
// let pos = vk::VertexInputAttributeDescription::builder()
// .binding(0)
// .location(0)
// .format(vk::Format::R32G32_SFLOAT)
// .offset(0)
// .build();
// let color = vk::VertexInputAttributeDescription::builder()
// .binding(0)
// .location(1)
// .format(vk::Format::R32G32B32_SFLOAT)
// .offset(size_of::<Vec2f>() as u32)
// .build();
// [pos, color]
//}
}
const VERTEX_SHADER_SOURCE2:&[u8] = b"
#version 450

View file

@ -1,12 +1,13 @@
use anyhow::Result;
use anyhow::anyhow;
use cgmath::Deg;
use cgmath::point3;
use cgmath::vec2;
use cgmath::vec3;
use cgmath::Deg;
use glfw::PWindow;
use log::*;
use std::collections::HashSet;
@ -33,6 +34,9 @@ use vulkanalia::vk::KhrSwapchainExtension;
use crate::cataclysm::Cataclysm;
use super::GraphicsCommander;
use super::Mat4f;
use super::Vec2f;
use super::Vec3f;
const VALIDATION_ENABLED:bool = cfg!(debug_assertions); // add env support?
const VALIDATION_LAYER:vk::ExtensionName = vk::ExtensionName::from_bytes(b"VK_LAYER_KHRONOS_validation");
@ -44,21 +48,11 @@ const VK_APPLICATION_NAME:&'static [u8; 8] = b"minemod\0";
const VK_ENGINE_NAME:&'static [u8; 10] = b"cataclysm\0";
const MAX_FRAMES_IN_FLIGHT:usize = 2;
// static VERTICES:[Vertex; 3] = [
// Vertex::new(vec2(0.0, -0.5), vec3(0.3, 0.0, 1.0)),
// Vertex::new(vec2(0.5, 0.5), vec3(0.3, 0.0, 1.0)),
// Vertex::new(vec2(-0.5, 0.5), vec3(0.3, 0.0, 1.0)),
// ];
static VERTICES:[Vertex; 4] = [
const VERTICES:[Vertex; 4] = [
Vertex::new(vec2(-0.5, -0.5), vec3(0.3, 0.0, 1.0)),
Vertex::new(vec2(0.5, -0.5), vec3(0.3, 0.0, 1.0)),
Vertex::new(vec2(0.5, 0.5), vec3(0.3, 0.0, 1.0)),
Vertex::new(vec2(-0.5, 0.5), vec3(0.3, 0.0, 1.0)),
// Vertex::new(vec2(-1.0, -1.0),vec3(0.3, 0.0, 1.0)),
// Vertex::new(vec2(1.0, -1.0), vec3(0.3, 0.0, 1.0)),
// Vertex::new(vec2(1.0, 1.0), vec3(0.3, 0.0, 1.0)),
// Vertex::new(vec2(-1.0, 1.0), vec3(0.3, 0.0, 1.0)),
];
const INDICES:&[u16] = &[0, 1, 2, 2, 3, 0];
@ -85,9 +79,13 @@ pub(crate) struct App {
}
impl GraphicsCommander for App {
fn suspend_rendering(&mut self) { info!("SUSPEND") }
fn suspend_rendering(&mut self) {
warn!("Unimplemented!");
}
fn resume_rendering(&mut self) { info!("RESUME") }
fn resume_rendering(&mut self) {
warn!("Unimplemented!");
}
/// Renders a frame for our Vulkan app.
fn render(&mut self, window:&mut PWindow, cataclysm:&mut Cataclysm) -> Result<()> {
@ -159,11 +157,21 @@ impl GraphicsCommander for App {
}
}
fn register_vbos(&mut self, data:&[super::VertexData]) { todo!() }
fn create_vxos(&mut self, data:&[super::VertexData]) {
warn!("Unimplemented!");
}
fn register_texture(&mut self) { todo!() }
fn destroy_vxos(&mut self) {
warn!("Unimplemented!");
}
fn destroy_texture(&mut self) { todo!() }
fn register_texture(&mut self) {
warn!("Unimplemented!");
}
fn destroy_texture(&mut self) {
warn!("Unimplemented!");
}
fn exit(&mut self) {
info!("Destroying Vulkan instance.");

View file

@ -63,3 +63,5 @@ fn init_logging() {
// test BCn vs raw formats
// research why texture atlases exist, it seems like an easy way to reduce the allocation calls since they are limited, and it seems to provide better usage of memory overall
// multirender system where both vulkan and opengl are active at once, each rendering half of the screen, can use to compare the two systems while working on them

View file

@ -1,16 +1,24 @@
use anyhow::Result;
use cgmath::vec2;
use cgmath::vec3;
use glfw::Action;
use glfw::Context;
use glfw::Key;
use log::*;
use std::collections::HashMap;
use crate::cataclysm::Cataclysm;
use crate::cataclysm::CataclysmChunk;
use crate::cataclysm::SimpleBlock;
use crate::graphics_engines::GMode;
use crate::graphics_engines::GraphicsCommander;
use crate::graphics_engines::Vertex;
use crate::graphics_engines::VertexData;
//#[cfg(target_os = "linux")] mod linux;
//#[cfg(target_os = "linux")] pub use linux::*;
@ -22,6 +30,15 @@ use crate::graphics_engines::GraphicsCommander;
pub const WINDOW_TITLE:&'static str = "MineMod";
pub const WINDOW_DECORATION_LEFT:bool = false;
pub fn shutdown_handler(sender:std::sync::mpsc::Sender<()>) {
static SHUTDOWN_COUNT:std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(1);
if SHUTDOWN_COUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst) >= 3 {
warn!("3 exit events have piled up. Forcing exit.");
std::process::exit(-1);
}
sender.send(()).expect("Failed to send shutdown signal");
}
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
crate::init_logging();
@ -29,26 +46,25 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let (shutdown_tx, shutdown_rx) = std::sync::mpsc::channel();
ctrlc::set_handler(move || {
shutdown_tx.send(()).expect("Failed to send shutdown signal");
})
.expect("Error setting Ctrl-C handler");
{
let tx = shutdown_tx.clone();
ctrlc::set_handler(move || shutdown_handler(tx.clone())).expect("Error setting Ctrl-C handler");
}
//std::thread::sleep(std::time::Duration::from_secs(10));
let mut glfw = glfw::init(|err, string| match err {
// we dont give a shit because we supply our own render system
glfw::Error::NoWindowContext /*| glfw::Error::NoError*/ => warn!("GLFW Error: {err} {string}"),
glfw::Error::NoWindowContext => warn!("GLFW Error: {err} {string}"),
_ => panic!("GLFW Error! {err}, {string}"),
})?;
let graphics_mode = GMode::OpenGL;
let mut graphics_mode = GMode::OpenGL;
// if we do not want to use opengl, disable it
if graphics_mode != GMode::OpenGL {
glfw.window_hint(glfw::WindowHint::ClientApi(glfw::ClientApiHint::NoApi));
}
if let GMode::OpenGL = graphics_mode {}
let (mut window, events) = if let Some(glfw) = glfw.create_window(1024, 768, &WINDOW_TITLE, glfw::WindowMode::Windowed) {
glfw
} else {
@ -57,21 +73,115 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
window.set_key_polling(true);
window.make_current();
window.set_close_callback(move |_| shutdown_handler(shutdown_tx.clone()));
let mut cmd = /*Some(*/make_graphics_commander(graphics_mode, &mut window)?/*)*/;
let mut graphics_commander = make_graphics_commander(graphics_mode, &mut window)?;
let mut opengl_cache = None;
// Register models
let verts:Box<[Vertex]> = Box::new([
Vertex::new(vec2(-0.5, -0.5), vec3(0.3, 0.0, 1.0)),
Vertex::new(vec2(0.5, -0.5), vec3(0.3, 0.0, 1.0)),
Vertex::new(vec2(0.5, 0.5), vec3(0.3, 0.0, 1.0)),
Vertex::new(vec2(-0.5, 0.5), vec3(0.3, 0.0, 1.0)),
]);
graphics_commander.create_vxos(&[VertexData { verts, ..Default::default() }]);
// create game world
let mut game_world = Cataclysm::new();
game_world.chunks.insert((0, 0, 0), CataclysmChunk::new());
//let mut inners = vec![];
//let mut mids = vec![];
//let mut outers = vec![];
for x in 0..Cataclysm::CHUNK_SIZE {
for y in 0..Cataclysm::CHUNK_SIZE {
for z in 0..Cataclysm::CHUNK_SIZE {
game_world.chunks.get_mut(&(0, 0, 0)).unwrap().simple_blocks.insert((x, y, z), SimpleBlock {});
let mut threads = vec![];
let (sender, recv) = std::sync::mpsc::channel();
let instant = std::time::Instant::now();
//let mut count = 0;
const RANGE:std::ops::Range<u32> = 0..1;
for x in RANGE {
'ml: loop {
if threads.len() >= 4 {
//info!("MAX");
recv.recv().unwrap();
break 'ml;
} else {
break 'ml;
}
}
let sender = sender.clone();
threads.push(std::thread::spawn(move || {
info!("Spawned");
let mut chunks:HashMap<(u32, u32, u32), CataclysmChunk> = HashMap::new();
let instant = std::time::Instant::now();
for y in RANGE {
//let instant = std::time::Instant::now();
for z in RANGE {
//let instant = std::time::Instant::now();
chunks.insert((x, y, z), CataclysmChunk::new());
for bx in 0..Cataclysm::CHUNK_SIZE {
for by in 0..Cataclysm::CHUNK_SIZE {
for bz in 0..Cataclysm::CHUNK_SIZE {
chunks.get_mut(&(x, y, z)).unwrap().simple_blocks.insert((bx, by, bz), SimpleBlock {});
//count += 1;
}
}
}
//inners.push(std::time::Instant::now() - instant);
}
//mids.push(std::time::Instant::now() - instant);
}
//outers.push(std::time::Instant::now() - instant);
sender.send(()).unwrap();
chunks
}));
}
//dbg!(count);
let mut master_chunkmap:HashMap<(u32, u32, u32), CataclysmChunk> = HashMap::new();
for t in threads {
let chunks = t.join().unwrap();
for (_id, (key, value)) in chunks.iter().enumerate() {
if let Some(val) = master_chunkmap.insert(*key, value.clone()) {
warn!("Existing value present! {:?}", val);
}
}
}
game_world.chunks = master_chunkmap;
//{
// let mut avg = 0.0;
// for i in &inners {
// avg += i.as_secs_f32();
// }
// avg = avg / inners.len() as f32;
// info!("inners:{avg}");
// avg = 0.0;
// for i in &mids {
// avg += i.as_secs_f32();
// }
// avg = avg / mids.len() as f32;
// info!("mids:{avg}");
// avg = 0.0;
// for i in &outers {
// avg += i.as_secs_f32();
// }
// avg = avg / outers.len() as f32;
// info!("outers:{avg}");
//}
info!("MASTER: {}", (std::time::Instant::now() - instant).as_secs_f32());
//return Ok(());
let mut graphics_commander = Some(graphics_commander);
//'mainloop: while !window.should_close() {
loop {
if shutdown_rx.try_recv().is_ok() {
@ -79,11 +189,8 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
window.set_should_close(true);
}
// Swap front and back buffers
//window.swap_buffers(); // cannot be used
// dont flood the logs
//std::thread::sleep(Duration::from_secs(1));
//std::thread::sleep(std::time::Duration::from_secs(1));
trace!("Polling GLFW events.");
// Poll for and process events
@ -93,38 +200,53 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
info!("GLFW Event: {:?}", event);
match event {
//glfw::WindowEvent::FramebufferSize(x, y) => {},
//glfw::WindowEvent::Close => window.set_should_close(true),
// minimize? doesnt appear to be
glfw::WindowEvent::Iconify(e) =>
//if let Some(cmd) = graphics_commander.as_mut() {
if e {
cmd.suspend_rendering();
} else {
cmd.resume_rendering();
if let Some(graphics_commander) = graphics_commander.as_mut() {
if e {
graphics_commander.suspend_rendering();
} else {
graphics_commander.resume_rendering();
}
},
//},
glfw::WindowEvent::Key(key, _, Action::Press, _) => match key {
Key::Escape | Key::Q => window.set_should_close(true),
//Key::E => {
//if let Some(cmd) = graphics_commander.as_mut() {
// cmd.exit();
//}
//let _gc = graphics_commander.take();
//match graphics_mode {
// GMode::Vulkan => graphics_mode = GMode::OpenGL,
// GMode::OpenGL => graphics_mode = GMode::Vulkan,
// #[cfg(target_os = "macos")]
// GMode::Metal => todo!(),
// #[cfg(target_os = "windows")]
// GMode::DirectX => todo!(),
//}
//graphics_commander = Some(make_graphics_commander(graphics_mode, &mut window)?);
//},
Key::E => {
match graphics_mode {
GMode::Vulkan => {
info!("v1 mode{:?} cmd{} cache{}", graphics_mode, graphics_commander.is_some(), opengl_cache.is_some());
if let Some(mut graphics_commander) = graphics_commander.take() {
graphics_commander.exit();
}
info!("v2 mode{:?} cmd{} cache{}", graphics_mode, graphics_commander.is_some(), opengl_cache.is_some());
graphics_mode = GMode::OpenGL;
graphics_commander = opengl_cache.take();
if graphics_commander.is_none() {
error!("OpenGL was expected but not present");
graphics_commander = Some(make_graphics_commander(graphics_mode, &mut window)?);
}
info!("v3 mode{:?} cmd{} cache{}", graphics_mode, graphics_commander.is_some(), opengl_cache.is_some());
},
GMode::OpenGL => {
info!("o1 mode{:?} cmd{} cache{}", graphics_mode, graphics_commander.is_some(), opengl_cache.is_some());
//graphics_commander.clean();
opengl_cache = graphics_commander.take();
info!("o2 mode{:?} cmd{} cache{}", graphics_mode, graphics_commander.is_some(), opengl_cache.is_some());
graphics_mode = GMode::Vulkan;
graphics_commander = Some(make_graphics_commander(graphics_mode, &mut window)?);
info!("o3 mode{:?} cmd{} cache{}", graphics_mode, graphics_commander.is_some(), opengl_cache.is_some());
},
#[cfg(target_os = "macos")]
GMode::Metal => todo!(),
#[cfg(target_os = "windows")]
GMode::DirectX => todo!(),
}
},
_ => (),
},
event => {
dbg!(event);
},
_ => (),
}
}
@ -133,17 +255,17 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
break;
}
//if let Some(cmd) = graphics_commander.as_mut() {
trace!("Rendering.");
//cmd.render_simple_blocks(game_world.chunks.get_mut(&(0, 0, 0)).unwrap().simple_blocks);
cmd.render(&mut window, &mut game_world)?;
//}
if let Some(graphics_commander) = graphics_commander.as_mut() {
trace!("Rendering.");
//cmd.render_simple_blocks(game_world.chunks.get_mut(&(0, 0, 0)).unwrap().simple_blocks);
graphics_commander.render(&mut window, &mut game_world)?;
}
}
//if let Some(cmd) = graphics_commander.as_mut() {
info!("Closing GC instance.");
cmd.exit();
//}
if let Some(graphics_commander) = graphics_commander.as_mut() {
info!("Closing GC instance.");
graphics_commander.exit();
}
info!("Exiting.");
Ok(())
@ -152,7 +274,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
fn make_graphics_commander(graphics_mode:GMode, window:&mut glfw::PWindow) -> Result<Box<dyn GraphicsCommander>> {
Ok(match graphics_mode {
GMode::Vulkan => Box::new(unsafe { crate::graphics_engines::vulkan_gc::App::create(&window)? }),
GMode::OpenGL => Box::new(crate::graphics_engines::opengl::Renderer::create(window)?),
GMode::OpenGL => Box::new(crate::graphics_engines::opengl::CataclysmOGL::create(window)?),
#[cfg(target_os = "macos")]
GMode::Metal => todo!(),
#[cfg(target_os = "windows")]