Pārlūkot izejas kodu

Implemented camera and basic quad rendering

raster
Bergmann89 pirms 5 gadiem
vecāks
revīzija
feee8f1be2
15 mainītis faili ar 360 papildinājumiem un 49 dzēšanām
  1. +8
    -0
      glc/src/array_buffer.rs
  2. +2
    -2
      glc/src/error.rs
  3. +19
    -9
      glc/src/matrix.rs
  4. +30
    -7
      glc/src/shader.rs
  5. +20
    -9
      glc/src/vector.rs
  6. +125
    -0
      space-crush/src/app/misc/camera.rs
  7. +1
    -0
      space-crush/src/app/misc/mod.rs
  8. +28
    -12
      space-crush/src/app/misc/window.rs
  9. +3
    -2
      space-crush/src/app/mod.rs
  10. +38
    -6
      space-crush/src/app/render/init.rs
  11. +4
    -2
      space-crush/src/app/render/mod.rs
  12. +8
    -0
      space-crush/src/app/render/shader/quad.frag
  13. +16
    -0
      space-crush/src/app/render/shader/quad.vert
  14. +55
    -0
      space-crush/src/app/render/test.rs
  15. +3
    -0
      space-crush/src/error.rs

+ 8
- 0
glc/src/array_buffer.rs Parādīt failu

@@ -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> {
let ptr = Error::err_if(&null(), gl::map_named_buffer(self.id, access))?;
let count = self.size / size_of::<T>();


+ 2
- 2
glc/src/error.rs Parādīt failu

@@ -14,8 +14,8 @@ pub enum Error {
#[error("OpenGL Error: {0}")]
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}")]
ShaderLink(String),


+ 19
- 9
glc/src/matrix.rs Parādīt failu

@@ -6,6 +6,12 @@ use std::ops::{Deref, DerefMut, Mul};

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 {
($Name:ident, $Vector:ident, $size:tt, $($T:ident => $i:tt => $f:ident),*) => {
#[repr(C, packed)]
@@ -18,6 +24,10 @@ macro_rules! define_mat {
pub fn new($($f: $Vector<T>,)+) -> Self {
Self { $($f,)+ }
}

pub fn as_ptr(&self) -> * const T {
first_ptr!(self $(,$f)+)
}
}

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!(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 */



+ 30
- 7
glc/src/shader.rs Parādīt failu

@@ -5,6 +5,7 @@ use std::str::from_utf8;

use crate::{
error::Error,
matrix::Matrix4f,
misc::{AsEnum, Bindable},
};

@@ -69,6 +70,12 @@ impl Program {
pub fn id(&self) -> gl::GLuint {
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 {
@@ -99,10 +106,10 @@ impl Shader {
let id = Error::err_if(&0, id)?;

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);

let mut success = 1;
@@ -124,7 +131,10 @@ impl Shader {

let msg = from_utf8(&buffer)?;

return Err(Error::ShaderCompile(msg.into()));
return Err(Error::ShaderCompile {
code: source,
error: msg.into(),
});
}

Ok(Self { id })
@@ -134,9 +144,16 @@ impl Shader {
where
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 {
@@ -174,3 +191,9 @@ impl AsEnum for Type {
}
}
}

/* Uniform */

pub enum Uniform<'a> {
Matrix4f(&'a Matrix4f),
}

+ 20
- 9
glc/src/vector.rs Parādīt failu

@@ -4,6 +4,12 @@ use std::convert::{AsMut, AsRef};
use std::fmt::{Debug, Formatter, Result as FmtResult};
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 {
($Name:ident, $size:tt, $($T:ident => $i:tt => $f:ident),*) => {
#[repr(C, packed)]
@@ -16,6 +22,11 @@ macro_rules! define_vec {
pub fn new($($f: T,)+) -> Self {
Self { $($f,)+ }
}

#[inline]
pub fn as_ptr(&self) -> * const T {
first_ptr!(self $(, $f)+)
}
}

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!(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 */



+ 125
- 0
space-crush/src/app/misc/camera.rs Parādīt failu

@@ -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
- 0
space-crush/src/app/misc/mod.rs Parādīt failu

@@ -1,3 +1,4 @@
pub mod camera;
pub mod events;
pub mod geometry;
pub mod window;

+ 28
- 12
space-crush/src/app/misc/window.rs Parādīt failu

@@ -5,6 +5,7 @@ use glutin::{
window::WindowBuilder,
Api, ContextBuilder, ContextWrapper, GlProfile, GlRequest, PossiblyCurrent,
};
use log::info;

use crate::Error;

@@ -14,18 +15,33 @@ pub struct Window {

impl Window {
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_size = window.outer_size();


+ 3
- 2
space-crush/src/app/mod.rs Parādīt failu

@@ -7,7 +7,7 @@ use specs::{Dispatcher, DispatcherBuilder, World};
use crate::Error;

use misc::{events::Events, geometry::Geometry, window::Window};
use render::Background;
use render::{Init, Test};
use systems::{State, StateUpdate};

pub struct App<'a, 'b> {
@@ -24,7 +24,8 @@ impl<'a, 'b> App<'a, 'b> {

let mut dispatcher = DispatcherBuilder::new()
.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();
dispatcher.setup(world);



space-crush/src/app/render/background.rs → space-crush/src/app/render/init.rs Parādīt failu

@@ -2,19 +2,36 @@ use glc::{
misc::Bindable,
shader::{Program, Shader, Type},
};
use log::error;
use shrev::{EventChannel, ReaderId};
use specs::{ReadExpect, System, World};
use specs::{ReadExpect, System, World, WriteExpect};

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,
window_events_id: ReaderId<WindowEvent>,
}

impl Background {
impl Init {
pub fn new(world: &mut World) -> Result<Self, Error> {
let shaders = vec![
(Type::Vertex, include_str!("shader/noise.vert")),
@@ -29,6 +46,8 @@ impl Background {
.fetch_mut::<EventChannel<WindowEvent>>()
.register_reader();

world.insert(Global::new()?);

Ok(Self {
program,
window_events_id,
@@ -36,17 +55,30 @@ impl Background {
}
}

impl<'a> System<'a> for Background {
impl<'a> System<'a> for Init {
type SystemData = (
WriteExpect<'a, Global>,
ReadExpect<'a, Geometry>,
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);
for event in events {
if let WindowEvent::Resize(w, h) = event {
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);
}
}
}


+ 4
- 2
space-crush/src/app/render/mod.rs Parādīt failu

@@ -1,3 +1,5 @@
mod background;
mod init;
mod test;

pub use background::Background;
pub use init::{Global, Init};
pub use test::Test;

+ 8
- 0
space-crush/src/app/render/shader/quad.frag Parādīt failu

@@ -0,0 +1,8 @@
#version 450 core

out vec4 Color;

void main()
{
Color = vec4(1.0, 1.0, 1.0, 1.0);
}

+ 16
- 0
space-crush/src/app/render/shader/quad.vert Parādīt failu

@@ -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);
}

+ 55
- 0
space-crush/src/app/render/test.rs Parādīt failu

@@ -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();
}
}

+ 3
- 0
space-crush/src/error.rs Parādīt failu

@@ -12,6 +12,9 @@ pub enum Error {

#[error("glutin Creation Error: {0}")]
GlutinCreationError(GlutinCreationError),

#[error("Unable to create OpenGL context")]
UnableToCreateContext,
}

impl From<GlcError> for Error {


Notiek ielāde…
Atcelt
Saglabāt