| @@ -107,6 +107,14 @@ impl ArrayBuffer { | |||||
| }) | }) | ||||
| } | } | ||||
| pub fn bind_buffer_base(&self, index: gl::GLuint) { | |||||
| gl::bind_buffer_base(self.target.as_enum(), index, self.id); | |||||
| } | |||||
| pub fn bind_buffer_range(&self, index: gl::GLuint, offset: gl::GLintptr, size: gl::GLsizeiptr) { | |||||
| gl::bind_buffer_range(self.target.as_enum(), index, self.id, offset, size); | |||||
| } | |||||
| fn inner_map<T>(&self, access: gl::GLenum) -> Result<&mut [T], Error> { | fn inner_map<T>(&self, access: gl::GLenum) -> Result<&mut [T], Error> { | ||||
| let ptr = Error::err_if(&null(), gl::map_named_buffer(self.id, access))?; | let ptr = Error::err_if(&null(), gl::map_named_buffer(self.id, access))?; | ||||
| let count = self.size / size_of::<T>(); | let count = self.size / size_of::<T>(); | ||||
| @@ -14,8 +14,8 @@ pub enum Error { | |||||
| #[error("OpenGL Error: {0}")] | #[error("OpenGL Error: {0}")] | ||||
| GlError(gl::GLenum), | GlError(gl::GLenum), | ||||
| #[error("Error while compiling shader object: {0}")] | |||||
| ShaderCompile(String), | |||||
| #[error("Error while compiling shader object\n{code:}\n{error:}")] | |||||
| ShaderCompile { code: String, error: String }, | |||||
| #[error("Error while linking shader program: {0}")] | #[error("Error while linking shader program: {0}")] | ||||
| ShaderLink(String), | ShaderLink(String), | ||||
| @@ -6,6 +6,12 @@ use std::ops::{Deref, DerefMut, Mul}; | |||||
| use super::vector::{Element, Vector2, Vector3, Vector4}; | use super::vector::{Element, Vector2, Vector3, Vector4}; | ||||
| macro_rules! first_ptr { | |||||
| ($this:ident, $first:ident $(,$other:ident)*) => { | |||||
| unsafe { $this.$first.as_ptr() } | |||||
| }; | |||||
| } | |||||
| macro_rules! define_mat { | macro_rules! define_mat { | ||||
| ($Name:ident, $Vector:ident, $size:tt, $($T:ident => $i:tt => $f:ident),*) => { | ($Name:ident, $Vector:ident, $size:tt, $($T:ident => $i:tt => $f:ident),*) => { | ||||
| #[repr(C, packed)] | #[repr(C, packed)] | ||||
| @@ -18,6 +24,10 @@ macro_rules! define_mat { | |||||
| pub fn new($($f: $Vector<T>,)+) -> Self { | pub fn new($($f: $Vector<T>,)+) -> Self { | ||||
| Self { $($f,)+ } | Self { $($f,)+ } | ||||
| } | } | ||||
| pub fn as_ptr(&self) -> * const T { | |||||
| first_ptr!(self $(,$f)+) | |||||
| } | |||||
| } | } | ||||
| impl<T> Default for $Name<T> | impl<T> Default for $Name<T> | ||||
| @@ -139,17 +149,17 @@ define_mat!(Matrix2, Vector2, 2, T => 0 => axis_x, T => 1 => axis_y); | |||||
| define_mat!(Matrix3, Vector3, 3, T => 0 => axis_x, T => 1 => axis_y, T => 2 => axis_z); | define_mat!(Matrix3, Vector3, 3, T => 0 => axis_x, T => 1 => axis_y, T => 2 => axis_z); | ||||
| define_mat!(Matrix4, Vector4, 4, T => 0 => axis_x, T => 1 => axis_y, T => 2 => axis_z, T => 3 => position); | define_mat!(Matrix4, Vector4, 4, T => 0 => axis_x, T => 1 => axis_y, T => 2 => axis_z, T => 3 => position); | ||||
| type Matrix2f = Matrix2<gl::GLfloat>; | |||||
| type Matrix3f = Matrix3<gl::GLfloat>; | |||||
| type Matrix4f = Matrix4<gl::GLfloat>; | |||||
| pub type Matrix2f = Matrix2<gl::GLfloat>; | |||||
| pub type Matrix3f = Matrix3<gl::GLfloat>; | |||||
| pub type Matrix4f = Matrix4<gl::GLfloat>; | |||||
| type Matrix2d = Matrix2<gl::GLdouble>; | |||||
| type Matrix3d = Matrix3<gl::GLdouble>; | |||||
| type Matrix4d = Matrix4<gl::GLdouble>; | |||||
| pub type Matrix2d = Matrix2<gl::GLdouble>; | |||||
| pub type Matrix3d = Matrix3<gl::GLdouble>; | |||||
| pub type Matrix4d = Matrix4<gl::GLdouble>; | |||||
| type Matrix2i = Matrix2<gl::GLint>; | |||||
| type Matrix3i = Matrix3<gl::GLint>; | |||||
| type Matrix4i = Matrix4<gl::GLint>; | |||||
| pub type Matrix2i = Matrix2<gl::GLint>; | |||||
| pub type Matrix3i = Matrix3<gl::GLint>; | |||||
| pub type Matrix4i = Matrix4<gl::GLint>; | |||||
| /* Matrix2 */ | /* Matrix2 */ | ||||
| @@ -5,6 +5,7 @@ use std::str::from_utf8; | |||||
| use crate::{ | use crate::{ | ||||
| error::Error, | error::Error, | ||||
| matrix::Matrix4f, | |||||
| misc::{AsEnum, Bindable}, | misc::{AsEnum, Bindable}, | ||||
| }; | }; | ||||
| @@ -69,6 +70,12 @@ impl Program { | |||||
| pub fn id(&self) -> gl::GLuint { | pub fn id(&self) -> gl::GLuint { | ||||
| self.id | self.id | ||||
| } | } | ||||
| pub fn uniform(&self, location: gl::GLint, uniform: Uniform<'_>) { | |||||
| match uniform { | |||||
| Uniform::Matrix4f(v) => gl::uniform_matrix_4fv(location, 1, gl::FALSE, v.as_ptr()), | |||||
| } | |||||
| } | |||||
| } | } | ||||
| impl Drop for Program { | impl Drop for Program { | ||||
| @@ -99,10 +106,10 @@ impl Shader { | |||||
| let id = Error::err_if(&0, id)?; | let id = Error::err_if(&0, id)?; | ||||
| source.push('\0'); | source.push('\0'); | ||||
| let source = source.as_ptr() as *const i8; | |||||
| let source: *const *const i8 = &source; | |||||
| let source_ptr = source.as_ptr() as *const i8; | |||||
| let source_ptr: *const *const i8 = &source_ptr; | |||||
| gl::shader_source(id, 1, source, null()); | |||||
| gl::shader_source(id, 1, source_ptr, null()); | |||||
| gl::compile_shader(id); | gl::compile_shader(id); | ||||
| let mut success = 1; | let mut success = 1; | ||||
| @@ -124,7 +131,10 @@ impl Shader { | |||||
| let msg = from_utf8(&buffer)?; | let msg = from_utf8(&buffer)?; | ||||
| return Err(Error::ShaderCompile(msg.into())); | |||||
| return Err(Error::ShaderCompile { | |||||
| code: source, | |||||
| error: msg.into(), | |||||
| }); | |||||
| } | } | ||||
| Ok(Self { id }) | Ok(Self { id }) | ||||
| @@ -134,9 +144,16 @@ impl Shader { | |||||
| where | where | ||||
| P: AsRef<Path>, | P: AsRef<Path>, | ||||
| { | { | ||||
| let source = read_to_string(path)?; | |||||
| Self::from_string(type_, source) | |||||
| let source = read_to_string(&path)?; | |||||
| match Self::from_string(type_, source) { | |||||
| Ok(v) => Ok(v), | |||||
| Err(Error::ShaderCompile { code, error }) => Err(Error::ShaderCompile { | |||||
| code: format!("{}\n{}", path.as_ref().display(), code), | |||||
| error, | |||||
| }), | |||||
| Err(err) => Err(err), | |||||
| } | |||||
| } | } | ||||
| pub fn id(&self) -> gl::GLuint { | pub fn id(&self) -> gl::GLuint { | ||||
| @@ -174,3 +191,9 @@ impl AsEnum for Type { | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Uniform */ | |||||
| pub enum Uniform<'a> { | |||||
| Matrix4f(&'a Matrix4f), | |||||
| } | |||||
| @@ -4,6 +4,12 @@ use std::convert::{AsMut, AsRef}; | |||||
| use std::fmt::{Debug, Formatter, Result as FmtResult}; | use std::fmt::{Debug, Formatter, Result as FmtResult}; | ||||
| use std::ops::{Add, Deref, DerefMut, Div, Mul, Neg, Sub}; | use std::ops::{Add, Deref, DerefMut, Div, Mul, Neg, Sub}; | ||||
| macro_rules! first_ptr { | |||||
| ($this:ident, $first:ident $(,$other:ident)*) => { | |||||
| unsafe { &$this.$first } | |||||
| }; | |||||
| } | |||||
| macro_rules! define_vec { | macro_rules! define_vec { | ||||
| ($Name:ident, $size:tt, $($T:ident => $i:tt => $f:ident),*) => { | ($Name:ident, $size:tt, $($T:ident => $i:tt => $f:ident),*) => { | ||||
| #[repr(C, packed)] | #[repr(C, packed)] | ||||
| @@ -16,6 +22,11 @@ macro_rules! define_vec { | |||||
| pub fn new($($f: T,)+) -> Self { | pub fn new($($f: T,)+) -> Self { | ||||
| Self { $($f,)+ } | Self { $($f,)+ } | ||||
| } | } | ||||
| #[inline] | |||||
| pub fn as_ptr(&self) -> * const T { | |||||
| first_ptr!(self $(, $f)+) | |||||
| } | |||||
| } | } | ||||
| impl<T> Default for $Name<T> | impl<T> Default for $Name<T> | ||||
| @@ -139,17 +150,17 @@ define_vec!(Vector2, 2, T => 0 => x, T => 1 => y); | |||||
| define_vec!(Vector3, 3, T => 0 => x, T => 1 => y, T => 2 => z); | define_vec!(Vector3, 3, T => 0 => x, T => 1 => y, T => 2 => z); | ||||
| define_vec!(Vector4, 4, T => 0 => x, T => 1 => y, T => 2 => z, T => 3 => w); | define_vec!(Vector4, 4, T => 0 => x, T => 1 => y, T => 2 => z, T => 3 => w); | ||||
| type Vector2f = Vector2<gl::GLfloat>; | |||||
| type Vector3f = Vector3<gl::GLfloat>; | |||||
| type Vector4f = Vector4<gl::GLfloat>; | |||||
| pub type Vector2f = Vector2<gl::GLfloat>; | |||||
| pub type Vector3f = Vector3<gl::GLfloat>; | |||||
| pub type Vector4f = Vector4<gl::GLfloat>; | |||||
| type Vector2d = Vector2<gl::GLdouble>; | |||||
| type Vector3d = Vector3<gl::GLdouble>; | |||||
| type Vector4d = Vector4<gl::GLdouble>; | |||||
| pub type Vector2d = Vector2<gl::GLdouble>; | |||||
| pub type Vector3d = Vector3<gl::GLdouble>; | |||||
| pub type Vector4d = Vector4<gl::GLdouble>; | |||||
| type Vector2i = Vector2<gl::GLint>; | |||||
| type Vector3i = Vector3<gl::GLint>; | |||||
| type Vector4i = Vector4<gl::GLint>; | |||||
| pub type Vector2i = Vector2<gl::GLint>; | |||||
| pub type Vector3i = Vector3<gl::GLint>; | |||||
| pub type Vector4i = Vector4<gl::GLint>; | |||||
| /* Vector2 */ | /* Vector2 */ | ||||
| @@ -0,0 +1,125 @@ | |||||
| #![allow(dead_code)] | |||||
| use glc::{ | |||||
| array_buffer::{ArrayBuffer, Target, Usage}, | |||||
| error::Error, | |||||
| matrix::{Angle, Matrix4f}, | |||||
| vector::Vector4f, | |||||
| }; | |||||
| pub struct Camera { | |||||
| buffer: ArrayBuffer, | |||||
| } | |||||
| impl Camera { | |||||
| pub fn new() -> Result<Self, Error> { | |||||
| let mut buffer = ArrayBuffer::new(Target::UniformBuffer)?; | |||||
| buffer.buffer_data( | |||||
| Usage::StaticDraw, | |||||
| &[Data { | |||||
| projection: Matrix4f::identity(), | |||||
| view: Matrix4f::identity(), | |||||
| }], | |||||
| )?; | |||||
| Ok(Self { buffer }) | |||||
| } | |||||
| pub fn ortho( | |||||
| &mut self, | |||||
| left: f32, | |||||
| right: f32, | |||||
| bottom: f32, | |||||
| top: f32, | |||||
| near: f32, | |||||
| far: f32, | |||||
| ) -> Result<(), Error> { | |||||
| let mut data = self.buffer.map_mut::<Data>(true)?; | |||||
| data[0].projection = Matrix4f::new( | |||||
| Vector4f::new(2.0 / (right - left), 0.0, 0.0, 0.0), | |||||
| Vector4f::new(0.0, 2.0 / (top - bottom), 0.0, 0.0), | |||||
| Vector4f::new(0.0, 0.0, -2.0 / (far - near), 0.0), | |||||
| Vector4f::new( | |||||
| -(right + left) / (right - left), | |||||
| -(top + bottom) / (top - bottom), | |||||
| -(far + near) / (far - near), | |||||
| 1.0, | |||||
| ), | |||||
| ); | |||||
| Ok(()) | |||||
| } | |||||
| pub fn perspective( | |||||
| &mut self, | |||||
| fov: Angle<f32>, | |||||
| ratio: f32, | |||||
| near: f32, | |||||
| far: f32, | |||||
| ) -> Result<(), Error> { | |||||
| let top = near * fov.into_rad().into_inner().tan(); | |||||
| let bottom = -top; | |||||
| let right = ratio * top; | |||||
| let left = -right; | |||||
| let mut data = self.buffer.map_mut::<Data>(true)?; | |||||
| data[0].projection = Matrix4f::new( | |||||
| Vector4f::new(2.0 * near / (right - left), 0.0, 0.0, 0.0), | |||||
| Vector4f::new(0.0, 2.0 * near / (top - bottom), 0.0, 0.0), | |||||
| Vector4f::new( | |||||
| (right + left) / (right - left), | |||||
| (top + bottom) / (top - bottom), | |||||
| -(far + near) / (far - near), | |||||
| -1.0, | |||||
| ), | |||||
| Vector4f::new(0.0, 0.0, -2.0 * far * near / (far - near), 0.0), | |||||
| ); | |||||
| Ok(()) | |||||
| } | |||||
| pub fn set_projection(&mut self, m: Matrix4f) -> Result<(), Error> { | |||||
| let mut data = self.buffer.map_mut::<Data>(false)?; | |||||
| data[0].projection = m; | |||||
| Ok(()) | |||||
| } | |||||
| pub fn set_view(&mut self, m: Matrix4f) -> Result<(), Error> { | |||||
| let mut data = self.buffer.map_mut::<Data>(false)?; | |||||
| data[0].view = m; | |||||
| Ok(()) | |||||
| } | |||||
| pub fn update_view(&mut self, m: Matrix4f) -> Result<(), Error> { | |||||
| let mut data = self.buffer.map_mut::<Data>(false)?; | |||||
| data[0].view = data[0].view * m; | |||||
| Ok(()) | |||||
| } | |||||
| pub fn projection(&self) -> Result<Matrix4f, Error> { | |||||
| let data = self.buffer.map::<Data>()?; | |||||
| let ret = data[0].view; | |||||
| Ok(ret) | |||||
| } | |||||
| pub fn view(&self) -> Result<Matrix4f, Error> { | |||||
| let data = self.buffer.map::<Data>()?; | |||||
| let ret = data[0].view; | |||||
| Ok(ret) | |||||
| } | |||||
| pub fn bind(&self, index: gl::GLuint) -> Result<(), Error> { | |||||
| Error::checked(|| self.buffer.bind_buffer_base(index)) | |||||
| } | |||||
| } | |||||
| #[repr(C, packed)] | |||||
| struct Data { | |||||
| projection: Matrix4f, | |||||
| view: Matrix4f, | |||||
| } | |||||
| @@ -1,3 +1,4 @@ | |||||
| pub mod camera; | |||||
| pub mod events; | pub mod events; | ||||
| pub mod geometry; | pub mod geometry; | ||||
| pub mod window; | pub mod window; | ||||
| @@ -5,6 +5,7 @@ use glutin::{ | |||||
| window::WindowBuilder, | window::WindowBuilder, | ||||
| Api, ContextBuilder, ContextWrapper, GlProfile, GlRequest, PossiblyCurrent, | Api, ContextBuilder, ContextWrapper, GlProfile, GlRequest, PossiblyCurrent, | ||||
| }; | }; | ||||
| use log::info; | |||||
| use crate::Error; | use crate::Error; | ||||
| @@ -14,18 +15,33 @@ pub struct Window { | |||||
| impl Window { | impl Window { | ||||
| pub fn new<T>(event_loop: &EventLoop<T>) -> Result<Self, Error> { | pub fn new<T>(event_loop: &EventLoop<T>) -> Result<Self, Error> { | ||||
| let window_builder = WindowBuilder::new() | |||||
| .with_title("space-crush") | |||||
| .with_visible(true) | |||||
| .with_inner_size(PhysicalSize::new(WINDOW_WIDTH, WINDOW_HEIGHT)); | |||||
| let context = ContextBuilder::new() | |||||
| .with_double_buffer(Some(true)) | |||||
| .with_hardware_acceleration(Some(true)) | |||||
| .with_pixel_format(24, 8) | |||||
| .with_vsync(true) | |||||
| .with_gl(GlRequest::Specific(Api::OpenGl, (4, 5))) | |||||
| .with_gl_profile(GlProfile::Core) | |||||
| .build_windowed(window_builder, event_loop)?; | |||||
| let mut multisampling = [16u16, 8, 4, 2, 1, 0].iter(); | |||||
| let context = loop { | |||||
| let multisampling = match multisampling.next() { | |||||
| Some(multisampling) => multisampling, | |||||
| None => return Err(Error::UnableToCreateContext), | |||||
| }; | |||||
| info!("Create OpenGL context (multisampling={})", multisampling); | |||||
| let window_builder = WindowBuilder::new() | |||||
| .with_title("space-crush") | |||||
| .with_visible(true) | |||||
| .with_inner_size(PhysicalSize::new(WINDOW_WIDTH, WINDOW_HEIGHT)); | |||||
| let ret = ContextBuilder::new() | |||||
| .with_double_buffer(Some(true)) | |||||
| .with_hardware_acceleration(Some(true)) | |||||
| .with_pixel_format(24, 8) | |||||
| .with_multisampling(*multisampling) | |||||
| .with_vsync(true) | |||||
| .with_gl(GlRequest::Specific(Api::OpenGl, (4, 5))) | |||||
| .with_gl_profile(GlProfile::Core) | |||||
| .build_windowed(window_builder, event_loop); | |||||
| if let Ok(context) = ret { | |||||
| break context; | |||||
| } | |||||
| }; | |||||
| let window = context.window(); | let window = context.window(); | ||||
| let window_size = window.outer_size(); | let window_size = window.outer_size(); | ||||
| @@ -7,7 +7,7 @@ use specs::{Dispatcher, DispatcherBuilder, World}; | |||||
| use crate::Error; | use crate::Error; | ||||
| use misc::{events::Events, geometry::Geometry, window::Window}; | use misc::{events::Events, geometry::Geometry, window::Window}; | ||||
| use render::Background; | |||||
| use render::{Init, Test}; | |||||
| use systems::{State, StateUpdate}; | use systems::{State, StateUpdate}; | ||||
| pub struct App<'a, 'b> { | pub struct App<'a, 'b> { | ||||
| @@ -24,7 +24,8 @@ impl<'a, 'b> App<'a, 'b> { | |||||
| let mut dispatcher = DispatcherBuilder::new() | let mut dispatcher = DispatcherBuilder::new() | ||||
| .with(StateUpdate::new(world), "state_update", &[]) | .with(StateUpdate::new(world), "state_update", &[]) | ||||
| .with_thread_local(Background::new(world)?) | |||||
| .with_thread_local(Init::new(world)?) | |||||
| .with_thread_local(Test::new(world)?) | |||||
| .build(); | .build(); | ||||
| dispatcher.setup(world); | dispatcher.setup(world); | ||||
| @@ -2,19 +2,36 @@ use glc::{ | |||||
| misc::Bindable, | misc::Bindable, | ||||
| shader::{Program, Shader, Type}, | shader::{Program, Shader, Type}, | ||||
| }; | }; | ||||
| use log::error; | |||||
| use shrev::{EventChannel, ReaderId}; | use shrev::{EventChannel, ReaderId}; | ||||
| use specs::{ReadExpect, System, World}; | |||||
| use specs::{ReadExpect, System, World, WriteExpect}; | |||||
| use crate::Error; | use crate::Error; | ||||
| use super::super::misc::{events::WindowEvent, geometry::Geometry}; | |||||
| use super::super::misc::{camera::Camera, events::WindowEvent, geometry::Geometry}; | |||||
| pub struct Background { | |||||
| /* Global */ | |||||
| pub struct Global { | |||||
| pub camera: Camera, | |||||
| } | |||||
| impl Global { | |||||
| pub fn new() -> Result<Self, Error> { | |||||
| Ok(Self { | |||||
| camera: Camera::new()?, | |||||
| }) | |||||
| } | |||||
| } | |||||
| /* Init */ | |||||
| pub struct Init { | |||||
| program: Program, | program: Program, | ||||
| window_events_id: ReaderId<WindowEvent>, | window_events_id: ReaderId<WindowEvent>, | ||||
| } | } | ||||
| impl Background { | |||||
| impl Init { | |||||
| pub fn new(world: &mut World) -> Result<Self, Error> { | pub fn new(world: &mut World) -> Result<Self, Error> { | ||||
| let shaders = vec![ | let shaders = vec![ | ||||
| (Type::Vertex, include_str!("shader/noise.vert")), | (Type::Vertex, include_str!("shader/noise.vert")), | ||||
| @@ -29,6 +46,8 @@ impl Background { | |||||
| .fetch_mut::<EventChannel<WindowEvent>>() | .fetch_mut::<EventChannel<WindowEvent>>() | ||||
| .register_reader(); | .register_reader(); | ||||
| world.insert(Global::new()?); | |||||
| Ok(Self { | Ok(Self { | ||||
| program, | program, | ||||
| window_events_id, | window_events_id, | ||||
| @@ -36,17 +55,30 @@ impl Background { | |||||
| } | } | ||||
| } | } | ||||
| impl<'a> System<'a> for Background { | |||||
| impl<'a> System<'a> for Init { | |||||
| type SystemData = ( | type SystemData = ( | ||||
| WriteExpect<'a, Global>, | |||||
| ReadExpect<'a, Geometry>, | ReadExpect<'a, Geometry>, | ||||
| ReadExpect<'a, EventChannel<WindowEvent>>, | ReadExpect<'a, EventChannel<WindowEvent>>, | ||||
| ); | ); | ||||
| fn run(&mut self, (geometry, window_events): Self::SystemData) { | |||||
| fn run(&mut self, (mut global, geometry, window_events): Self::SystemData) { | |||||
| let events = window_events.read(&mut self.window_events_id); | let events = window_events.read(&mut self.window_events_id); | ||||
| for event in events { | for event in events { | ||||
| if let WindowEvent::Resize(w, h) = event { | if let WindowEvent::Resize(w, h) = event { | ||||
| gl::viewport(0, 0, *w as gl::GLsizei, *h as gl::GLsizei); | gl::viewport(0, 0, *w as gl::GLsizei, *h as gl::GLsizei); | ||||
| let w = *w as f32; | |||||
| let h = *h as f32; | |||||
| if let Err(err) = | |||||
| global | |||||
| .camera | |||||
| .ortho(-w / 2.0, w / 2.0, -h / 2.0, h / 2.0, -100.0, 100.0) | |||||
| { | |||||
| error!("Error while updating camera: {}", err); | |||||
| panic!("Error while updating camera: {}", err); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,3 +1,5 @@ | |||||
| mod background; | |||||
| mod init; | |||||
| mod test; | |||||
| pub use background::Background; | |||||
| pub use init::{Global, Init}; | |||||
| pub use test::Test; | |||||
| @@ -0,0 +1,8 @@ | |||||
| #version 450 core | |||||
| out vec4 Color; | |||||
| void main() | |||||
| { | |||||
| Color = vec4(1.0, 1.0, 1.0, 1.0); | |||||
| } | |||||
| @@ -0,0 +1,16 @@ | |||||
| #version 450 core | |||||
| layout (location = 0) in vec3 Position; | |||||
| layout (std140, binding = 0) uniform Camera | |||||
| { | |||||
| mat4 projection; | |||||
| mat4 view; | |||||
| }; | |||||
| layout (location = 1) uniform mat4 model; | |||||
| void main() | |||||
| { | |||||
| gl_Position = projection * view * model * vec4(Position, 1.0); | |||||
| } | |||||
| @@ -0,0 +1,55 @@ | |||||
| use glc::{ | |||||
| matrix::{Angle, Matrix4f}, | |||||
| misc::Bindable, | |||||
| shader::{Program, Shader, Type, Uniform}, | |||||
| vector::Vector3f, | |||||
| }; | |||||
| use specs::{ReadExpect, System, World}; | |||||
| use crate::Error; | |||||
| use super::{super::misc::geometry::Geometry, init::Global}; | |||||
| pub struct Test { | |||||
| program: Program, | |||||
| model: Matrix4f, | |||||
| } | |||||
| impl Test { | |||||
| pub fn new(world: &World) -> Result<Self, Error> { | |||||
| let shaders = vec![ | |||||
| (Type::Vertex, include_str!("shader/quad.vert")), | |||||
| (Type::Fragment, include_str!("shader/quad.frag")), | |||||
| ]; | |||||
| let program = Program::from_shaders_result( | |||||
| shaders | |||||
| .into_iter() | |||||
| .map(|(t, s)| Shader::from_string(t, s.into())), | |||||
| )?; | |||||
| let global = world.fetch::<Global>(); | |||||
| program.bind(); | |||||
| global.camera.bind(0)?; | |||||
| program.unbind(); | |||||
| Ok(Self { | |||||
| program, | |||||
| model: Matrix4f::scale(Vector3f::new(100.0, 100.0, 100.0)), | |||||
| }) | |||||
| } | |||||
| } | |||||
| impl<'a> System<'a> for Test { | |||||
| type SystemData = ReadExpect<'a, Geometry>; | |||||
| fn run(&mut self, geometry: Self::SystemData) { | |||||
| self.model = self.model * Matrix4f::rotate(Vector3f::new(0.0, 0.0, 1.0), Angle::Deg(0.01)); | |||||
| self.program.bind(); | |||||
| self.program.uniform(1, Uniform::Matrix4f(&self.model)); | |||||
| geometry.render_quad(); | |||||
| self.program.unbind(); | |||||
| } | |||||
| } | |||||
| @@ -12,6 +12,9 @@ pub enum Error { | |||||
| #[error("glutin Creation Error: {0}")] | #[error("glutin Creation Error: {0}")] | ||||
| GlutinCreationError(GlutinCreationError), | GlutinCreationError(GlutinCreationError), | ||||
| #[error("Unable to create OpenGL context")] | |||||
| UnableToCreateContext, | |||||
| } | } | ||||
| impl From<GlcError> for Error { | impl From<GlcError> for Error { | ||||