Autors | SHA1 | Ziņojums | Datums |
---|---|---|---|
Bergmann89 | 8c9022c740 | WIP | pirms 3 gadiem |
Bergmann89 | ae9f57b993 | reduced color vector from 4 elements to 3 | pirms 3 gadiem |
Bergmann89 | 5ac3940358 | Use vertex array and geometry shader to render asteroids | pirms 3 gadiem |
Bergmann89 | c5e70fb728 | Use vertex array and geometry shader to render planets | pirms 3 gadiem |
Bergmann89 | e26c7dbfd3 | Use vertex array and geometry shader to render ships | pirms 3 gadiem |
Bergmann89 | 7697f03369 | Improved 'FlaggedStorage' | pirms 3 gadiem |
Bergmann89 | 0fb546baad | Renamed glc 'ArrayBuffer' to 'Buffer' | pirms 3 gadiem |
@@ -1,6 +1,8 @@ | |||||
use std::cell::{Ref, RefCell}; | |||||
use std::mem::size_of; | use std::mem::size_of; | ||||
use std::ops::{Deref, DerefMut}; | use std::ops::{Deref, DerefMut}; | ||||
use std::ptr::null; | use std::ptr::null; | ||||
use std::rc::Rc; | |||||
use std::slice::from_raw_parts_mut; | use std::slice::from_raw_parts_mut; | ||||
use crate::{ | use crate::{ | ||||
@@ -8,31 +10,30 @@ use crate::{ | |||||
misc::{AsEnum, Bindable}, | misc::{AsEnum, Bindable}, | ||||
}; | }; | ||||
/* ArrayBuffer */ | |||||
/* Buffer */ | |||||
pub struct ArrayBuffer { | |||||
pub struct Buffer { | |||||
id: gl::GLuint, | id: gl::GLuint, | ||||
target: Target, | |||||
size: usize, | size: usize, | ||||
} | } | ||||
impl ArrayBuffer { | |||||
pub fn new(target: Target) -> Result<Self, Error> { | |||||
impl Buffer { | |||||
pub fn new() -> Result<Self, Error> { | |||||
let mut id = 0; | let mut id = 0; | ||||
Error::checked(|| gl::create_buffers(1, &mut id))?; | Error::checked(|| gl::create_buffers(1, &mut id))?; | ||||
Ok(Self { | |||||
id, | |||||
target, | |||||
size: 0, | |||||
}) | |||||
Ok(Self { id, size: 0 }) | |||||
} | } | ||||
pub fn id(&self) -> gl::GLuint { | pub fn id(&self) -> gl::GLuint { | ||||
self.id | self.id | ||||
} | } | ||||
pub fn size(&self) -> usize { | |||||
self.size | |||||
} | |||||
pub fn buffer_data<T>(&mut self, usage: Usage, data: &[T]) -> Result<(), Error> { | pub fn buffer_data<T>(&mut self, usage: Usage, data: &[T]) -> Result<(), Error> { | ||||
let size = data.len() * size_of::<T>(); | let size = data.len() * size_of::<T>(); | ||||
@@ -107,12 +108,18 @@ 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_base(&self, target: Target, index: gl::GLuint) { | |||||
gl::bind_buffer_base(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); | |||||
pub fn bind_buffer_range( | |||||
&self, | |||||
target: Target, | |||||
index: gl::GLuint, | |||||
offset: gl::GLintptr, | |||||
size: gl::GLsizeiptr, | |||||
) { | |||||
gl::bind_buffer_range(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> { | ||||
@@ -150,26 +157,29 @@ impl ArrayBuffer { | |||||
} | } | ||||
} | } | ||||
impl Drop for ArrayBuffer { | |||||
impl Drop for Buffer { | |||||
fn drop(&mut self) { | fn drop(&mut self) { | ||||
gl::delete_buffers(1, &self.id); | gl::delete_buffers(1, &self.id); | ||||
} | } | ||||
} | } | ||||
impl Bindable for ArrayBuffer { | |||||
impl<T> Bindable for (Target, T) | |||||
where | |||||
T: Deref<Target = Buffer>, | |||||
{ | |||||
fn bind(&self) { | fn bind(&self) { | ||||
gl::bind_buffer(self.target.as_enum(), self.id); | |||||
gl::bind_buffer(self.0.as_enum(), self.1.id); | |||||
} | } | ||||
fn unbind(&self) { | fn unbind(&self) { | ||||
gl::bind_buffer(self.target.as_enum(), 0); | |||||
gl::bind_buffer(self.0.as_enum(), 0); | |||||
} | } | ||||
} | } | ||||
/* Map */ | /* Map */ | ||||
pub struct Map<'a, T> { | pub struct Map<'a, T> { | ||||
buf: &'a ArrayBuffer, | |||||
buf: &'a Buffer, | |||||
data: &'a [T], | data: &'a [T], | ||||
} | } | ||||
@@ -190,7 +200,7 @@ impl<T> Deref for Map<'_, T> { | |||||
/* MapMut */ | /* MapMut */ | ||||
pub struct MapMut<'a, T> { | pub struct MapMut<'a, T> { | ||||
buf: &'a ArrayBuffer, | |||||
buf: &'a Buffer, | |||||
data: &'a mut [T], | data: &'a mut [T], | ||||
} | } | ||||
@@ -214,6 +224,38 @@ impl<T> DerefMut for MapMut<'_, T> { | |||||
} | } | ||||
} | } | ||||
/* BufferRef */ | |||||
pub trait BufferRef { | |||||
type Output: Deref<Target = Buffer>; | |||||
fn as_ref(self) -> Self::Output; | |||||
} | |||||
impl<'a> BufferRef for &'a Buffer { | |||||
type Output = &'a Buffer; | |||||
fn as_ref(self) -> Self::Output { | |||||
self | |||||
} | |||||
} | |||||
impl<'a> BufferRef for &'a RefCell<Buffer> { | |||||
type Output = Ref<'a, Buffer>; | |||||
fn as_ref(self) -> Self::Output { | |||||
self.borrow() | |||||
} | |||||
} | |||||
impl<'a> BufferRef for &'a Rc<RefCell<Buffer>> { | |||||
type Output = Ref<'a, Buffer>; | |||||
fn as_ref(self) -> Self::Output { | |||||
self.borrow() | |||||
} | |||||
} | |||||
/* Target */ | /* Target */ | ||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)] | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
@@ -40,6 +40,12 @@ pub enum Error { | |||||
#[error("Vertex Array: Expected pointer!")] | #[error("Vertex Array: Expected pointer!")] | ||||
VertexArrayExpectedPointer, | VertexArrayExpectedPointer, | ||||
#[error("Transform Feedback: Index is already in use: {0}!")] | |||||
TransformFeedbackIndexAlreadyInUse(gl::GLuint), | |||||
#[error("Transform Feedback: Array Buffer must be for target GL_TRANSFORM_FEEDBACK_BUFFER!")] | |||||
TransformFeedbackInvalidBuffer, | |||||
#[error("Invalid Parameter!")] | #[error("Invalid Parameter!")] | ||||
InvalidParameter, | InvalidParameter, | ||||
@@ -1,6 +1,6 @@ | |||||
pub mod angle; | pub mod angle; | ||||
pub mod animation; | pub mod animation; | ||||
pub mod array_buffer; | |||||
pub mod buffer; | |||||
pub mod error; | pub mod error; | ||||
pub mod math; | pub mod math; | ||||
pub mod matrix; | pub mod matrix; | ||||
@@ -8,5 +8,6 @@ pub mod misc; | |||||
pub mod numeric; | pub mod numeric; | ||||
pub mod shader; | pub mod shader; | ||||
pub mod texture; | pub mod texture; | ||||
pub mod transform_feedback; | |||||
pub mod vector; | pub mod vector; | ||||
pub mod vertex_array; | pub mod vertex_array; |
@@ -20,6 +20,10 @@ pub struct Program { | |||||
} | } | ||||
impl Program { | impl Program { | ||||
pub fn builder() -> Builder { | |||||
Builder::default() | |||||
} | |||||
pub fn from_shaders<I>(iter: I) -> Result<Self, Error> | pub fn from_shaders<I>(iter: I) -> Result<Self, Error> | ||||
where | where | ||||
I: IntoIterator<Item = Shader>, | I: IntoIterator<Item = Shader>, | ||||
@@ -32,43 +36,15 @@ impl Program { | |||||
I: IntoIterator<Item = Result<Shader, E>>, | I: IntoIterator<Item = Result<Shader, E>>, | ||||
E: From<Error>, | E: From<Error>, | ||||
{ | { | ||||
let id = gl::create_program(); | |||||
let id = Error::err_if(&0, id)?; | |||||
let mut builder = Self::builder(); | |||||
let shaders = iter.into_iter().collect::<Result<Vec<_>, _>>()?; | |||||
for shader in &shaders { | |||||
gl::attach_shader(id, shader.id()); | |||||
for shader in iter.into_iter() { | |||||
builder = builder.add_shader(shader?); | |||||
} | } | ||||
gl::link_program(id); | |||||
for shader in &shaders { | |||||
gl::detach_shader(id, shader.id()); | |||||
} | |||||
let mut success = 1; | |||||
gl::get_program_iv(id, gl::LINK_STATUS, &mut success); | |||||
if success != 1 { | |||||
let mut len = 0; | |||||
gl::get_program_iv(id, gl::INFO_LOG_LENGTH, &mut len); | |||||
let mut buffer = Vec::<u8>::with_capacity(len as usize + 1); | |||||
buffer.resize(len as usize, 0); | |||||
gl::get_program_info_log( | |||||
id, | |||||
len, | |||||
null_mut(), | |||||
buffer.as_mut_ptr() as *mut gl::types::GLchar, | |||||
); | |||||
let msg = from_utf8(&buffer).map_err(Error::Utf8Error)?; | |||||
let program = builder.build()?; | |||||
return Err(Error::ShaderLink(msg.into()).into()); | |||||
} | |||||
Ok(Program { id }) | |||||
Ok(program) | |||||
} | } | ||||
pub fn id(&self) -> gl::GLuint { | pub fn id(&self) -> gl::GLuint { | ||||
@@ -87,6 +63,7 @@ impl Program { | |||||
Uniform::Vector2f(v) => gl::uniform_2fv(location, 1, v.as_ptr()), | Uniform::Vector2f(v) => gl::uniform_2fv(location, 1, v.as_ptr()), | ||||
Uniform::Float(v) => gl::uniform_1f(location, v), | Uniform::Float(v) => gl::uniform_1f(location, v), | ||||
Uniform::Texture(i) => gl::uniform_1i(location, i), | Uniform::Texture(i) => gl::uniform_1i(location, i), | ||||
Uniform::TextureVec(i) => gl::uniform_1iv(location, i.len() as _, i.as_ptr()), | |||||
} | } | ||||
Ok(()) | Ok(()) | ||||
@@ -252,6 +229,87 @@ impl Drop for Shader { | |||||
} | } | ||||
} | } | ||||
/* Builder */ | |||||
#[derive(Default)] | |||||
pub struct Builder { | |||||
shaders: Vec<Shader>, | |||||
transform_feedback_varyings: Option<(TransformFeedbackVaryingsMode, &'static [&'static str])>, | |||||
} | |||||
impl Builder { | |||||
pub fn add_shader(mut self, shader: Shader) -> Self { | |||||
self.shaders.push(shader); | |||||
self | |||||
} | |||||
pub fn set_transform_feedback_varyings( | |||||
mut self, | |||||
mode: TransformFeedbackVaryingsMode, | |||||
value: &'static [&'static str], | |||||
) -> Self { | |||||
self.transform_feedback_varyings = Some((mode, value)); | |||||
self | |||||
} | |||||
pub fn build(self) -> Result<Program, Error> { | |||||
let id = gl::create_program(); | |||||
let id = Error::err_if(&0, id)?; | |||||
for shader in &self.shaders { | |||||
gl::attach_shader(id, shader.id()); | |||||
} | |||||
if let Some((mode, tfv)) = self.transform_feedback_varyings { | |||||
let tfv = tfv | |||||
.iter() | |||||
.map(|v: &&str| CString::new(*v)) | |||||
.collect::<Result<Vec<_>, _>>()?; | |||||
let tfv = tfv | |||||
.iter() | |||||
.map(|v: &CString| v.as_ptr() as *const gl::GLchar) | |||||
.collect::<Vec<_>>(); | |||||
let ptr: *const *const gl::GLchar = tfv.as_slice().as_ptr(); | |||||
Error::checked(|| { | |||||
gl::transform_feedback_varyings(id, tfv.len() as _, ptr, mode.as_enum()) | |||||
})?; | |||||
} | |||||
gl::link_program(id); | |||||
for shader in &self.shaders { | |||||
gl::detach_shader(id, shader.id()); | |||||
} | |||||
let mut success = 1; | |||||
gl::get_program_iv(id, gl::LINK_STATUS, &mut success); | |||||
if success != 1 { | |||||
let mut len = 0; | |||||
gl::get_program_iv(id, gl::INFO_LOG_LENGTH, &mut len); | |||||
let mut buffer = Vec::<u8>::with_capacity(len as usize + 1); | |||||
buffer.resize(len as usize, 0); | |||||
gl::get_program_info_log( | |||||
id, | |||||
len, | |||||
null_mut(), | |||||
buffer.as_mut_ptr() as *mut gl::types::GLchar, | |||||
); | |||||
let msg = from_utf8(&buffer).map_err(Error::Utf8Error)?; | |||||
return Err(Error::ShaderLink(msg.into())); | |||||
} | |||||
Ok(Program { id }) | |||||
} | |||||
} | |||||
/* Type */ | /* Type */ | ||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)] | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||||
@@ -277,6 +335,22 @@ impl AsEnum for Type { | |||||
} | } | ||||
} | } | ||||
/* TransformFeedbackVaryingsMode */ | |||||
pub enum TransformFeedbackVaryingsMode { | |||||
Interleaved, | |||||
Separate, | |||||
} | |||||
impl AsEnum for TransformFeedbackVaryingsMode { | |||||
fn as_enum(&self) -> gl::GLenum { | |||||
match self { | |||||
Self::Interleaved => gl::INTERLEAVED_ATTRIBS, | |||||
Self::Separate => gl::SEPARATE_ATTRIBS, | |||||
} | |||||
} | |||||
} | |||||
/* Uniform */ | /* Uniform */ | ||||
pub enum Uniform<'a> { | pub enum Uniform<'a> { | ||||
@@ -285,6 +359,7 @@ pub enum Uniform<'a> { | |||||
Vector2f(&'a Vector2f), | Vector2f(&'a Vector2f), | ||||
Float(f32), | Float(f32), | ||||
Texture(gl::GLint), | Texture(gl::GLint), | ||||
TextureVec(&'a [gl::GLint]), | |||||
} | } | ||||
/* IntoUniformLocation */ | /* IntoUniformLocation */ | ||||
@@ -0,0 +1,117 @@ | |||||
use crate::{ | |||||
buffer::{Buffer, BufferRef, Target}, | |||||
error::Error, | |||||
misc::{BindGuard, Bindable}, | |||||
}; | |||||
/* TransformFeedback */ | |||||
pub struct TransformFeedback<T = Buffer> { | |||||
id: gl::GLuint, | |||||
buffers: Vec<T>, | |||||
} | |||||
impl<T> TransformFeedback<T> { | |||||
pub fn builder() -> Builder<T> { | |||||
Builder::default() | |||||
} | |||||
pub fn id(&self) -> gl::GLuint { | |||||
self.id | |||||
} | |||||
pub fn buffers(&self) -> &[T] { | |||||
&self.buffers | |||||
} | |||||
pub fn buffers_mut(&mut self) -> &mut [T] { | |||||
&mut self.buffers | |||||
} | |||||
} | |||||
impl<T> Drop for TransformFeedback<T> { | |||||
fn drop(&mut self) { | |||||
gl::delete_transform_feedbacks(1, &self.id); | |||||
} | |||||
} | |||||
impl<T> Bindable for TransformFeedback<T> { | |||||
fn bind(&self) { | |||||
gl::bind_transform_feedback(gl::TRANSFORM_FEEDBACK, self.id); | |||||
} | |||||
fn unbind(&self) { | |||||
gl::bind_transform_feedback(gl::TRANSFORM_FEEDBACK, 0); | |||||
} | |||||
} | |||||
/* Builder */ | |||||
pub struct Builder<T> { | |||||
bindings: Vec<Binding<T>>, | |||||
} | |||||
impl<T> Builder<T> | |||||
where | |||||
for<'a> &'a T: BufferRef, | |||||
{ | |||||
pub fn bind_buffer(mut self, index: gl::GLuint, buffer: T) -> Result<Builder<T>, Error> { | |||||
for binding in &self.bindings { | |||||
if binding.index == index { | |||||
return Err(Error::TransformFeedbackIndexAlreadyInUse(index)); | |||||
} | |||||
} | |||||
let binding = Binding { buffer, index }; | |||||
self.bindings.push(binding); | |||||
Ok(self) | |||||
} | |||||
pub fn build(self) -> Result<TransformFeedback<T>, Error> { | |||||
let mut id = 0; | |||||
Error::checked(|| gl::create_transform_feedbacks(1, &mut id))?; | |||||
let mut transform_feedback = TransformFeedback { | |||||
id, | |||||
buffers: Vec::new(), | |||||
}; | |||||
let guard = BindGuard::new(&transform_feedback); | |||||
let mut buffers = Vec::new(); | |||||
for binding in self.bindings { | |||||
Error::checked(|| { | |||||
binding | |||||
.buffer | |||||
.as_ref() | |||||
.bind_buffer_base(Target::TransformFeedbackBuffer, binding.index) | |||||
})?; | |||||
buffers.push(binding.buffer); | |||||
} | |||||
drop(guard); | |||||
transform_feedback.buffers = buffers; | |||||
Ok(transform_feedback) | |||||
} | |||||
} | |||||
impl<T> Default for Builder<T> { | |||||
fn default() -> Self { | |||||
Self { | |||||
bindings: Vec::new(), | |||||
} | |||||
} | |||||
} | |||||
/* Binding */ | |||||
struct Binding<T> { | |||||
buffer: T, | |||||
index: gl::GLuint, | |||||
} |
@@ -1,37 +1,37 @@ | |||||
use crate::{ | use crate::{ | ||||
array_buffer::ArrayBuffer, | |||||
buffer::{Buffer, BufferRef, Target}, | |||||
error::Error, | error::Error, | ||||
misc::{AsEnum, BindGuard, Bindable}, | misc::{AsEnum, BindGuard, Bindable}, | ||||
}; | }; | ||||
/* VertexArray */ | /* VertexArray */ | ||||
pub struct VertexArray { | |||||
pub struct VertexArray<T = Buffer> { | |||||
id: gl::GLuint, | id: gl::GLuint, | ||||
buffers: Vec<ArrayBuffer>, | |||||
buffers: Vec<T>, | |||||
} | } | ||||
impl VertexArray { | |||||
pub fn builder() -> Builder { | |||||
impl<T> VertexArray<T> { | |||||
pub fn builder() -> Builder<T> { | |||||
Builder::default() | Builder::default() | ||||
} | } | ||||
pub fn buffers(&self) -> &Vec<ArrayBuffer> { | |||||
pub fn buffers(&self) -> &[T] { | |||||
&self.buffers | &self.buffers | ||||
} | } | ||||
pub fn buffers_mut(&mut self) -> &mut Vec<ArrayBuffer> { | |||||
pub fn buffers_mut(&mut self) -> &mut [T] { | |||||
&mut self.buffers | &mut self.buffers | ||||
} | } | ||||
} | } | ||||
impl Drop for VertexArray { | |||||
impl<T> Drop for VertexArray<T> { | |||||
fn drop(&mut self) { | fn drop(&mut self) { | ||||
gl::delete_vertex_arrays(1, &self.id); | gl::delete_vertex_arrays(1, &self.id); | ||||
} | } | ||||
} | } | ||||
impl Bindable for VertexArray { | |||||
impl<T> Bindable for VertexArray<T> { | |||||
fn bind(&self) { | fn bind(&self) { | ||||
gl::bind_vertex_array(self.id); | gl::bind_vertex_array(self.id); | ||||
} | } | ||||
@@ -43,13 +43,12 @@ impl Bindable for VertexArray { | |||||
/* Builder */ | /* Builder */ | ||||
#[derive(Default)] | |||||
pub struct Builder { | |||||
bindings: Vec<Binding>, | |||||
pub struct Builder<T> { | |||||
bindings: Vec<Binding<T>>, | |||||
} | } | ||||
impl Builder { | |||||
pub fn bind_buffer(mut self, buffer: ArrayBuffer) -> BindingBuilder { | |||||
impl<T> Builder<T> { | |||||
pub fn bind_buffer(mut self, buffer: T) -> BindingBuilder<T> { | |||||
let binding = Binding { | let binding = Binding { | ||||
buffer, | buffer, | ||||
pointers: Vec::new(), | pointers: Vec::new(), | ||||
@@ -59,8 +58,13 @@ impl Builder { | |||||
BindingBuilder { builder: self } | BindingBuilder { builder: self } | ||||
} | } | ||||
} | |||||
pub fn build(self) -> Result<VertexArray, Error> { | |||||
impl<T> Builder<T> | |||||
where | |||||
for<'a> &'a T: BufferRef, | |||||
{ | |||||
pub fn build(self) -> Result<VertexArray<T>, Error> { | |||||
let mut id = 0; | let mut id = 0; | ||||
Error::checked(|| gl::create_vertex_arrays(1, &mut id))?; | Error::checked(|| gl::create_vertex_arrays(1, &mut id))?; | ||||
@@ -74,25 +78,41 @@ impl Builder { | |||||
let mut buffers = Vec::new(); | let mut buffers = Vec::new(); | ||||
for binding in self.bindings { | for binding in self.bindings { | ||||
let guard = BindGuard::new(&binding.buffer); | |||||
let guard = BindGuard::new((Target::ArrayBuffer, binding.buffer.as_ref())); | |||||
for pointer in binding.pointers { | for pointer in binding.pointers { | ||||
Error::checked(|| gl::enable_vertex_attrib_array(pointer.index))?; | Error::checked(|| gl::enable_vertex_attrib_array(pointer.index))?; | ||||
Error::checked(|| { | |||||
gl::vertex_attrib_pointer( | |||||
pointer.index, | |||||
pointer.size, | |||||
pointer.type_.as_enum(), | |||||
if pointer.normalize { | |||||
gl::TRUE | |||||
} else { | |||||
gl::FALSE | |||||
}, | |||||
pointer.stride, | |||||
pointer.offset as *const _, | |||||
) | |||||
})?; | |||||
match pointer.type_ { | |||||
DataType::Byte | |||||
| DataType::UnsignedByte | |||||
| DataType::Short | |||||
| DataType::UnsignedShort | |||||
| DataType::Int | |||||
| DataType::UnsignedInt => Error::checked(|| { | |||||
gl::vertex_attrib_i_pointer( | |||||
pointer.index, | |||||
pointer.size, | |||||
pointer.type_.as_enum(), | |||||
pointer.stride, | |||||
pointer.offset as *const _, | |||||
) | |||||
})?, | |||||
_ => Error::checked(|| { | |||||
gl::vertex_attrib_pointer( | |||||
pointer.index, | |||||
pointer.size, | |||||
pointer.type_.as_enum(), | |||||
if pointer.normalize { | |||||
gl::TRUE | |||||
} else { | |||||
gl::FALSE | |||||
}, | |||||
pointer.stride, | |||||
pointer.offset as *const _, | |||||
) | |||||
})?, | |||||
} | |||||
if let Some(divisor) = pointer.divisor { | if let Some(divisor) = pointer.divisor { | ||||
Error::checked(|| gl::vertex_attrib_divisor(pointer.index, divisor))?; | Error::checked(|| gl::vertex_attrib_divisor(pointer.index, divisor))?; | ||||
@@ -112,14 +132,33 @@ impl Builder { | |||||
} | } | ||||
} | } | ||||
impl<T> Clone for Builder<T> | |||||
where | |||||
T: Clone, | |||||
{ | |||||
fn clone(&self) -> Self { | |||||
Self { | |||||
bindings: self.bindings.clone(), | |||||
} | |||||
} | |||||
} | |||||
impl<T> Default for Builder<T> { | |||||
fn default() -> Self { | |||||
Self { | |||||
bindings: Vec::new(), | |||||
} | |||||
} | |||||
} | |||||
/* BindingBuilder */ | /* BindingBuilder */ | ||||
pub struct BindingBuilder { | |||||
builder: Builder, | |||||
pub struct BindingBuilder<T> { | |||||
builder: Builder<T>, | |||||
} | } | ||||
impl BindingBuilder { | |||||
pub fn bind_buffer(self, buffer: ArrayBuffer) -> Self { | |||||
impl<T> BindingBuilder<T> { | |||||
pub fn bind_buffer(self, buffer: T) -> Self { | |||||
self.builder.bind_buffer(buffer) | self.builder.bind_buffer(buffer) | ||||
} | } | ||||
@@ -171,15 +210,32 @@ impl BindingBuilder { | |||||
Ok(self) | Ok(self) | ||||
} | } | ||||
} | |||||
pub fn build(self) -> Result<VertexArray, Error> { | |||||
impl<T> BindingBuilder<T> | |||||
where | |||||
for<'a> &'a T: BufferRef, | |||||
{ | |||||
pub fn build(self) -> Result<VertexArray<T>, Error> { | |||||
self.builder.build() | self.builder.build() | ||||
} | } | ||||
} | } | ||||
impl<T> Clone for BindingBuilder<T> | |||||
where | |||||
T: Clone, | |||||
{ | |||||
fn clone(&self) -> Self { | |||||
Self { | |||||
builder: self.builder.clone(), | |||||
} | |||||
} | |||||
} | |||||
/* DataType */ | /* DataType */ | ||||
#[allow(non_camel_case_types)] | #[allow(non_camel_case_types)] | ||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] | |||||
pub enum DataType { | pub enum DataType { | ||||
Byte, | Byte, | ||||
UnsignedByte, | UnsignedByte, | ||||
@@ -218,19 +274,32 @@ impl AsEnum for DataType { | |||||
/* Binding */ | /* Binding */ | ||||
struct Binding { | |||||
buffer: ArrayBuffer, | |||||
struct Binding<T> { | |||||
buffer: T, | |||||
pointers: Vec<Pointer>, | pointers: Vec<Pointer>, | ||||
} | } | ||||
impl<T> Clone for Binding<T> | |||||
where | |||||
T: Clone, | |||||
{ | |||||
fn clone(&self) -> Self { | |||||
Self { | |||||
buffer: self.buffer.clone(), | |||||
pointers: self.pointers.clone(), | |||||
} | |||||
} | |||||
} | |||||
/* Pointer */ | /* Pointer */ | ||||
struct Pointer { | |||||
index: gl::GLuint, | |||||
size: gl::GLint, | |||||
type_: DataType, | |||||
normalize: bool, | |||||
stride: gl::GLsizei, | |||||
offset: gl::GLsizei, | |||||
divisor: Option<gl::GLuint>, | |||||
#[derive(Clone, Debug)] | |||||
pub struct Pointer { | |||||
pub index: gl::GLuint, | |||||
pub size: gl::GLint, | |||||
pub type_: DataType, | |||||
pub normalize: bool, | |||||
pub stride: gl::GLsizei, | |||||
pub offset: gl::GLsizei, | |||||
pub divisor: Option<gl::GLuint>, | |||||
} | } |
@@ -12,17 +12,17 @@ const GlowArgs GLOW_ARGS = { | |||||
/* pulseTime */ 2.000, | /* pulseTime */ 2.000, | ||||
}; | }; | ||||
in FragmentData fragmentData; | |||||
in FragmentData fragmentData; | |||||
flat in int textureId; | |||||
uniform vec4 uGlowColor; | |||||
uniform sampler2D uTexture; | |||||
uniform sampler2D uTexture[2]; | |||||
out vec4 outColor; | out vec4 outColor; | ||||
void main() { | void main() { | ||||
float alpha = glow(GLOW_ARGS, fragmentData.texCoords - vec2(0.5), uGlobal.time); | |||||
vec4 glow = vec4(uGlowColor.rgb, uGlowColor.a * alpha); | |||||
vec4 tex = texture(uTexture, fragmentData.texCoords); | |||||
float alpha = glow(GLOW_ARGS, fragmentData.texCoords, uGlobal.time); | |||||
vec4 glow = vec4(fragmentData.color, GLOW_ALPHA * alpha); | |||||
vec4 tex = texture(uTexture[textureId], 0.5 * GLOW_SIZE * fragmentData.texCoords + vec2(0.5)); | |||||
outColor = tex * tex.a + glow * (1.0 - tex.a); | outColor = tex * tex.a + glow * (1.0 - tex.a); | ||||
} | } |
@@ -0,0 +1,46 @@ | |||||
#version 450 core | |||||
#pragma include ./shared.glsl | |||||
#pragma include ../misc/camera.glsl | |||||
in VertexData vertexData[]; | |||||
layout (points) in; | |||||
layout (triangle_strip, max_vertices = 4) out; | |||||
out FragmentData fragmentData; | |||||
flat out int textureId; | |||||
void main() { | |||||
VertexData d = vertexData[0]; | |||||
vec2 pos = d.pos; | |||||
float size = d.size * GLOW_SIZE; | |||||
mat4 m = uCamera.projection * uCamera.view * mat4( | |||||
vec4( size, 0.0, 0.0, 0.0), | |||||
vec4( 0.0, size, 0.0, 0.0), | |||||
vec4( 0.0, 0.0, 0.0, 0.0), | |||||
vec4(pos.x, pos.y, 0.0, 1.0)); | |||||
textureId = d.texture; | |||||
fragmentData.color = d.color; | |||||
gl_Position = m * vec4(-1.0, -1.0, 0.0, 1.0); | |||||
fragmentData.texCoords = vec2(-1.0, 1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4(-1.0, 1.0, 0.0, 1.0); | |||||
fragmentData.texCoords = vec2(-1.0, -1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4( 1.0, -1.0, 0.0, 1.0); | |||||
fragmentData.texCoords = vec2( 1.0, 1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4( 1.0, 1.0, 0.0, 1.0); | |||||
fragmentData.texCoords = vec2( 1.0, -1.0); | |||||
EmitVertex(); | |||||
EndPrimitive(); | |||||
} |
@@ -1,3 +1,14 @@ | |||||
struct FragmentData { | struct FragmentData { | ||||
vec2 texCoords; | vec2 texCoords; | ||||
vec3 color; | |||||
}; | }; | ||||
struct VertexData { | |||||
vec2 pos; | |||||
float size; | |||||
vec3 color; | |||||
int texture; | |||||
}; | |||||
const float GLOW_SIZE = 2.0; // relative to planet size | |||||
const float GLOW_ALPHA = 0.2; |
@@ -3,15 +3,16 @@ | |||||
#pragma include ./shared.glsl | #pragma include ./shared.glsl | ||||
#pragma include ../misc/camera.glsl | #pragma include ../misc/camera.glsl | ||||
const float GLOW_SIZE_FACTOR = 2.00; | |||||
layout (location = 0) in vec2 inPosition; | |||||
layout (location = 1) in float inSize; | |||||
layout (location = 2) in vec3 inColor; | |||||
layout (location = 3) in int inTexture; | |||||
in vec3 inPosition; | |||||
uniform mat4 uModel; | |||||
out FragmentData fragmentData; | |||||
out VertexData vertexData; | |||||
void main() { | void main() { | ||||
fragmentData.texCoords = inPosition.xy * GLOW_SIZE_FACTOR + vec2(0.5); | |||||
gl_Position = uCamera.projection * uCamera.view * uModel * vec4(2.0 * inPosition * GLOW_SIZE_FACTOR, 1.0); | |||||
vertexData.pos = inPosition; | |||||
vertexData.size = inSize; | |||||
vertexData.color = inColor; | |||||
vertexData.texture = inTexture; | |||||
} | } |
@@ -1,3 +1,4 @@ | |||||
layout (std140) uniform Global { | layout (std140) uniform Global { | ||||
float time; | float time; | ||||
float delta; | |||||
} uGlobal; | } uGlobal; |
@@ -14,15 +14,14 @@ const GlowArgs GLOW_ARGS = { | |||||
in FragmentData fragmentData; | in FragmentData fragmentData; | ||||
uniform vec4 uGlowColor; | |||||
uniform sampler2D uTexture; | uniform sampler2D uTexture; | ||||
out vec4 outColor; | out vec4 outColor; | ||||
void main() { | void main() { | ||||
float alpha = glow(GLOW_ARGS, fragmentData.texCoords - vec2(0.5), uGlobal.time); | |||||
vec4 glow = vec4(uGlowColor.rgb, uGlowColor.a * alpha); | |||||
vec4 tex = texture(uTexture, fragmentData.texCoords); | |||||
float alpha = glow(GLOW_ARGS, fragmentData.texCoords, uGlobal.time); | |||||
vec4 glow = vec4(fragmentData.color, GLOW_ALPHA * alpha); | |||||
vec4 tex = texture(uTexture, 0.5 * GLOW_SIZE * fragmentData.texCoords + vec2(0.5)); | |||||
outColor = tex * tex.a + glow * (1.0 - tex.a); | outColor = tex * tex.a + glow * (1.0 - tex.a); | ||||
} | } |
@@ -0,0 +1,44 @@ | |||||
#version 450 core | |||||
#pragma include ./shared.glsl | |||||
#pragma include ../misc/camera.glsl | |||||
in VertexData vertexData[]; | |||||
layout (points) in; | |||||
layout (triangle_strip, max_vertices = 4) out; | |||||
out FragmentData fragmentData; | |||||
void main() { | |||||
VertexData d = vertexData[0]; | |||||
vec2 pos = d.pos; | |||||
float size = d.size * GLOW_SIZE; | |||||
mat4 m = uCamera.projection * uCamera.view * mat4( | |||||
vec4( size, 0.0, 0.0, 0.0), | |||||
vec4( 0.0, size, 0.0, 0.0), | |||||
vec4( 0.0, 0.0, 0.0, 0.0), | |||||
vec4(pos.x, pos.y, 0.0, 1.0)); | |||||
fragmentData.color = d.color; | |||||
gl_Position = m * vec4(-1.0, -1.0, 0.0, 1.0); | |||||
fragmentData.texCoords = vec2(-1.0, 1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4(-1.0, 1.0, 0.0, 1.0); | |||||
fragmentData.texCoords = vec2(-1.0, -1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4( 1.0, -1.0, 0.0, 1.0); | |||||
fragmentData.texCoords = vec2( 1.0, 1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4( 1.0, 1.0, 0.0, 1.0); | |||||
fragmentData.texCoords = vec2( 1.0, -1.0); | |||||
EmitVertex(); | |||||
EndPrimitive(); | |||||
} |
@@ -1,3 +1,13 @@ | |||||
struct FragmentData { | struct FragmentData { | ||||
vec2 texCoords; | vec2 texCoords; | ||||
vec3 color; | |||||
}; | }; | ||||
struct VertexData { | |||||
vec2 pos; | |||||
float size; | |||||
vec3 color; | |||||
}; | |||||
const float GLOW_SIZE = 2.0; // relative to planet size | |||||
const float GLOW_ALPHA = 0.2; |
@@ -3,15 +3,14 @@ | |||||
#pragma include ./shared.glsl | #pragma include ./shared.glsl | ||||
#pragma include ../misc/camera.glsl | #pragma include ../misc/camera.glsl | ||||
const float GLOW_SIZE_FACTOR = 2.00; | |||||
layout (location = 0) in vec2 inPosition; | |||||
layout (location = 1) in float inSize; | |||||
layout (location = 2) in vec3 inColor; | |||||
in vec3 inPosition; | |||||
uniform mat4 uModel; | |||||
out FragmentData fragmentData; | |||||
out VertexData vertexData; | |||||
void main() { | void main() { | ||||
fragmentData.texCoords = inPosition.xy * GLOW_SIZE_FACTOR + vec2(0.5); | |||||
gl_Position = uCamera.projection * uCamera.view * uModel * vec4(2.0 * inPosition * GLOW_SIZE_FACTOR, 1.0); | |||||
vertexData.pos = inPosition; | |||||
vertexData.size = inSize; | |||||
vertexData.color = inColor; | |||||
} | } |
@@ -1,29 +0,0 @@ | |||||
#version 450 core | |||||
#pragma include ./shared.glsl | |||||
#pragma include ../misc/glow.glsl | |||||
#pragma include ../misc/global.glsl | |||||
const float GLOW_ALPHA = 0.20; | |||||
const GlowArgs GLOW_ARGS = { | |||||
/* step0 */ 0.100, | |||||
/* step1 */ 1.900, | |||||
/* pulseSize0 */ 0.050, | |||||
/* pulseSize1 */ 0.200, | |||||
/* pulseTime */ 2.000, | |||||
}; | |||||
in FragmentData fragmentData; | |||||
uniform vec4 uGlowColor; | |||||
uniform sampler2D uTexture; | |||||
out vec4 outColor; | |||||
void main() { | |||||
float alpha = glow(GLOW_ARGS, fragmentData.texCoords - vec2(0.5), uGlobal.time); | |||||
vec4 glow = vec4(uGlowColor.rgb, uGlowColor.a * alpha * GLOW_ALPHA); | |||||
vec4 tex = texture(uTexture, fragmentData.texCoords); | |||||
outColor = tex * tex.a + glow * (1.0 - tex.a); | |||||
} |
@@ -1,3 +0,0 @@ | |||||
struct FragmentData { | |||||
vec2 texCoords; | |||||
}; |
@@ -0,0 +1,28 @@ | |||||
#version 450 core | |||||
#pragma include ./ship_shared.glsl | |||||
#pragma include ../misc/glow.glsl | |||||
#pragma include ../misc/global.glsl | |||||
const GlowArgs GLOW_ARGS = { | |||||
/* step0 */ 0.100, | |||||
/* step1 */ 0.900, | |||||
/* pulseSize0 */ 0.050, | |||||
/* pulseSize1 */ 0.100, | |||||
/* pulseTime */ 2.000, | |||||
}; | |||||
in FragmentData fragmentData; | |||||
flat in int textureId; | |||||
uniform sampler2D uTexture[3]; | |||||
out vec4 outColor; | |||||
void main() { | |||||
float alpha = glow(GLOW_ARGS, fragmentData.texCoords, uGlobal.time); | |||||
vec4 glow = vec4(fragmentData.color, GLOW_ALPHA * alpha); | |||||
vec4 tex = texture(uTexture[textureId], 0.5 * GLOW_SIZE * fragmentData.texCoords + vec2(0.5)); | |||||
outColor = tex * tex.a + glow * (1.0 - tex.a); | |||||
} |
@@ -0,0 +1,46 @@ | |||||
#version 450 core | |||||
#pragma include ./ship_shared.glsl | |||||
#pragma include ../misc/camera.glsl | |||||
in VertexData vertexData[]; | |||||
layout (points) in; | |||||
layout (triangle_strip, max_vertices = 4) out; | |||||
out FragmentData fragmentData; | |||||
flat out int textureId; | |||||
void main() { | |||||
VertexData d = vertexData[0]; | |||||
vec2 pos = d.pos; | |||||
vec2 dir = d.dir * SHIP_SIZE * GLOW_SIZE; | |||||
mat4 m = uCamera.projection * uCamera.view * mat4( | |||||
vec4(dir.y, -dir.x, 0.0, 0.0), | |||||
vec4(dir.x, dir.y, 0.0, 0.0), | |||||
vec4( 0.0, 0.0, 0.0, 0.0), | |||||
vec4(pos.x, pos.y, 0.0, 1.0)); | |||||
textureId = d.texture; | |||||
fragmentData.color = d.color; | |||||
gl_Position = m * vec4(-1.0, -1.0, 0.0, 1.0); | |||||
fragmentData.texCoords = vec2(-1.0, 1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4(-1.0, 1.0, 0.0, 1.0); | |||||
fragmentData.texCoords = vec2(-1.0, -1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4( 1.0, -1.0, 0.0, 1.0); | |||||
fragmentData.texCoords = vec2( 1.0, 1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4( 1.0, 1.0, 0.0, 1.0); | |||||
fragmentData.texCoords = vec2( 1.0, -1.0); | |||||
EmitVertex(); | |||||
EndPrimitive(); | |||||
} |
@@ -0,0 +1,15 @@ | |||||
struct FragmentData { | |||||
vec2 texCoords; | |||||
vec3 color; | |||||
}; | |||||
struct VertexData { | |||||
vec2 pos; | |||||
vec2 dir; | |||||
vec3 color; | |||||
int texture; | |||||
}; | |||||
const float SHIP_SIZE = 25.00; // absolute ship size | |||||
const float GLOW_SIZE = 4.00; // relative to ship size | |||||
const float GLOW_ALPHA = 0.05; |
@@ -0,0 +1,17 @@ | |||||
#version 450 core | |||||
#pragma include ./ship_shared.glsl | |||||
layout (location = 0) in vec2 inPosition; | |||||
layout (location = 1) in vec2 inDirection; | |||||
layout (location = 2) in vec3 inColor; | |||||
layout (location = 3) in int inTexture; | |||||
out VertexData vertexData; | |||||
void main() { | |||||
vertexData.pos = inPosition; | |||||
vertexData.dir = inDirection; | |||||
vertexData.color = inColor; | |||||
vertexData.texture = inTexture; | |||||
} |
@@ -0,0 +1,11 @@ | |||||
#version 450 core | |||||
#pragma include ./tail_render_shared.glsl | |||||
in FragmentData fragmentData; | |||||
out vec4 outColor; | |||||
void main() { | |||||
outColor = fragmentData.color; | |||||
} |
@@ -0,0 +1,40 @@ | |||||
#version 450 core | |||||
#pragma include ./tail_render_shared.glsl | |||||
#pragma include ../misc/camera.glsl | |||||
in VertexData vertexData[]; | |||||
layout (points) in; | |||||
layout (line_strip, max_vertices = 6) out; | |||||
out FragmentData fragmentData; | |||||
void main() { | |||||
mat4 m = uCamera.projection * uCamera.view; | |||||
VertexData d = vertexData[0]; | |||||
fragmentData.color = vec4(d.color, 1.0); | |||||
gl_Position = m * vec4(d.tail[0], 0.0, 1.0); | |||||
fragmentData.color = vec4(1.0, 0.0, 0.0, 1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4(d.tail[1], 0.0, 1.0); | |||||
fragmentData.color = vec4(1.0, 1.0, 0.0, 1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4(d.tail[2], 0.0, 1.0); | |||||
fragmentData.color = vec4(0.0, 1.0, 0.0, 1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4(d.tail[3], 0.0, 1.0); | |||||
fragmentData.color = vec4(0.0, 1.0, 1.0, 1.0); | |||||
EmitVertex(); | |||||
gl_Position = m * vec4(d.tail[4], 0.0, 1.0); | |||||
fragmentData.color = vec4(0.0, 0.0, 1.0, 1.0); | |||||
EmitVertex(); | |||||
EndPrimitive(); | |||||
} |
@@ -0,0 +1,8 @@ | |||||
struct FragmentData { | |||||
vec4 color; | |||||
}; | |||||
struct VertexData { | |||||
vec3 color; | |||||
vec2 tail[5]; | |||||
}; |
@@ -0,0 +1,21 @@ | |||||
#version 450 core | |||||
#pragma include ./tail_render_shared.glsl | |||||
layout (location = 0) in vec3 inColor; | |||||
layout (location = 1) in vec2 inTail0; | |||||
layout (location = 2) in vec2 inTail1; | |||||
layout (location = 3) in vec2 inTail2; | |||||
layout (location = 4) in vec2 inTail3; | |||||
layout (location = 5) in vec2 inTail4; | |||||
out VertexData vertexData; | |||||
void main() { | |||||
vertexData.color = inColor; | |||||
vertexData.tail[0] = inTail0; | |||||
vertexData.tail[1] = inTail1; | |||||
vertexData.tail[2] = inTail2; | |||||
vertexData.tail[3] = inTail3; | |||||
vertexData.tail[4] = inTail4; | |||||
} |
@@ -0,0 +1,38 @@ | |||||
#version 450 core | |||||
#pragma include ./tail_update_shared.glsl | |||||
#pragma include ../misc/global.glsl | |||||
in VertexData vertexData[]; | |||||
layout (points) in; | |||||
layout (points, max_vertices = 1) out; | |||||
out vec2 outTail0; | |||||
out vec2 outTail1; | |||||
out vec2 outTail2; | |||||
out vec2 outTail3; | |||||
out vec2 outTail4; | |||||
vec2 move(vec2 ref, vec2 point) { | |||||
vec2 dir = ref - point; | |||||
float len = length(dir); | |||||
float diff = max(len - TAIL_LEN, 0.0); | |||||
float force = min(TAIL_FORCE * diff * uGlobal.delta, diff); | |||||
return point + normalize(dir) * force; | |||||
} | |||||
void main() { | |||||
VertexData d = vertexData[0]; | |||||
outTail0 = d.pos; | |||||
outTail1 = move(d.pos, d.tail[1]); | |||||
outTail2 = move(d.tail[1], d.tail[2]); | |||||
outTail3 = move(d.tail[2], d.tail[3]); | |||||
outTail4 = move(d.tail[3], d.tail[4]); | |||||
EmitVertex(); | |||||
EndPrimitive(); | |||||
} |
@@ -0,0 +1,7 @@ | |||||
struct VertexData { | |||||
vec2 pos; | |||||
vec2 tail[5]; | |||||
}; | |||||
const float TAIL_LEN = 10.0; | |||||
const float TAIL_FORCE = 1.0; |
@@ -0,0 +1,21 @@ | |||||
#version 450 core | |||||
#pragma include ./tail_update_shared.glsl | |||||
layout (location = 0) in vec2 inPosition; | |||||
layout (location = 1) in vec2 inTail0; | |||||
layout (location = 2) in vec2 inTail1; | |||||
layout (location = 3) in vec2 inTail2; | |||||
layout (location = 4) in vec2 inTail3; | |||||
layout (location = 5) in vec2 inTail4; | |||||
out VertexData vertexData; | |||||
void main() { | |||||
vertexData.pos = inPosition; | |||||
vertexData.tail[0] = inTail0; | |||||
vertexData.tail[1] = inTail1; | |||||
vertexData.tail[2] = inTail2; | |||||
vertexData.tail[3] = inTail3; | |||||
vertexData.tail[4] = inTail4; | |||||
} |
@@ -1,17 +0,0 @@ | |||||
#version 450 core | |||||
#pragma include ./shared.glsl | |||||
#pragma include ../misc/camera.glsl | |||||
const float GLOW_SIZE_FACTOR = 4.00; | |||||
in vec3 inPosition; | |||||
uniform mat4 uModel; | |||||
out FragmentData fragmentData; | |||||
void main() { | |||||
fragmentData.texCoords = inPosition.xy * GLOW_SIZE_FACTOR + vec2(0.5); | |||||
gl_Position = uCamera.projection * uCamera.view * uModel * vec4(2.0 * inPosition * GLOW_SIZE_FACTOR, 1.0); | |||||
} |
@@ -1,11 +1,10 @@ | |||||
use std::time::Duration; | use std::time::Duration; | ||||
use glc::vector::Vector4f; | |||||
use glc::vector::Vector3f; | |||||
pub const UNIFORM_BUFFER_INDEX_CAMERA: gl::GLuint = 0; | pub const UNIFORM_BUFFER_INDEX_CAMERA: gl::GLuint = 0; | ||||
pub const UNIFORM_BUFFER_INDEX_UNIFORM: gl::GLuint = 1; | pub const UNIFORM_BUFFER_INDEX_UNIFORM: gl::GLuint = 1; | ||||
pub const SHIP_SIZE: f32 = 25.0; | |||||
pub const PLANET_SIZE: f32 = 200.0; | pub const PLANET_SIZE: f32 = 200.0; | ||||
pub const ASTEROID_SIZE: f32 = 100.0; | pub const ASTEROID_SIZE: f32 = 100.0; | ||||
@@ -16,4 +15,4 @@ pub const FLEET_SELECT_TEXT_OFFSET: f32 = 40.0; | |||||
pub const FLEET_SELECT_ANIMATION_TIME: f32 = 0.400; | pub const FLEET_SELECT_ANIMATION_TIME: f32 = 0.400; | ||||
pub const FLEET_SELECT_TEXT_SIZE: f32 = 24.0; | pub const FLEET_SELECT_TEXT_SIZE: f32 = 24.0; | ||||
pub const PLAYER_COLOR_DEFAULT: Vector4f = Vector4f::new(1.0, 1.0, 1.0, 0.1); | |||||
pub const PLAYER_COLOR_DEFAULT: Vector3f = Vector3f::new(1.0, 1.0, 1.0); |
@@ -1,4 +1,4 @@ | |||||
use glc::vector::Vector4f; | |||||
use glc::vector::Vector3f; | |||||
use log::{error, info}; | use log::{error, info}; | ||||
use rand::random; | use rand::random; | ||||
use space_crush_app::{App, Error}; | use space_crush_app::{App, Error}; | ||||
@@ -38,7 +38,7 @@ fn run(vfs: Vfs) -> Result<(), Error> { | |||||
let mut common = Dispatcher::new(&mut world)?; | let mut common = Dispatcher::new(&mut world)?; | ||||
let player1 = world | let player1 = world | ||||
.create_entity() | .create_entity() | ||||
.with(Player::new(Vector4f::new(0.0, 0.5, 1.0, 0.1))) | |||||
.with(Player::new(Vector3f::new(0.0, 0.5, 1.0))) | |||||
.build(); | .build(); | ||||
let mut app = App::new(&mut world, player1)?; | let mut app = App::new(&mut world, player1)?; | ||||
@@ -1,4 +1,5 @@ | |||||
mod events; | mod events; | ||||
// mod particles; | |||||
mod text; | mod text; | ||||
mod window; | mod window; | ||||
mod world; | mod world; | ||||
@@ -6,6 +7,7 @@ mod world; | |||||
pub use events::{ | pub use events::{ | ||||
ControlEvent, Events, KeyboardEvent, MouseButton, MouseEvent, VirtualKeyCode, WindowEvent, | ControlEvent, Events, KeyboardEvent, MouseButton, MouseEvent, VirtualKeyCode, WindowEvent, | ||||
}; | }; | ||||
// pub use particles::Particles; | |||||
pub use text::{HorizontalAlign, Text, TextCache, TextManager, VerticalAlign}; | pub use text::{HorizontalAlign, Text, TextCache, TextManager, VerticalAlign}; | ||||
pub use window::Window; | pub use window::Window; | ||||
pub use world::WorldHelper; | pub use world::WorldHelper; |
@@ -0,0 +1,222 @@ | |||||
use std::mem::swap; | |||||
use std::rc::Rc; | |||||
use glc::{ | |||||
buffer::Buffer, | |||||
misc::BindGuard, | |||||
transform_feedback::TransformFeedback, | |||||
vertex_array::{BindingBuilder, DataType, Pointer, VertexArray}, | |||||
}; | |||||
use space_crush_common::return_if_none; | |||||
use crate::Error; | |||||
type VertexArrayBuilder = BindingBuilder<Rc<Buffer>>; | |||||
/* Particles */ | |||||
pub struct Particles { | |||||
input: Buffers, | |||||
output: Buffers, | |||||
} | |||||
impl Particles { | |||||
pub fn builder() -> Builder { | |||||
Builder::default() | |||||
} | |||||
pub fn update(&mut self) { | |||||
let update_array = return_if_none!(&self.input.update_array); | |||||
gl::enable(gl::RASTERIZER_DISCARD); | |||||
let guard_buffer = BindGuard::new(update_array); | |||||
let guard_transform_feedback = BindGuard::new(&self.output.transform_feedback); | |||||
gl::begin_transform_feedback(gl::POINTS); | |||||
// TODO gl::draw_arrays(mode, 0, count as _); | |||||
gl::end_transform_feedback(); | |||||
gl::disable(gl::RASTERIZER_DISCARD); | |||||
drop(guard_buffer); | |||||
drop(guard_transform_feedback); | |||||
swap(&mut self.input, &mut self.output); | |||||
} | |||||
} | |||||
/* Buffer */ | |||||
struct Buffers { | |||||
transform_feedback: TransformFeedback<Rc<Buffer>>, | |||||
update_array: Option<VertexArray<Rc<Buffer>>>, | |||||
render_array: Option<VertexArray<Rc<Buffer>>>, | |||||
} | |||||
impl Buffers { | |||||
fn from_builder(builder: &Builder) -> Result<Self, Error> { | |||||
let mut transform_feedback = TransformFeedback::builder(); | |||||
let mut update_array: Option<VertexArrayBuilder> = None; | |||||
let mut render_array: Option<VertexArrayBuilder> = None; | |||||
let mut index = 0; | |||||
for b in &builder.buffers { | |||||
if b.render_pointers.is_empty() && b.update_pointers.is_empty() { | |||||
continue; | |||||
} | |||||
let buffer = Rc::new(Buffer::new()?); | |||||
transform_feedback = transform_feedback.bind_buffer(index, buffer.clone())?; | |||||
update_array = update_vertex_array(update_array, &buffer, &b.update_pointers)?; | |||||
render_array = update_vertex_array(render_array, &buffer, &b.render_pointers)?; | |||||
index += 1; | |||||
} | |||||
let transform_feedback = transform_feedback.build()?; | |||||
let update_array = match update_array { | |||||
Some(update_array) => Some(update_array.build()?), | |||||
None => None, | |||||
}; | |||||
let render_array = match render_array { | |||||
Some(render_array) => Some(render_array.build()?), | |||||
None => None, | |||||
}; | |||||
Ok(Self { | |||||
transform_feedback, | |||||
update_array, | |||||
render_array, | |||||
}) | |||||
} | |||||
} | |||||
fn update_vertex_array( | |||||
mut builder: Option<VertexArrayBuilder>, | |||||
buffer: &Rc<Buffer>, | |||||
pointers: &[Pointer], | |||||
) -> Result<Option<VertexArrayBuilder>, Error> { | |||||
if !pointers.is_empty() { | |||||
builder = match builder { | |||||
Some(builder) => Some(builder.bind_buffer(buffer.clone())), | |||||
None => Some(VertexArray::builder().bind_buffer(buffer.clone())), | |||||
}; | |||||
for p in pointers { | |||||
builder = Some(builder.unwrap().vertex_attrib_pointer( | |||||
p.index, | |||||
p.size, | |||||
p.type_, | |||||
p.normalize, | |||||
p.stride, | |||||
p.offset, | |||||
)?); | |||||
} | |||||
} | |||||
Ok(builder) | |||||
} | |||||
/* Builder */ | |||||
#[derive(Default)] | |||||
pub struct Builder { | |||||
buffers: Vec<BufferData>, | |||||
} | |||||
impl Builder { | |||||
pub fn add_buffer(mut self) -> BufferBuilder { | |||||
self.buffers.push(BufferData::default()); | |||||
BufferBuilder { builder: self } | |||||
} | |||||
fn build(self) -> Result<Particles, Error> { | |||||
let input = Buffers::from_builder(&self)?; | |||||
let output = Buffers::from_builder(&self)?; | |||||
Ok(Particles { input, output }) | |||||
} | |||||
} | |||||
/* BufferBuilder */ | |||||
#[derive(Default)] | |||||
pub struct BufferBuilder { | |||||
builder: Builder, | |||||
} | |||||
impl BufferBuilder { | |||||
pub fn add_buffer(self) -> BufferBuilder { | |||||
self.builder.add_buffer() | |||||
} | |||||
pub fn update_attrib_pointer( | |||||
mut self, | |||||
index: gl::GLuint, | |||||
size: gl::GLint, | |||||
type_: DataType, | |||||
normalize: bool, | |||||
stride: gl::GLsizei, | |||||
offset: gl::GLsizei, | |||||
) -> Result<Self, Error> { | |||||
self.builder | |||||
.buffers | |||||
.last_mut() | |||||
.unwrap() | |||||
.update_pointers | |||||
.push(Pointer { | |||||
index, | |||||
size, | |||||
type_, | |||||
normalize, | |||||
stride, | |||||
offset, | |||||
divisor: None, | |||||
}); | |||||
Ok(self) | |||||
} | |||||
pub fn render_attrib_pointer( | |||||
mut self, | |||||
index: gl::GLuint, | |||||
size: gl::GLint, | |||||
type_: DataType, | |||||
normalize: bool, | |||||
stride: gl::GLsizei, | |||||
offset: gl::GLsizei, | |||||
) -> Result<Self, Error> { | |||||
self.builder | |||||
.buffers | |||||
.last_mut() | |||||
.unwrap() | |||||
.render_pointers | |||||
.push(Pointer { | |||||
index, | |||||
size, | |||||
type_, | |||||
normalize, | |||||
stride, | |||||
offset, | |||||
divisor: None, | |||||
}); | |||||
Ok(self) | |||||
} | |||||
pub fn build(self) -> Result<Particles, Error> { | |||||
self.builder.build() | |||||
} | |||||
} | |||||
/* BufferData */ | |||||
#[derive(Default)] | |||||
struct BufferData { | |||||
update_pointers: Vec<Pointer>, | |||||
render_pointers: Vec<Pointer>, | |||||
} |
@@ -11,7 +11,7 @@ use std::ptr::null; | |||||
use std::rc::{Rc, Weak}; | use std::rc::{Rc, Weak}; | ||||
use glc::{ | use glc::{ | ||||
array_buffer::{ArrayBuffer, Target, Usage}, | |||||
buffer::{Buffer, Usage}, | |||||
error::Error as GlcError, | error::Error as GlcError, | ||||
misc::BindGuard, | misc::BindGuard, | ||||
shader::{Program, Type, Uniform}, | shader::{Program, Type, Uniform}, | ||||
@@ -592,7 +592,7 @@ impl Text { | |||||
const OFFSET_TEX_MAX: gl::GLsizei = OFFSET_TEX_MIN + SIZE_VEC2; | const OFFSET_TEX_MAX: gl::GLsizei = OFFSET_TEX_MIN + SIZE_VEC2; | ||||
const OFFSET_COLOR: gl::GLsizei = OFFSET_TEX_MAX + SIZE_VEC2; | const OFFSET_COLOR: gl::GLsizei = OFFSET_TEX_MAX + SIZE_VEC2; | ||||
let buffer = ArrayBuffer::new(Target::ArrayBuffer)?; | |||||
let buffer = Buffer::new()?; | |||||
let array = VertexArray::builder() | let array = VertexArray::builder() | ||||
.bind_buffer(buffer) | .bind_buffer(buffer) | ||||
.vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE, OFFSET_POS_MIN)? | .vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE, OFFSET_POS_MIN)? | ||||
@@ -643,9 +643,7 @@ impl Text { | |||||
.uniform(2, Uniform::Vector2f(pos)) | .uniform(2, Uniform::Vector2f(pos)) | ||||
.warn("Unable to update text offset"); | .warn("Unable to update text offset"); | ||||
// gl::draw_arrays(gl::POINTS, 0, inner.vertex_count as _); | |||||
gl::draw_arrays(gl::POINTS, 0, inner.vertex_count as _); | gl::draw_arrays(gl::POINTS, 0, inner.vertex_count as _); | ||||
// gl::draw_arrays_instanced(gl::POINTS, 0, 1, inner.vertex_count as _); | |||||
} | } | ||||
pub fn update<S>(&mut self, mut index: usize, text: S) -> Result<&Self, Error> | pub fn update<S>(&mut self, mut index: usize, text: S) -> Result<&Self, Error> | ||||
@@ -17,6 +17,8 @@ pub trait WorldHelper { | |||||
where | where | ||||
I: IntoIterator<Item = (Type, &'static str)>; | I: IntoIterator<Item = (Type, &'static str)>; | ||||
fn load_shader(&self, type_: Type, file: &str) -> Result<Shader, Error>; | |||||
fn load_texture(&self, path: &str) -> Result<Texture, Error>; | fn load_texture(&self, path: &str) -> Result<Texture, Error>; | ||||
} | } | ||||
@@ -25,39 +27,40 @@ impl WorldHelper for World { | |||||
where | where | ||||
I: IntoIterator<Item = (Type, &'static str)>, | I: IntoIterator<Item = (Type, &'static str)>, | ||||
{ | { | ||||
let vfs = self.fetch::<Vfs>(); | |||||
Program::from_shaders_result(iter.into_iter().map(|(t, p)| self.load_shader(t, p))) | |||||
} | |||||
Program::from_shaders_result(iter.into_iter().map(|(t, p)| { | |||||
let path = vfs.join(p)?; | |||||
let mut file = path.open_file()?; | |||||
let path = path.parent().unwrap(); | |||||
let shader = Shader::from_reader(t, &mut file, |include| { | |||||
let p = if include.starts_with('.') { | |||||
path.join(include) | |||||
} else { | |||||
vfs.join(include) | |||||
}; | |||||
let p = match p { | |||||
Ok(p) => p, | |||||
Err(err) => return Err(GlcError::ShaderInclude(format!("{}", err))), | |||||
}; | |||||
let mut r = match p.open_file() { | |||||
Ok(r) => r, | |||||
Err(err) => return Err(GlcError::ShaderInclude(format!("{}", err))), | |||||
}; | |||||
let mut code = String::default(); | |||||
if let Err(err) = r.read_to_string(&mut code) { | |||||
return Err(GlcError::ShaderInclude(format!("{}", err))); | |||||
} | |||||
Ok(code) | |||||
})?; | |||||
Ok(shader) | |||||
})) | |||||
fn load_shader(&self, type_: Type, path: &str) -> Result<Shader, Error> { | |||||
let vfs = self.fetch::<Vfs>(); | |||||
let path = vfs.join(path)?; | |||||
let mut file = path.open_file()?; | |||||
let path = path.parent().unwrap(); | |||||
let shader = Shader::from_reader(type_, &mut file, |include| { | |||||
let p = if include.starts_with('.') { | |||||
path.join(include) | |||||
} else { | |||||
vfs.join(include) | |||||
}; | |||||
let p = match p { | |||||
Ok(p) => p, | |||||
Err(err) => return Err(GlcError::ShaderInclude(format!("{}", err))), | |||||
}; | |||||
let mut r = match p.open_file() { | |||||
Ok(r) => r, | |||||
Err(err) => return Err(GlcError::ShaderInclude(format!("{}", err))), | |||||
}; | |||||
let mut code = String::default(); | |||||
if let Err(err) = r.read_to_string(&mut code) { | |||||
return Err(GlcError::ShaderInclude(format!("{}", err))); | |||||
} | |||||
Ok(code) | |||||
})?; | |||||
Ok(shader) | |||||
} | } | ||||
fn load_texture(&self, path: &str) -> Result<Texture, Error> { | fn load_texture(&self, path: &str) -> Result<Texture, Error> { | ||||
@@ -1,15 +1,18 @@ | |||||
use std::mem::size_of; | |||||
use glc::{ | use glc::{ | ||||
matrix::Matrix4f, | |||||
buffer::{Buffer, Usage}, | |||||
misc::{BindGuard, Bindable}, | misc::{BindGuard, Bindable}, | ||||
shader::{Program, Type, Uniform}, | shader::{Program, Type, Uniform}, | ||||
texture::Texture, | texture::Texture, | ||||
vector::Vector4f, | |||||
vector::{Vector2f, Vector3f}, | |||||
vertex_array::{DataType, VertexArray}, | |||||
}; | }; | ||||
use space_crush_common::{ | use space_crush_common::{ | ||||
components::{Asteroid, AsteroidType, Player, PlayerOwned, Position}, | components::{Asteroid, AsteroidType, Player, PlayerOwned, Position}, | ||||
misc::LogResult, | |||||
misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, | |||||
}; | }; | ||||
use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | |||||
use specs::{prelude::*, ReadStorage, System, World}; | |||||
use crate::{ | use crate::{ | ||||
constants::{ | constants::{ | ||||
@@ -17,7 +20,6 @@ use crate::{ | |||||
UNIFORM_BUFFER_INDEX_UNIFORM, | UNIFORM_BUFFER_INDEX_UNIFORM, | ||||
}, | }, | ||||
misc::WorldHelper, | misc::WorldHelper, | ||||
resources::Geometry, | |||||
Error, | Error, | ||||
}; | }; | ||||
@@ -25,47 +27,76 @@ pub struct Asteroids { | |||||
program: Program, | program: Program, | ||||
texture_metal: Texture, | texture_metal: Texture, | ||||
texture_crystal: Texture, | texture_crystal: Texture, | ||||
location_model: gl::GLint, | |||||
location_glow_color: gl::GLint, | |||||
vertex_array: VertexArray, | |||||
reader_id: ReaderId<ComponentEvent<Asteroid>>, | |||||
asteroid_count: usize, | |||||
} | |||||
#[repr(C, packed)] | |||||
struct VertexData { | |||||
pos: Vector2f, | |||||
size: gl::GLfloat, | |||||
color: Vector3f, | |||||
texture: gl::GLint, | |||||
} | } | ||||
impl Asteroids { | impl Asteroids { | ||||
pub fn new(world: &World) -> Result<Self, Error> { | |||||
pub fn new(world: &mut World) -> Result<Self, Error> { | |||||
WriteStorage::<Asteroid>::setup(world); | |||||
let program = world.load_program(vec![ | let program = world.load_program(vec![ | ||||
(Type::Vertex, "resources/shader/asteroid/vert.glsl"), | (Type::Vertex, "resources/shader/asteroid/vert.glsl"), | ||||
(Type::Geometry, "resources/shader/asteroid/geom.glsl"), | |||||
(Type::Fragment, "resources/shader/asteroid/frag.glsl"), | (Type::Fragment, "resources/shader/asteroid/frag.glsl"), | ||||
])?; | ])?; | ||||
program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | ||||
program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; | program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; | ||||
let location_model = program.uniform_location("uModel")?; | |||||
let location_glow_color = program.uniform_location("uGlowColor")?; | |||||
program.bind(); | program.bind(); | ||||
program.uniform("uTexture", Uniform::Texture(0))?; | |||||
program.uniform("uTexture", Uniform::TextureVec(&[0, 1]))?; | |||||
program.unbind(); | program.unbind(); | ||||
let texture_metal = world.load_texture("resources/textures/asteroid_metal.png")?; | let texture_metal = world.load_texture("resources/textures/asteroid_metal.png")?; | ||||
let texture_crystal = world.load_texture("resources/textures/asteroid_crystal.png")?; | let texture_crystal = world.load_texture("resources/textures/asteroid_crystal.png")?; | ||||
const STRIDE: gl::GLsizei = size_of::<VertexData>() as gl::GLsizei; | |||||
const OFFSET_POS: gl::GLsizei = 0; | |||||
const OFFSET_SIZ: gl::GLsizei = OFFSET_POS + size_of::<Vector2f>() as gl::GLsizei; | |||||
const OFFSET_CLR: gl::GLsizei = OFFSET_SIZ + size_of::<gl::GLfloat>() as gl::GLsizei; | |||||
const OFFSET_TEX: gl::GLsizei = OFFSET_CLR + size_of::<Vector3f>() as gl::GLsizei; | |||||
let vertex_array = VertexArray::builder() | |||||
.bind_buffer(Buffer::new()?) | |||||
.vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE, OFFSET_POS)? | |||||
.vertex_attrib_pointer(1, 1, DataType::Float, false, STRIDE, OFFSET_SIZ)? | |||||
.vertex_attrib_pointer(2, 3, DataType::Float, false, STRIDE, OFFSET_CLR)? | |||||
.vertex_attrib_pointer(3, 1, DataType::Int, false, STRIDE, OFFSET_TEX)? | |||||
.build()?; | |||||
let reader_id = world | |||||
.system_data::<WriteStorage<Asteroid>>() | |||||
.register_event_reader(); | |||||
let asteroid_count = 0; | |||||
Ok(Self { | Ok(Self { | ||||
program, | program, | ||||
texture_metal, | texture_metal, | ||||
texture_crystal, | texture_crystal, | ||||
location_model, | |||||
location_glow_color, | |||||
vertex_array, | |||||
reader_id, | |||||
asteroid_count, | |||||
}) | }) | ||||
} | } | ||||
} | } | ||||
#[derive(SystemData)] | #[derive(SystemData)] | ||||
pub struct AsteroidsData<'a> { | pub struct AsteroidsData<'a> { | ||||
geometry: ReadExpect<'a, Geometry>, | |||||
position: ReadStorage<'a, Position>, | |||||
asteroid: ReadStorage<'a, Asteroid>, | |||||
positions: ReadStorage<'a, Position>, | |||||
asteroids: ReadStorage<'a, Asteroid>, | |||||
players: ReadStorage<'a, Player>, | |||||
owned: ReadStorage<'a, PlayerOwned>, | owned: ReadStorage<'a, PlayerOwned>, | ||||
player: ReadStorage<'a, Player>, | |||||
} | } | ||||
impl<'a> System<'a> for Asteroids { | impl<'a> System<'a> for Asteroids { | ||||
@@ -73,50 +104,77 @@ impl<'a> System<'a> for Asteroids { | |||||
fn run(&mut self, data: Self::SystemData) { | fn run(&mut self, data: Self::SystemData) { | ||||
let AsteroidsData { | let AsteroidsData { | ||||
geometry, | |||||
position, | |||||
asteroid, | |||||
positions, | |||||
asteroids, | |||||
players, | |||||
owned, | owned, | ||||
player, | |||||
} = data; | } = data; | ||||
gl::enable(gl::BLEND); | |||||
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | |||||
/* handle events */ | |||||
let mut need_update = false; | |||||
let events = asteroids.channel().read(&mut self.reader_id); | |||||
for event in events { | |||||
match event { | |||||
ComponentEvent::Inserted(_, _) => { | |||||
need_update = true; | |||||
self.asteroid_count += 1; | |||||
} | |||||
ComponentEvent::Removed(_, _) => { | |||||
need_update = true; | |||||
self.asteroid_count -= 1; | |||||
} | |||||
ComponentEvent::Modified(_, _) => { | |||||
unreachable!("Updates of the asteroid component should not be tracked!") | |||||
} | |||||
} | |||||
} | |||||
/* update vertex array */ | |||||
let buffer = &mut self.vertex_array.buffers_mut()[0]; | |||||
if need_update { | |||||
buffer | |||||
.buffer_size( | |||||
Usage::StaticDraw, | |||||
self.asteroid_count * size_of::<VertexData>(), | |||||
) | |||||
.panic("Unable to change buffer size for asteroid data"); | |||||
let data = (&positions, &asteroids, owned.maybe()); | |||||
let mut buffer = buffer | |||||
.map_mut::<VertexData>(true) | |||||
.panic("Unable to map buffer for asteroid data"); | |||||
for (i, (position, asteroid, owned)) in data.join().enumerate() { | |||||
let mut d = &mut buffer[i]; | |||||
d.pos = *position.pos(); | |||||
d.size = position.shape().circle().unwrap_or(ASTEROID_SIZE); | |||||
d.color = match owned.and_then(|owned| players.get(owned.owner())) { | |||||
Some(pv) => *pv.color(), | |||||
None => PLAYER_COLOR_DEFAULT, | |||||
}; | |||||
d.texture = match asteroid.type_() { | |||||
AsteroidType::Metal => 0, | |||||
AsteroidType::Crystal => 1, | |||||
}; | |||||
} | |||||
} | |||||
/* render asteroids */ | |||||
let _guard = BindGuard::new(&self.program); | let _guard = BindGuard::new(&self.program); | ||||
let _guard = BindGuard::new(&self.vertex_array); | |||||
for (position, asteroid, owned) in (&position, &asteroid, owned.maybe()).join() { | |||||
let p_x = position.pos().x; | |||||
let p_y = position.pos().y; | |||||
let s = position.shape().circle().unwrap_or(ASTEROID_SIZE); | |||||
let _guard = match asteroid.type_() { | |||||
AsteroidType::Metal => BindGuard::new(&self.texture_metal), | |||||
AsteroidType::Crystal => BindGuard::new(&self.texture_crystal), | |||||
}; | |||||
let c = match owned.and_then(|owned| player.get(owned.owner())) { | |||||
Some(pv) => pv.color(), | |||||
None => &PLAYER_COLOR_DEFAULT, | |||||
}; | |||||
let m = Matrix4f::new( | |||||
Vector4f::new(s, 0.0, 0.0, 0.0), | |||||
Vector4f::new(0.0, s, 0.0, 0.0), | |||||
Vector4f::new(0.0, 0.0, s, 0.0), | |||||
Vector4f::new(p_x, p_y, 0.0, 1.0), | |||||
); | |||||
self.program | |||||
.uniform(self.location_glow_color, Uniform::Vector4f(&c)) | |||||
.error("Error while updating glow color"); | |||||
self.program | |||||
.uniform(self.location_model, Uniform::Matrix4f(&m)) | |||||
.error("Error while updating model matrix"); | |||||
geometry.render_quad(); | |||||
} | |||||
gl::active_texture(gl::TEXTURE1); | |||||
let _guard = BindGuard::new(&self.texture_crystal); | |||||
gl::active_texture(gl::TEXTURE0); | |||||
let _guard = BindGuard::new(&self.texture_metal); | |||||
gl::enable(gl::BLEND); | |||||
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | |||||
gl::draw_arrays(gl::POINTS, 0, self.asteroid_count as _); | |||||
gl::disable(gl::BLEND); | gl::disable(gl::BLEND); | ||||
} | } | ||||
} | } |
@@ -1,15 +1,18 @@ | |||||
use std::mem::size_of; | |||||
use glc::{ | use glc::{ | ||||
matrix::Matrix4f, | |||||
buffer::{Buffer, Usage}, | |||||
misc::{BindGuard, Bindable}, | misc::{BindGuard, Bindable}, | ||||
shader::{Program, Type, Uniform}, | shader::{Program, Type, Uniform}, | ||||
texture::Texture, | texture::Texture, | ||||
vector::Vector4f, | |||||
vector::{Vector2f, Vector3f}, | |||||
vertex_array::{DataType, VertexArray}, | |||||
}; | }; | ||||
use space_crush_common::{ | use space_crush_common::{ | ||||
components::{Planet, Player, PlayerOwned, Position}, | components::{Planet, Player, PlayerOwned, Position}, | ||||
misc::LogResult, | |||||
misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, | |||||
}; | }; | ||||
use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | |||||
use specs::{prelude::*, ReadStorage, System, World}; | |||||
use crate::{ | use crate::{ | ||||
constants::{ | constants::{ | ||||
@@ -17,52 +20,77 @@ use crate::{ | |||||
UNIFORM_BUFFER_INDEX_UNIFORM, | UNIFORM_BUFFER_INDEX_UNIFORM, | ||||
}, | }, | ||||
misc::WorldHelper, | misc::WorldHelper, | ||||
resources::Geometry, | |||||
Error, | Error, | ||||
}; | }; | ||||
pub struct Planets { | pub struct Planets { | ||||
program: Program, | program: Program, | ||||
texture: Texture, | texture: Texture, | ||||
location_model: gl::GLint, | |||||
location_glow_color: gl::GLint, | |||||
vertex_array: VertexArray, | |||||
reader_id: ReaderId<ComponentEvent<Planet>>, | |||||
planet_count: usize, | |||||
} | |||||
#[repr(C, packed)] | |||||
struct VertexData { | |||||
pos: Vector2f, | |||||
size: gl::GLfloat, | |||||
color: Vector3f, | |||||
} | } | ||||
impl Planets { | impl Planets { | ||||
pub fn new(world: &World) -> Result<Self, Error> { | |||||
pub fn new(world: &mut World) -> Result<Self, Error> { | |||||
WriteStorage::<Planet>::setup(world); | |||||
let program = world.load_program(vec![ | let program = world.load_program(vec![ | ||||
(Type::Vertex, "resources/shader/planet/vert.glsl"), | (Type::Vertex, "resources/shader/planet/vert.glsl"), | ||||
(Type::Geometry, "resources/shader/planet/geom.glsl"), | |||||
(Type::Fragment, "resources/shader/planet/frag.glsl"), | (Type::Fragment, "resources/shader/planet/frag.glsl"), | ||||
])?; | ])?; | ||||
program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | ||||
program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; | program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; | ||||
let location_model = program.uniform_location("uModel")?; | |||||
let location_glow_color = program.uniform_location("uGlowColor")?; | |||||
program.bind(); | program.bind(); | ||||
program.uniform("uTexture", Uniform::Texture(0))?; | program.uniform("uTexture", Uniform::Texture(0))?; | ||||
program.unbind(); | program.unbind(); | ||||
let texture = world.load_texture("resources/textures/planet01.png")?; | let texture = world.load_texture("resources/textures/planet01.png")?; | ||||
const STRIDE: gl::GLsizei = size_of::<VertexData>() as gl::GLsizei; | |||||
const OFFSET_POS: gl::GLsizei = 0; | |||||
const OFFSET_SIZ: gl::GLsizei = OFFSET_POS + size_of::<Vector2f>() as gl::GLsizei; | |||||
const OFFSET_CLR: gl::GLsizei = OFFSET_SIZ + size_of::<gl::GLfloat>() as gl::GLsizei; | |||||
let vertex_array = VertexArray::builder() | |||||
.bind_buffer(Buffer::new()?) | |||||
.vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE, OFFSET_POS)? | |||||
.vertex_attrib_pointer(1, 1, DataType::Float, false, STRIDE, OFFSET_SIZ)? | |||||
.vertex_attrib_pointer(2, 3, DataType::Float, false, STRIDE, OFFSET_CLR)? | |||||
.build()?; | |||||
let reader_id = world | |||||
.system_data::<WriteStorage<Planet>>() | |||||
.register_event_reader(); | |||||
let planet_count = 0; | |||||
Ok(Self { | Ok(Self { | ||||
program, | program, | ||||
texture, | texture, | ||||
location_model, | |||||
location_glow_color, | |||||
vertex_array, | |||||
reader_id, | |||||
planet_count, | |||||
}) | }) | ||||
} | } | ||||
} | } | ||||
#[derive(SystemData)] | #[derive(SystemData)] | ||||
pub struct PlanetsData<'a> { | pub struct PlanetsData<'a> { | ||||
geometry: ReadExpect<'a, Geometry>, | |||||
position: ReadStorage<'a, Position>, | |||||
planet: ReadStorage<'a, Planet>, | |||||
positions: ReadStorage<'a, Position>, | |||||
planets: ReadStorage<'a, Planet>, | |||||
players: ReadStorage<'a, Player>, | |||||
owned: ReadStorage<'a, PlayerOwned>, | owned: ReadStorage<'a, PlayerOwned>, | ||||
player: ReadStorage<'a, Player>, | |||||
} | } | ||||
impl<'a> System<'a> for Planets { | impl<'a> System<'a> for Planets { | ||||
@@ -70,46 +98,68 @@ impl<'a> System<'a> for Planets { | |||||
fn run(&mut self, data: Self::SystemData) { | fn run(&mut self, data: Self::SystemData) { | ||||
let PlanetsData { | let PlanetsData { | ||||
geometry, | |||||
position, | |||||
planet, | |||||
positions, | |||||
planets, | |||||
players, | |||||
owned, | owned, | ||||
player, | |||||
} = data; | } = data; | ||||
gl::enable(gl::BLEND); | |||||
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | |||||
/* handle events */ | |||||
let mut need_update = false; | |||||
let events = planets.channel().read(&mut self.reader_id); | |||||
for event in events { | |||||
match event { | |||||
ComponentEvent::Inserted(_, _) => { | |||||
need_update = true; | |||||
self.planet_count += 1; | |||||
} | |||||
ComponentEvent::Removed(_, _) => { | |||||
need_update = true; | |||||
self.planet_count -= 1; | |||||
} | |||||
ComponentEvent::Modified(_, _) => { | |||||
unreachable!("Updates of the planet component should not be tracked!") | |||||
} | |||||
} | |||||
} | |||||
/* update vertex array */ | |||||
let buffer = &mut self.vertex_array.buffers_mut()[0]; | |||||
if need_update { | |||||
buffer | |||||
.buffer_size( | |||||
Usage::StaticDraw, | |||||
self.planet_count * size_of::<VertexData>(), | |||||
) | |||||
.panic("Unable to change buffer size for planet data"); | |||||
let data = (&positions, &planets, owned.maybe()); | |||||
let mut buffer = buffer | |||||
.map_mut::<VertexData>(true) | |||||
.panic("Unable to map buffer for planet data"); | |||||
for (i, (position, _, owned)) in data.join().enumerate() { | |||||
let mut d = &mut buffer[i]; | |||||
d.pos = *position.pos(); | |||||
d.size = position.shape().circle().unwrap_or(PLANET_SIZE); | |||||
d.color = match owned.and_then(|owned| players.get(owned.owner())) { | |||||
Some(pv) => *pv.color(), | |||||
None => PLAYER_COLOR_DEFAULT, | |||||
}; | |||||
} | |||||
} | |||||
/* render planets */ | |||||
let _guard = BindGuard::new(&self.program); | let _guard = BindGuard::new(&self.program); | ||||
let _guard = BindGuard::new(&self.vertex_array); | |||||
let _guard = BindGuard::new(&self.texture); | let _guard = BindGuard::new(&self.texture); | ||||
for (p, _, owned) in (&position, &planet, owned.maybe()).join() { | |||||
let p_x = p.pos().x; | |||||
let p_y = p.pos().y; | |||||
let s = p.shape().circle().unwrap_or(PLANET_SIZE); | |||||
let c = match owned.and_then(|owned| player.get(owned.owner())) { | |||||
Some(pv) => &pv.color(), | |||||
None => &PLAYER_COLOR_DEFAULT, | |||||
}; | |||||
let m = Matrix4f::new( | |||||
Vector4f::new(s, 0.0, 0.0, 0.0), | |||||
Vector4f::new(0.0, s, 0.0, 0.0), | |||||
Vector4f::new(0.0, 0.0, s, 0.0), | |||||
Vector4f::new(p_x, p_y, 0.0, 1.0), | |||||
); | |||||
self.program | |||||
.uniform(self.location_glow_color, Uniform::Vector4f(&c)) | |||||
.error("Error while updating glow color"); | |||||
self.program | |||||
.uniform(self.location_model, Uniform::Matrix4f(&m)) | |||||
.error("Error while updating model matrix"); | |||||
geometry.render_quad(); | |||||
} | |||||
gl::enable(gl::BLEND); | |||||
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | |||||
gl::draw_arrays(gl::POINTS, 0, self.planet_count as _); | |||||
gl::disable(gl::BLEND); | gl::disable(gl::BLEND); | ||||
} | } | ||||
} | } |
@@ -1,129 +1,413 @@ | |||||
use std::cell::RefCell; | |||||
use std::mem::{size_of, swap}; | |||||
use std::rc::Rc; | |||||
use glc::{ | use glc::{ | ||||
matrix::Matrix4f, | |||||
buffer::{Buffer, Usage}, | |||||
misc::{BindGuard, Bindable}, | misc::{BindGuard, Bindable}, | ||||
shader::{Program, Type, Uniform}, | |||||
shader::{Program, TransformFeedbackVaryingsMode, Type, Uniform}, | |||||
texture::Texture, | texture::Texture, | ||||
vector::Vector4f, | |||||
transform_feedback::TransformFeedback, | |||||
vector::{Vector2f, Vector3f}, | |||||
vertex_array::{DataType, VertexArray}, | |||||
}; | }; | ||||
use space_crush_common::{ | use space_crush_common::{ | ||||
components::{Player, PlayerOwned, Position, Ship, ShipType, Velocity}, | components::{Player, PlayerOwned, Position, Ship, ShipType, Velocity}, | ||||
misc::LogResult, | |||||
misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, | |||||
}; | |||||
use specs::{ | |||||
hibitset::{BitSet, BitSetAll, BitSetLike}, | |||||
prelude::*, | |||||
world::Index as Id, | |||||
ReadStorage, System, World, | |||||
}; | }; | ||||
use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | |||||
use crate::{ | use crate::{ | ||||
constants::{ | |||||
PLAYER_COLOR_DEFAULT, SHIP_SIZE, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM, | |||||
}, | |||||
constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||||
misc::WorldHelper, | misc::WorldHelper, | ||||
resources::Geometry, | |||||
Error, | Error, | ||||
}; | }; | ||||
pub struct Ships { | pub struct Ships { | ||||
program: Program, | |||||
program_ship: Program, | |||||
program_tail_update: Program, | |||||
program_tail_render: Program, | |||||
ship_data: BufferRef, | |||||
ship_render: VertexArray<BufferRef>, | |||||
input: TailObjects, | |||||
output: TailObjects, | |||||
texture_bomber: Texture, | texture_bomber: Texture, | ||||
texture_fighter: Texture, | texture_fighter: Texture, | ||||
texture_transporter: Texture, | texture_transporter: Texture, | ||||
location_model: gl::GLint, | |||||
location_glow_color: gl::GLint, | |||||
reader_id: ReaderId<ComponentEvent<Ship>>, | |||||
need_init: BitSet, | |||||
id_to_index: Vec<u32>, | |||||
index_to_id: Vec<Id>, | |||||
} | |||||
#[derive(SystemData)] | |||||
pub struct ShipsData<'a> { | |||||
positions: ReadStorage<'a, Position>, | |||||
velocities: ReadStorage<'a, Velocity>, | |||||
players: ReadStorage<'a, Player>, | |||||
owned: ReadStorage<'a, PlayerOwned>, | |||||
ships: ReadStorage<'a, Ship>, | |||||
} | |||||
struct TailObjects { | |||||
tail_data: BufferRef, | |||||
tail_update: VertexArray<BufferRef>, | |||||
tail_render: VertexArray<BufferRef>, | |||||
transform_feedback: TransformFeedback<BufferRef>, | |||||
} | |||||
type BufferRef = Rc<RefCell<Buffer>>; | |||||
#[repr(C, packed)] | |||||
struct ShipData { | |||||
pos: Vector2f, | |||||
dir: Vector2f, | |||||
color: Vector3f, | |||||
texture: gl::GLint, | |||||
} | |||||
#[repr(C, packed)] | |||||
#[derive(Debug)] | |||||
struct TailData { | |||||
pos: [Vector2f; 5], | |||||
} | } | ||||
impl Ships { | impl Ships { | ||||
pub fn new(world: &World) -> Result<Self, Error> { | pub fn new(world: &World) -> Result<Self, Error> { | ||||
let program = world.load_program(vec![ | |||||
(Type::Vertex, "resources/shader/ship/vert.glsl"), | |||||
(Type::Fragment, "resources/shader/ship/frag.glsl"), | |||||
/* program ship */ | |||||
let program_ship = world.load_program(vec![ | |||||
(Type::Vertex, SHDR_SHIP_VERT), | |||||
(Type::Geometry, SHDR_SHIP_GEOM), | |||||
(Type::Fragment, SHDR_SHIP_FRAG), | |||||
])?; | |||||
program_ship.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | |||||
program_ship.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; | |||||
program_ship.bind(); | |||||
program_ship.uniform("uTexture", Uniform::TextureVec(&[0, 1, 2]))?; | |||||
program_ship.unbind(); | |||||
/* program tail update */ | |||||
let program_tail_update = Program::builder() | |||||
.add_shader(world.load_shader(Type::Vertex, SHDR_TAIL_UPDATE_VERT)?) | |||||
.add_shader(world.load_shader(Type::Geometry, SHDR_TAIL_UPDATE_GEOM)?) | |||||
.set_transform_feedback_varyings( | |||||
TransformFeedbackVaryingsMode::Interleaved, | |||||
SHDR_TAIL_VARYINGS, | |||||
) | |||||
.build()?; | |||||
program_tail_update.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; | |||||
/* program tail render */ | |||||
let program_tail_render = world.load_program(vec![ | |||||
(Type::Vertex, SHDR_TAIL_RENDER_VERT), | |||||
(Type::Geometry, SHDR_TAIL_RENDER_GEOM), | |||||
(Type::Fragment, SHDR_TAIL_RENDER_FRAG), | |||||
])?; | ])?; | ||||
program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | |||||
program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; | |||||
program_tail_render.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | |||||
/* ship data */ | |||||
let ship_data = Rc::new(RefCell::new(Buffer::new()?)); | |||||
let location_model = program.uniform_location("uModel")?; | |||||
let location_glow_color = program.uniform_location("uGlowColor")?; | |||||
/* vertex array ship */ | |||||
let ship_render = VertexArray::builder() | |||||
.bind_buffer(ship_data.clone()) | |||||
.vertex_attrib_pointer(0, 2, DataType::Float, false, SHIP_STRIDE, SHIP_OFFSET_POS)? | |||||
.vertex_attrib_pointer(1, 2, DataType::Float, false, SHIP_STRIDE, SHIP_OFFSET_DIR)? | |||||
.vertex_attrib_pointer(2, 3, DataType::Float, false, SHIP_STRIDE, SHIP_OFFSET_CLR)? | |||||
.vertex_attrib_pointer(3, 1, DataType::Int, false, SHIP_STRIDE, SHIP_OFFSET_TEX)? | |||||
.build()?; | |||||
program.bind(); | |||||
program.uniform("uTexture", Uniform::Texture(0))?; | |||||
program.unbind(); | |||||
/* tail objects */ | |||||
let input = TailObjects::new(&ship_data)?; | |||||
let output = TailObjects::new(&ship_data)?; | |||||
/* textures */ | |||||
let texture_bomber = world.load_texture("resources/textures/ship_bomber.png")?; | let texture_bomber = world.load_texture("resources/textures/ship_bomber.png")?; | ||||
let texture_fighter = world.load_texture("resources/textures/ship_fighter.png")?; | let texture_fighter = world.load_texture("resources/textures/ship_fighter.png")?; | ||||
let texture_transporter = world.load_texture("resources/textures/ship_transporter.png")?; | let texture_transporter = world.load_texture("resources/textures/ship_transporter.png")?; | ||||
/* event readers */ | |||||
let reader_id = world | |||||
.system_data::<WriteStorage<Ship>>() | |||||
.register_event_reader(); | |||||
/* rest */ | |||||
let need_init = BitSet::new(); | |||||
let id_to_index = Vec::new(); | |||||
let index_to_id = Vec::new(); | |||||
Ok(Self { | Ok(Self { | ||||
program, | |||||
program_ship, | |||||
program_tail_update, | |||||
program_tail_render, | |||||
ship_data, | |||||
ship_render, | |||||
input, | |||||
output, | |||||
texture_bomber, | texture_bomber, | ||||
texture_fighter, | texture_fighter, | ||||
texture_transporter, | texture_transporter, | ||||
location_model, | |||||
location_glow_color, | |||||
reader_id, | |||||
need_init, | |||||
id_to_index, | |||||
index_to_id, | |||||
}) | }) | ||||
} | } | ||||
} | |||||
#[derive(SystemData)] | |||||
pub struct ShipsData<'a> { | |||||
geometry: ReadExpect<'a, Geometry>, | |||||
position: ReadStorage<'a, Position>, | |||||
velocity: ReadStorage<'a, Velocity>, | |||||
ship: ReadStorage<'a, Ship>, | |||||
owned: ReadStorage<'a, PlayerOwned>, | |||||
player: ReadStorage<'a, Player>, | |||||
fn handle_events(&mut self, d: &ShipsData<'_>) { | |||||
self.need_init.clear(); | |||||
let events = d.ships.channel().read(&mut self.reader_id); | |||||
for event in events { | |||||
match event { | |||||
ComponentEvent::Inserted(id, _) => self.add_ship(*id), | |||||
ComponentEvent::Removed(id, _) => self.remove_ship(*id), | |||||
ComponentEvent::Modified(_, _) => { | |||||
unreachable!("Updates of the ship component should not be tracked!") | |||||
} | |||||
} | |||||
} | |||||
} | |||||
fn update_vertices(&self, d: &ShipsData<'_>) { | |||||
let mut borrow_ship = self.ship_data.borrow_mut(); | |||||
let mut buf_ship = borrow_ship | |||||
.map_mut::<ShipData>(true) | |||||
.panic("Unable to map buffer for ship data"); | |||||
let ids = BitSetAll; | |||||
let data = ( | |||||
&ids as &dyn BitSetLike, | |||||
&d.positions, | |||||
&d.velocities, | |||||
&d.ships, | |||||
d.owned.maybe(), | |||||
); | |||||
for (id, position, velocity, ship, owned) in data.join() { | |||||
let index = self.id_to_index[id as usize]; | |||||
let mut s = &mut buf_ship[index as usize]; | |||||
s.pos = *position.pos(); | |||||
s.dir = *velocity.dir(); | |||||
if self.need_init.contains(id) { | |||||
s.color = match owned.and_then(|owned| d.players.get(owned.owner())) { | |||||
Some(pv) => *pv.color(), | |||||
None => PLAYER_COLOR_DEFAULT, | |||||
}; | |||||
s.texture = match ship.type_() { | |||||
ShipType::Fighter => 0, | |||||
ShipType::Bomber => 1, | |||||
ShipType::Transporter => 2, | |||||
}; | |||||
let mut pos = *position.pos(); | |||||
let mut borrow_tail = self.input.tail_data.borrow_mut(); | |||||
let mut buf_tail = borrow_tail | |||||
.map_mut::<TailData>(true) | |||||
.panic("Unable to map buffer for tail data"); | |||||
for p in &mut buf_tail[index as usize].pos { | |||||
pos -= Vector2f::new(10.0, 0.0); | |||||
*p = pos; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
fn update_tail(&mut self) { | |||||
let guard_prog = BindGuard::new(&self.program_tail_update); | |||||
let guard_trfm = BindGuard::new(&self.output.transform_feedback); | |||||
let guard_data = BindGuard::new(&self.input.tail_update); | |||||
gl::enable(gl::RASTERIZER_DISCARD); | |||||
gl::begin_transform_feedback(gl::POINTS); | |||||
gl::draw_arrays(gl::POINTS, 0, self.index_to_id.len() as _); | |||||
gl::end_transform_feedback(); | |||||
gl::disable(gl::RASTERIZER_DISCARD); | |||||
drop(guard_trfm); | |||||
drop(guard_data); | |||||
drop(guard_prog); | |||||
swap(&mut self.input, &mut self.output); | |||||
} | |||||
fn render_tails(&self) { | |||||
let _guard = BindGuard::new(&self.program_tail_render); | |||||
let _guard = BindGuard::new(&self.input.tail_render); | |||||
gl::enable(gl::BLEND); | |||||
gl::blend_func(gl::SRC_ALPHA, gl::ONE); | |||||
gl::draw_arrays(gl::POINTS, 0, self.index_to_id.len() as _); | |||||
gl::disable(gl::BLEND); | |||||
} | |||||
fn render_ships(&self) { | |||||
let _guard = BindGuard::new(&self.program_ship); | |||||
let _guard = BindGuard::new(&self.ship_render); | |||||
gl::active_texture(gl::TEXTURE2); | |||||
let _guard = BindGuard::new(&self.texture_transporter); | |||||
gl::active_texture(gl::TEXTURE1); | |||||
let _guard = BindGuard::new(&self.texture_bomber); | |||||
gl::active_texture(gl::TEXTURE0); | |||||
let _guard = BindGuard::new(&self.texture_fighter); | |||||
gl::enable(gl::BLEND); | |||||
gl::blend_func(gl::SRC_ALPHA, gl::ONE); | |||||
gl::draw_arrays(gl::POINTS, 0, self.index_to_id.len() as _); | |||||
gl::disable(gl::BLEND); | |||||
} | |||||
fn add_ship(&mut self, id: Id) { | |||||
/* store id */ | |||||
self.need_init.add(id); | |||||
let id = id as usize; | |||||
if self.id_to_index.len() <= id { | |||||
self.id_to_index.resize_with(id + 1, Default::default); | |||||
} | |||||
let index = self.index_to_id.len(); | |||||
if self.index_to_id.len() <= index { | |||||
self.index_to_id.resize_with(index + 1, Default::default); | |||||
} | |||||
self.id_to_index[id] = index as u32; | |||||
self.index_to_id[index] = id as u32; | |||||
/* update ship buffer */ | |||||
let size = size_of::<TailData>() * self.index_to_id.len(); | |||||
let mut buffer = self.ship_data.borrow_mut(); | |||||
if size > buffer.size() { | |||||
buffer | |||||
.buffer_size(Usage::DynamicDraw, size) | |||||
.panic("Unable to change buffer size for ship data"); | |||||
} | |||||
/* update tail buffer */ | |||||
let size = size_of::<TailData>() * self.index_to_id.len(); | |||||
let mut buffer = self.input.tail_data.borrow_mut(); | |||||
if size > buffer.size() { | |||||
buffer | |||||
.buffer_size(Usage::DynamicDraw, size) | |||||
.panic("Unable to change buffer size for input tail data"); | |||||
} | |||||
let mut buffer = self.output.tail_data.borrow_mut(); | |||||
if size > buffer.size() { | |||||
buffer | |||||
.buffer_size(Usage::DynamicDraw, size) | |||||
.panic("Unable to change buffer size for output tail data"); | |||||
} | |||||
} | |||||
fn remove_ship(&mut self, id: Id) { | |||||
let _id = id; | |||||
// TODO | |||||
} | |||||
} | } | ||||
impl<'a> System<'a> for Ships { | impl<'a> System<'a> for Ships { | ||||
type SystemData = ShipsData<'a>; | type SystemData = ShipsData<'a>; | ||||
fn run(&mut self, data: Self::SystemData) { | fn run(&mut self, data: Self::SystemData) { | ||||
let ShipsData { | |||||
geometry, | |||||
position, | |||||
velocity, | |||||
ship, | |||||
owned, | |||||
player, | |||||
} = data; | |||||
self.handle_events(&data); | |||||
self.update_vertices(&data); | |||||
self.update_tail(); | |||||
self.render_tails(); | |||||
self.render_ships(); | |||||
} | |||||
} | |||||
gl::enable(gl::BLEND); | |||||
gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | |||||
let _guard = BindGuard::new(&self.program); | |||||
for (p, v, ship, owned) in (&position, &velocity, &ship, owned.maybe()).join() { | |||||
let _guard = match ship.type_() { | |||||
ShipType::Fighter => BindGuard::new(&self.texture_fighter), | |||||
ShipType::Bomber => BindGuard::new(&self.texture_bomber), | |||||
ShipType::Transporter => BindGuard::new(&self.texture_transporter), | |||||
}; | |||||
let c = match owned.and_then(|owned| player.get(owned.owner())) { | |||||
Some(pv) => pv.color(), | |||||
None => &PLAYER_COLOR_DEFAULT, | |||||
}; | |||||
let p_x = p.pos().x; | |||||
let p_y = p.pos().y; | |||||
let d_x = v.dir().x; | |||||
let d_y = v.dir().y; | |||||
let s = SHIP_SIZE; | |||||
let m = Matrix4f::new( | |||||
Vector4f::new(-s * d_y, s * d_x, 0.0, 0.0), | |||||
Vector4f::new(-s * d_x, -s * d_y, 0.0, 0.0), | |||||
Vector4f::new(0.0, 0.0, s, 0.0), | |||||
Vector4f::new(p_x, p_y, 0.0, 1.0), | |||||
); | |||||
self.program | |||||
.uniform(self.location_glow_color, Uniform::Vector4f(&c)) | |||||
.error("Error while updating glow color"); | |||||
self.program | |||||
.uniform(self.location_model, Uniform::Matrix4f(&m)) | |||||
.error("Error while updating model matrix"); | |||||
geometry.render_quad(); | |||||
} | |||||
impl TailObjects { | |||||
fn new(ship_data: &BufferRef) -> Result<Self, Error> { | |||||
/* tail data */ | |||||
let tail_data = Rc::new(RefCell::new(Buffer::new()?)); | |||||
tail_data | |||||
.borrow_mut() | |||||
.buffer_size(Usage::DynamicDraw, size_of::<TailData>() as _)?; | |||||
gl::disable(gl::BLEND); | |||||
/* vertex array tail update */ | |||||
let tail_update = VertexArray::builder() | |||||
.bind_buffer(ship_data.clone()) | |||||
.vertex_attrib_pointer(0, 2, DataType::Float, false, SHIP_STRIDE, SHIP_OFFSET_POS)? | |||||
.bind_buffer(tail_data.clone()) | |||||
.vertex_attrib_pointer(1, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL0)? | |||||
.vertex_attrib_pointer(2, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL1)? | |||||
.vertex_attrib_pointer(3, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL2)? | |||||
.vertex_attrib_pointer(4, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL3)? | |||||
.vertex_attrib_pointer(5, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL4)? | |||||
.build()?; | |||||
/* vertex array tail render */ | |||||
let tail_render = VertexArray::builder() | |||||
.bind_buffer(ship_data.clone()) | |||||
.vertex_attrib_pointer(0, 3, DataType::Float, false, SHIP_STRIDE, SHIP_OFFSET_CLR)? | |||||
.bind_buffer(tail_data.clone()) | |||||
.vertex_attrib_pointer(1, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL0)? | |||||
.vertex_attrib_pointer(2, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL1)? | |||||
.vertex_attrib_pointer(3, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL2)? | |||||
.vertex_attrib_pointer(4, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL3)? | |||||
.vertex_attrib_pointer(5, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL4)? | |||||
.build()?; | |||||
/* transform feedback buffer */ | |||||
let transform_feedback = TransformFeedback::builder() | |||||
.bind_buffer(0, tail_data.clone())? | |||||
.build()?; | |||||
Ok(Self { | |||||
tail_data, | |||||
tail_update, | |||||
tail_render, | |||||
transform_feedback, | |||||
}) | |||||
} | } | ||||
} | } | ||||
const SHDR_SHIP_VERT: &str = "resources/shader/ship/ship_vert.glsl"; | |||||
const SHDR_SHIP_GEOM: &str = "resources/shader/ship/ship_geom.glsl"; | |||||
const SHDR_SHIP_FRAG: &str = "resources/shader/ship/ship_frag.glsl"; | |||||
const SHDR_TAIL_UPDATE_VERT: &str = "resources/shader/ship/tail_update_vert.glsl"; | |||||
const SHDR_TAIL_UPDATE_GEOM: &str = "resources/shader/ship/tail_update_geom.glsl"; | |||||
const SHDR_TAIL_VARYINGS: &[&str] = &["outTail0", "outTail1", "outTail2", "outTail3", "outTail4"]; | |||||
const SHDR_TAIL_RENDER_VERT: &str = "resources/shader/ship/tail_render_vert.glsl"; | |||||
const SHDR_TAIL_RENDER_GEOM: &str = "resources/shader/ship/tail_render_geom.glsl"; | |||||
const SHDR_TAIL_RENDER_FRAG: &str = "resources/shader/ship/tail_render_frag.glsl"; | |||||
const SHIP_STRIDE: gl::GLsizei = size_of::<ShipData>() as gl::GLsizei; | |||||
const SHIP_OFFSET_POS: gl::GLsizei = 0; | |||||
const SHIP_OFFSET_DIR: gl::GLsizei = SHIP_OFFSET_POS + size_of::<Vector2f>() as gl::GLsizei; | |||||
const SHIP_OFFSET_CLR: gl::GLsizei = SHIP_OFFSET_DIR + size_of::<Vector2f>() as gl::GLsizei; | |||||
const SHIP_OFFSET_TEX: gl::GLsizei = SHIP_OFFSET_CLR + size_of::<Vector3f>() as gl::GLsizei; | |||||
const TAIL_STRIDE: gl::GLsizei = size_of::<TailData>() as gl::GLsizei; | |||||
const TAIL_OFFSET_TL0: gl::GLsizei = 0; | |||||
const TAIL_OFFSET_TL1: gl::GLsizei = TAIL_OFFSET_TL0 + size_of::<Vector2f>() as gl::GLsizei; | |||||
const TAIL_OFFSET_TL2: gl::GLsizei = TAIL_OFFSET_TL1 + size_of::<Vector2f>() as gl::GLsizei; | |||||
const TAIL_OFFSET_TL3: gl::GLsizei = TAIL_OFFSET_TL2 + size_of::<Vector2f>() as gl::GLsizei; | |||||
const TAIL_OFFSET_TL4: gl::GLsizei = TAIL_OFFSET_TL3 + size_of::<Vector2f>() as gl::GLsizei; |
@@ -1,14 +1,14 @@ | |||||
#![allow(dead_code)] | #![allow(dead_code)] | ||||
use glc::{ | use glc::{ | ||||
array_buffer::{ArrayBuffer, Target, Usage}, | |||||
buffer::{Buffer, Target, Usage}, | |||||
error::Error, | error::Error, | ||||
matrix::Matrix4f, | matrix::Matrix4f, | ||||
vector::Vector2f, | vector::Vector2f, | ||||
}; | }; | ||||
pub struct Camera { | pub struct Camera { | ||||
buffer: ArrayBuffer, | |||||
buffer: Buffer, | |||||
data: Data, | data: Data, | ||||
view_invert: Matrix4f, | view_invert: Matrix4f, | ||||
projection_invert: Matrix4f, | projection_invert: Matrix4f, | ||||
@@ -30,7 +30,7 @@ impl Camera { | |||||
view: Matrix4f::identity(), | view: Matrix4f::identity(), | ||||
size: Vector2f::default(), | size: Vector2f::default(), | ||||
}; | }; | ||||
let mut buffer = ArrayBuffer::new(Target::UniformBuffer)?; | |||||
let mut buffer = Buffer::new()?; | |||||
buffer.buffer_data(Usage::StaticDraw, &[data.clone()])?; | buffer.buffer_data(Usage::StaticDraw, &[data.clone()])?; | ||||
Ok(Self { | Ok(Self { | ||||
@@ -100,7 +100,7 @@ impl Camera { | |||||
} | } | ||||
pub fn bind(&self, index: gl::GLuint) -> Result<(), Error> { | pub fn bind(&self, index: gl::GLuint) -> Result<(), Error> { | ||||
Error::checked(|| self.buffer.bind_buffer_base(index)) | |||||
Error::checked(|| self.buffer.bind_buffer_base(Target::UniformBuffer, index)) | |||||
} | } | ||||
pub fn world_to_view<T: Into<Vector2f>>(&self, pos: T) -> Vector2f { | pub fn world_to_view<T: Into<Vector2f>>(&self, pos: T) -> Vector2f { | ||||
@@ -3,7 +3,7 @@ | |||||
use std::mem::size_of; | use std::mem::size_of; | ||||
use glc::{ | use glc::{ | ||||
array_buffer::{ArrayBuffer, Target, Usage}, | |||||
buffer::{Buffer, Usage}, | |||||
misc::Bindable, | misc::Bindable, | ||||
shader::{Program, Type, Uniform}, | shader::{Program, Type, Uniform}, | ||||
vector::{Vector2f, Vector4f}, | vector::{Vector2f, Vector4f}, | ||||
@@ -78,11 +78,11 @@ fn create_array_quad() -> Result<VertexArray, Error> { | |||||
const STRIDE_POS: gl::GLsizei = size_of::<Vector2f>() as gl::GLsizei; | const STRIDE_POS: gl::GLsizei = size_of::<Vector2f>() as gl::GLsizei; | ||||
const OFFSET_POS: gl::GLsizei = 0; | const OFFSET_POS: gl::GLsizei = 0; | ||||
let mut array_buffer = ArrayBuffer::new(Target::ArrayBuffer)?; | |||||
array_buffer.buffer_data(Usage::StaticDraw, vertices)?; | |||||
let mut buffer = Buffer::new()?; | |||||
buffer.buffer_data(Usage::StaticDraw, vertices)?; | |||||
let vertex_array = VertexArray::builder() | let vertex_array = VertexArray::builder() | ||||
.bind_buffer(array_buffer) | |||||
.bind_buffer(buffer) | |||||
.vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE_POS, OFFSET_POS)? | .vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE_POS, OFFSET_POS)? | ||||
.build()?; | .build()?; | ||||
@@ -93,10 +93,10 @@ fn create_array_line() -> Result<VertexArray, Error> { | |||||
const STRIDE_POS: gl::GLsizei = size_of::<Vector2f>() as gl::GLsizei; | const STRIDE_POS: gl::GLsizei = size_of::<Vector2f>() as gl::GLsizei; | ||||
const OFFSET_POS: gl::GLsizei = 0; | const OFFSET_POS: gl::GLsizei = 0; | ||||
let array_buffer = ArrayBuffer::new(Target::ArrayBuffer)?; | |||||
let buffer = Buffer::new()?; | |||||
let vertex_array = VertexArray::builder() | let vertex_array = VertexArray::builder() | ||||
.bind_buffer(array_buffer) | |||||
.bind_buffer(buffer) | |||||
.vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE_POS, OFFSET_POS)? | .vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE_POS, OFFSET_POS)? | ||||
.build()?; | .build()?; | ||||
@@ -1,42 +1,58 @@ | |||||
use std::time::Instant; | use std::time::Instant; | ||||
use glc::{ | use glc::{ | ||||
array_buffer::{ArrayBuffer, Target, Usage}, | |||||
buffer::{Buffer, Target, Usage}, | |||||
error::Error, | error::Error, | ||||
}; | }; | ||||
pub struct Uniform { | pub struct Uniform { | ||||
buffer: ArrayBuffer, | |||||
buffer: Buffer, | |||||
start_time: Instant, | start_time: Instant, | ||||
last_time: Instant, | |||||
} | } | ||||
#[repr(C, packed)] | #[repr(C, packed)] | ||||
struct Data { | struct Data { | ||||
time: f32, | time: f32, | ||||
delta: f32, | |||||
} | } | ||||
impl Uniform { | impl Uniform { | ||||
pub fn new() -> Result<Self, Error> { | pub fn new() -> Result<Self, Error> { | ||||
let mut buffer = ArrayBuffer::new(Target::UniformBuffer)?; | |||||
buffer.buffer_data(Usage::StaticDraw, &[Data { time: 0.0 }])?; | |||||
let mut buffer = Buffer::new()?; | |||||
buffer.buffer_data( | |||||
Usage::StaticDraw, | |||||
&[Data { | |||||
time: 0.0, | |||||
delta: 0.0, | |||||
}], | |||||
)?; | |||||
let now = Instant::now(); | |||||
Ok(Self { | Ok(Self { | ||||
buffer, | buffer, | ||||
start_time: Instant::now(), | |||||
start_time: now, | |||||
last_time: now, | |||||
}) | }) | ||||
} | } | ||||
pub fn update(&mut self) -> Result<(), Error> { | pub fn update(&mut self) -> Result<(), Error> { | ||||
let time = Instant::now().duration_since(self.start_time).as_secs_f32(); | |||||
let now = Instant::now(); | |||||
let time = now.duration_since(self.start_time).as_secs_f32(); | |||||
let delta = now.duration_since(self.last_time).as_secs_f32(); | |||||
self.last_time = now; | |||||
let mut data = self.buffer.map_mut::<Data>(true)?; | let mut data = self.buffer.map_mut::<Data>(true)?; | ||||
data[0].time = time; | data[0].time = time; | ||||
data[0].delta = delta; | |||||
Ok(()) | Ok(()) | ||||
} | } | ||||
pub fn bind(&self, index: gl::GLuint) -> Result<(), Error> { | pub fn bind(&self, index: gl::GLuint) -> Result<(), Error> { | ||||
Error::checked(|| self.buffer.bind_buffer_base(index)) | |||||
Error::checked(|| self.buffer.bind_buffer_base(Target::UniformBuffer, index)) | |||||
} | } | ||||
} | } |
@@ -1,6 +1,8 @@ | |||||
use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||
use specs::{Component, HashMapStorage}; | use specs::{Component, HashMapStorage}; | ||||
use crate::misc::FlaggedStorage; | |||||
#[derive(Clone, Debug, Serialize, Deserialize)] | #[derive(Clone, Debug, Serialize, Deserialize)] | ||||
pub struct Asteroid { | pub struct Asteroid { | ||||
type_: Type, | type_: Type, | ||||
@@ -25,5 +27,5 @@ impl Asteroid { | |||||
} | } | ||||
impl Component for Asteroid { | impl Component for Asteroid { | ||||
type Storage = HashMapStorage<Self>; | |||||
type Storage = FlaggedStorage<Self, HashMapStorage<Self>>; | |||||
} | } |
@@ -1,9 +1,11 @@ | |||||
use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||
use specs::{Component, NullStorage}; | use specs::{Component, NullStorage}; | ||||
use crate::misc::FlaggedStorage; | |||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, Default, Serialize, Deserialize)] | ||||
pub struct Planet {} | pub struct Planet {} | ||||
impl Component for Planet { | impl Component for Planet { | ||||
type Storage = NullStorage<Self>; | |||||
type Storage = FlaggedStorage<Self, NullStorage<Self>>; | |||||
} | } |
@@ -1,4 +1,4 @@ | |||||
use glc::vector::Vector4f; | |||||
use glc::vector::Vector3f; | |||||
use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||
use specs::{ | use specs::{ | ||||
error::NoError, | error::NoError, | ||||
@@ -9,7 +9,7 @@ use specs::{ | |||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)] | #[derive(Clone, Debug, Default, Serialize, Deserialize)] | ||||
pub struct Player { | pub struct Player { | ||||
index: usize, | index: usize, | ||||
color: Vector4f, | |||||
color: Vector3f, | |||||
} | } | ||||
#[derive(Copy, Clone, Debug)] | #[derive(Copy, Clone, Debug)] | ||||
@@ -24,7 +24,7 @@ pub struct OwnedData<M> { | |||||
impl Player { | impl Player { | ||||
#[inline] | #[inline] | ||||
pub fn new(color: Vector4f) -> Self { | |||||
pub fn new(color: Vector3f) -> Self { | |||||
Self { | Self { | ||||
index: next_index(), | index: next_index(), | ||||
color, | color, | ||||
@@ -37,7 +37,7 @@ impl Player { | |||||
} | } | ||||
#[inline] | #[inline] | ||||
pub fn color(&self) -> &Vector4f { | |||||
pub fn color(&self) -> &Vector3f { | |||||
&self.color | &self.color | ||||
} | } | ||||
} | } | ||||
@@ -5,6 +5,8 @@ use glc::vector::Vector2f; | |||||
use serde::{Deserialize, Serialize}; | use serde::{Deserialize, Serialize}; | ||||
use specs::{Component, Entity, VecStorage}; | use specs::{Component, Entity, VecStorage}; | ||||
use crate::misc::FlaggedStorage; | |||||
#[derive(Clone, Debug, Serialize, Deserialize)] | #[derive(Clone, Debug, Serialize, Deserialize)] | ||||
pub struct Ship { | pub struct Ship { | ||||
type_: Type, | type_: Type, | ||||
@@ -84,7 +86,7 @@ impl Ship { | |||||
} | } | ||||
impl Component for Ship { | impl Component for Ship { | ||||
type Storage = VecStorage<Self>; | |||||
type Storage = FlaggedStorage<Self, VecStorage<Self>>; | |||||
} | } | ||||
impl Default for Obstacle { | impl Default for Obstacle { | ||||
@@ -1,59 +1,53 @@ | |||||
#![allow(dead_code)] | #![allow(dead_code)] | ||||
use std::ops::{Deref, DerefMut}; | |||||
use hibitset::BitSetLike; | use hibitset::BitSetLike; | ||||
use shrev::EventChannel; | |||||
use shrev::{Event, EventChannel, ReaderId}; | |||||
use specs::{ | use specs::{ | ||||
storage::{TryDefault, UnprotectedStorage}, | |||||
storage::{DistinctStorage, MaskedStorage, Storage, TryDefault, UnprotectedStorage}, | |||||
world::Index, | world::Index, | ||||
Component, DenseVecStorage, | Component, DenseVecStorage, | ||||
}; | }; | ||||
/* FlaggedStorage */ | |||||
pub struct FlaggedStorage<C, T = DenseVecStorage<C>> | pub struct FlaggedStorage<C, T = DenseVecStorage<C>> | ||||
where | where | ||||
C: Send + Sync + 'static, | |||||
C: Event, | |||||
{ | { | ||||
event_emission: bool, | |||||
channel: EventChannel<ComponentEvent<C>>, | channel: EventChannel<ComponentEvent<C>>, | ||||
storage: T, | storage: T, | ||||
} | } | ||||
pub enum ComponentEvent<C> | pub enum ComponentEvent<C> | ||||
where | where | ||||
C: Send + Sync + 'static, | |||||
C: Event, | |||||
{ | { | ||||
Inserted(Index, C), | Inserted(Index, C), | ||||
Modified(Index, C), | Modified(Index, C), | ||||
Removed(Index, C), | Removed(Index, C), | ||||
} | } | ||||
impl<C, T> FlaggedStorage<C, T> | |||||
where | |||||
C: Send + Sync + 'static, | |||||
{ | |||||
pub fn channel(&self) -> &EventChannel<ComponentEvent<C>> { | |||||
&self.channel | |||||
} | |||||
pub fn channel_mut(&mut self) -> &mut EventChannel<ComponentEvent<C>> { | |||||
&mut self.channel | |||||
} | |||||
} | |||||
impl<C, T> Default for FlaggedStorage<C, T> | impl<C, T> Default for FlaggedStorage<C, T> | ||||
where | where | ||||
C: Send + Sync + 'static, | |||||
C: Event, | |||||
T: TryDefault, | T: TryDefault, | ||||
{ | { | ||||
fn default() -> Self { | fn default() -> Self { | ||||
FlaggedStorage { | FlaggedStorage { | ||||
event_emission: true, | |||||
channel: EventChannel::new(), | channel: EventChannel::new(), | ||||
storage: T::unwrap_default(), | storage: T::unwrap_default(), | ||||
} | } | ||||
} | } | ||||
} | } | ||||
impl<C: Component + Clone, T: UnprotectedStorage<C>> UnprotectedStorage<C> for FlaggedStorage<C, T> | |||||
impl<C, T> UnprotectedStorage<C> for FlaggedStorage<C, T> | |||||
where | where | ||||
C: Send + Sync + 'static, | |||||
C: Component + Event + Clone, | |||||
T: UnprotectedStorage<C>, | |||||
{ | { | ||||
unsafe fn clean<B>(&mut self, has: B) | unsafe fn clean<B>(&mut self, has: B) | ||||
where | where | ||||
@@ -69,8 +63,10 @@ where | |||||
unsafe fn get_mut(&mut self, id: Index) -> &mut C { | unsafe fn get_mut(&mut self, id: Index) -> &mut C { | ||||
let component = self.storage.get_mut(id); | let component = self.storage.get_mut(id); | ||||
self.channel | |||||
.single_write(ComponentEvent::Modified(id, component.clone())); | |||||
if self.event_emission { | |||||
self.channel | |||||
.single_write(ComponentEvent::Modified(id, component.clone())); | |||||
} | |||||
component | component | ||||
} | } | ||||
@@ -78,16 +74,105 @@ where | |||||
unsafe fn insert(&mut self, id: Index, component: C) { | unsafe fn insert(&mut self, id: Index, component: C) { | ||||
self.storage.insert(id, component.clone()); | self.storage.insert(id, component.clone()); | ||||
self.channel | |||||
.single_write(ComponentEvent::Inserted(id, component)); | |||||
if self.event_emission { | |||||
self.channel | |||||
.single_write(ComponentEvent::Inserted(id, component)); | |||||
} | |||||
} | } | ||||
unsafe fn remove(&mut self, id: Index) -> C { | unsafe fn remove(&mut self, id: Index) -> C { | ||||
let component = self.storage.remove(id); | let component = self.storage.remove(id); | ||||
self.channel | |||||
.single_write(ComponentEvent::Removed(id, component.clone())); | |||||
if self.event_emission { | |||||
self.channel | |||||
.single_write(ComponentEvent::Removed(id, component.clone())); | |||||
} | |||||
component | component | ||||
} | } | ||||
} | } | ||||
unsafe impl<C, T> DistinctStorage for FlaggedStorage<C, T> | |||||
where | |||||
C: Component + Event + Clone, | |||||
T: DistinctStorage, | |||||
{ | |||||
} | |||||
/* Tracked */ | |||||
pub trait Tracked<C: Event> { | |||||
fn channel(&self) -> &EventChannel<ComponentEvent<C>>; | |||||
fn channel_mut(&mut self) -> &mut EventChannel<ComponentEvent<C>>; | |||||
fn event_emission(&self) -> bool; | |||||
fn set_event_emission(&mut self, value: bool); | |||||
} | |||||
impl<C, T> Tracked<C> for FlaggedStorage<C, T> | |||||
where | |||||
C: Component + Event, | |||||
{ | |||||
fn channel(&self) -> &EventChannel<ComponentEvent<C>> { | |||||
&self.channel | |||||
} | |||||
fn channel_mut(&mut self) -> &mut EventChannel<ComponentEvent<C>> { | |||||
&mut self.channel | |||||
} | |||||
fn event_emission(&self) -> bool { | |||||
self.event_emission | |||||
} | |||||
fn set_event_emission(&mut self, value: bool) { | |||||
self.event_emission = value; | |||||
} | |||||
} | |||||
/* StorageHelper */ | |||||
pub trait StorageHelper<C: Event> { | |||||
fn event_emission(&self) -> bool; | |||||
fn channel(&self) -> &EventChannel<ComponentEvent<C>>; | |||||
} | |||||
pub trait StorageHelperMut<C: Event> { | |||||
fn set_event_emission(&mut self, value: bool); | |||||
fn channel_mut(&mut self) -> &mut EventChannel<ComponentEvent<C>>; | |||||
fn register_event_reader(&mut self) -> ReaderId<ComponentEvent<C>>; | |||||
} | |||||
impl<'e, T, D> StorageHelper<T> for Storage<'e, T, D> | |||||
where | |||||
T: Component + Event, | |||||
T::Storage: Tracked<T>, | |||||
D: Deref<Target = MaskedStorage<T>>, | |||||
{ | |||||
fn event_emission(&self) -> bool { | |||||
self.unprotected_storage().event_emission() | |||||
} | |||||
fn channel(&self) -> &EventChannel<ComponentEvent<T>> { | |||||
self.unprotected_storage().channel() | |||||
} | |||||
} | |||||
impl<'e, T, D> StorageHelperMut<T> for Storage<'e, T, D> | |||||
where | |||||
T: Component + Event, | |||||
T::Storage: Tracked<T>, | |||||
D: DerefMut<Target = MaskedStorage<T>>, | |||||
{ | |||||
fn set_event_emission(&mut self, value: bool) { | |||||
unsafe { self.unprotected_storage_mut().set_event_emission(value) }; | |||||
} | |||||
fn channel_mut(&mut self) -> &mut EventChannel<ComponentEvent<T>> { | |||||
unsafe { self.unprotected_storage_mut().channel_mut() } | |||||
} | |||||
fn register_event_reader(&mut self) -> ReaderId<ComponentEvent<T>> { | |||||
self.channel_mut().register_reader() | |||||
} | |||||
} |
@@ -7,7 +7,9 @@ mod world; | |||||
pub use self::log::init as init_logger; | pub use self::log::init as init_logger; | ||||
pub use self::vfs::{Vfs, VfsError}; | pub use self::vfs::{Vfs, VfsError}; | ||||
pub use flagged_storage::{ComponentEvent, FlaggedStorage}; | |||||
pub use flagged_storage::{ | |||||
ComponentEvent, FlaggedStorage, StorageHelper, StorageHelperMut, Tracked, | |||||
}; | |||||
pub use log_result::LogResult; | pub use log_result::LogResult; | ||||
pub use persistence::{PersistWorld, Persistence}; | pub use persistence::{PersistWorld, Persistence}; | ||||
pub use world::WorldHelper; | pub use world::WorldHelper; |
@@ -5,7 +5,7 @@ use specs::{prelude::*, world::Index, Entities, ReadStorage, System, World, Writ | |||||
use crate::{ | use crate::{ | ||||
components::{Fleet, FleetOwned, Ship}, | components::{Fleet, FleetOwned, Ship}, | ||||
misc::ComponentEvent, | |||||
misc::{ComponentEvent, StorageHelper, StorageHelperMut}, | |||||
}; | }; | ||||
pub struct FleetOwnedUpdate { | pub struct FleetOwnedUpdate { | ||||
@@ -17,19 +17,14 @@ pub struct FleetOwnedUpdate { | |||||
impl FleetOwnedUpdate { | impl FleetOwnedUpdate { | ||||
pub fn new(world: &mut World) -> Self { | pub fn new(world: &mut World) -> Self { | ||||
WriteStorage::<FleetOwned>::setup(world); | |||||
let fleet_ids = BitSet::new(); | let fleet_ids = BitSet::new(); | ||||
let fleet_owned_ids = BitSet::new(); | let fleet_owned_ids = BitSet::new(); | ||||
let old_fleet_ids = HashMap::new(); | let old_fleet_ids = HashMap::new(); | ||||
let fleet_owned_event_id = unsafe { | |||||
WriteStorage::<FleetOwned>::setup(world); | |||||
let mut fleet_owned = world.system_data::<WriteStorage<FleetOwned>>(); | |||||
fleet_owned | |||||
.unprotected_storage_mut() | |||||
.channel_mut() | |||||
.register_reader() | |||||
}; | |||||
let fleet_owned_event_id = world | |||||
.system_data::<WriteStorage<FleetOwned>>() | |||||
.register_event_reader(); | |||||
Self { | Self { | ||||
fleet_ids, | fleet_ids, | ||||
@@ -64,10 +59,7 @@ impl<'a> System<'a> for FleetOwnedUpdate { | |||||
self.old_fleet_ids.clear(); | self.old_fleet_ids.clear(); | ||||
/* handle events */ | /* handle events */ | ||||
let events = fleet_owned | |||||
.unprotected_storage() | |||||
.channel() | |||||
.read(&mut self.fleet_owned_event_id); | |||||
let events = fleet_owned.channel().read(&mut self.fleet_owned_event_id); | |||||
for event in events { | for event in events { | ||||
match event { | match event { | ||||
ComponentEvent::Inserted(id, fleet_owned) => { | ComponentEvent::Inserted(id, fleet_owned) => { | ||||
@@ -8,7 +8,7 @@ use specs::{ | |||||
use crate::{ | use crate::{ | ||||
components::{Orbit, OrbitOwned, PlayerOwned}, | components::{Orbit, OrbitOwned, PlayerOwned}, | ||||
misc::ComponentEvent, | |||||
misc::{ComponentEvent, StorageHelper, StorageHelperMut}, | |||||
}; | }; | ||||
pub struct OrbitOwnedUpdate { | pub struct OrbitOwnedUpdate { | ||||
@@ -20,19 +20,14 @@ pub struct OrbitOwnedUpdate { | |||||
impl OrbitOwnedUpdate { | impl OrbitOwnedUpdate { | ||||
pub fn new(world: &mut World) -> Self { | pub fn new(world: &mut World) -> Self { | ||||
WriteStorage::<OrbitOwned>::setup(world); | |||||
let orbit_ids = BitSet::new(); | let orbit_ids = BitSet::new(); | ||||
let orbit_owned_ids = BitSet::new(); | let orbit_owned_ids = BitSet::new(); | ||||
let old_orbit_ids = HashMap::new(); | let old_orbit_ids = HashMap::new(); | ||||
let orbit_owned_event_id = unsafe { | |||||
WriteStorage::<OrbitOwned>::setup(world); | |||||
let mut orbit_owned = world.system_data::<WriteStorage<OrbitOwned>>(); | |||||
orbit_owned | |||||
.unprotected_storage_mut() | |||||
.channel_mut() | |||||
.register_reader() | |||||
}; | |||||
let orbit_owned_event_id = world | |||||
.system_data::<WriteStorage<OrbitOwned>>() | |||||
.register_event_reader(); | |||||
Self { | Self { | ||||
orbit_ids, | orbit_ids, | ||||
@@ -67,10 +62,7 @@ impl<'a> System<'a> for OrbitOwnedUpdate { | |||||
self.old_orbit_ids.clear(); | self.old_orbit_ids.clear(); | ||||
/* handle events */ | /* handle events */ | ||||
let events = orbit_owned | |||||
.unprotected_storage() | |||||
.channel() | |||||
.read(&mut self.orbit_owned_event_id); | |||||
let events = orbit_owned.channel().read(&mut self.orbit_owned_event_id); | |||||
for event in events { | for event in events { | ||||
match event { | match event { | ||||
ComponentEvent::Inserted(id, orbit_owned) => { | ComponentEvent::Inserted(id, orbit_owned) => { | ||||
@@ -16,7 +16,7 @@ use crate::{ | |||||
SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND, | SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND, | ||||
SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X, | SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X, | ||||
}, | }, | ||||
misc::ComponentEvent, | |||||
misc::{ComponentEvent, StorageHelper, StorageHelperMut}, | |||||
resources::Global, | resources::Global, | ||||
return_if_none, | return_if_none, | ||||
}; | }; | ||||
@@ -51,16 +51,12 @@ struct Processor<'a> { | |||||
impl Ships { | impl Ships { | ||||
pub fn new(world: &mut World) -> Self { | pub fn new(world: &mut World) -> Self { | ||||
WriteStorage::<FleetOwned>::setup(world); | |||||
let need_update = BitSet::new(); | let need_update = BitSet::new(); | ||||
let fleet_owned_id = unsafe { | |||||
WriteStorage::<FleetOwned>::setup(world); | |||||
let mut fleet_owned = world.system_data::<WriteStorage<FleetOwned>>(); | |||||
fleet_owned | |||||
.unprotected_storage_mut() | |||||
.channel_mut() | |||||
.register_reader() | |||||
}; | |||||
let fleet_owned_id = world | |||||
.system_data::<WriteStorage<FleetOwned>>() | |||||
.register_event_reader(); | |||||
Self { | Self { | ||||
need_update, | need_update, | ||||
@@ -70,10 +66,7 @@ impl Ships { | |||||
fn progress_events(&mut self, fleet_owned: &ReadStorage<'_, FleetOwned>) { | fn progress_events(&mut self, fleet_owned: &ReadStorage<'_, FleetOwned>) { | ||||
self.need_update.clear(); | self.need_update.clear(); | ||||
let events = fleet_owned | |||||
.unprotected_storage() | |||||
.channel() | |||||
.read(&mut self.fleet_owned_id); | |||||
let events = fleet_owned.channel().read(&mut self.fleet_owned_id); | |||||
for event in events { | for event in events { | ||||
let id = match event { | let id = match event { | ||||
ComponentEvent::Inserted(id, _) => id, | ComponentEvent::Inserted(id, _) => id, | ||||
@@ -115,6 +108,8 @@ impl<'a> System<'a> for Ships { | |||||
delta: global.delta * global.world_speed, | delta: global.delta * global.world_speed, | ||||
}; | }; | ||||
ships.set_event_emission(false); | |||||
let data = ( | let data = ( | ||||
positions.mask(), | positions.mask(), | ||||
&mut ships, | &mut ships, | ||||
@@ -127,6 +122,8 @@ impl<'a> System<'a> for Ships { | |||||
.for_each(|(id, ship, velocity, position, fleet_owned)| { | .for_each(|(id, ship, velocity, position, fleet_owned)| { | ||||
processor.progress_ship(id, ship, velocity, position, fleet_owned); | processor.progress_ship(id, ship, velocity, position, fleet_owned); | ||||
}); | }); | ||||
ships.set_event_emission(true); | |||||
} | } | ||||
} | } | ||||