| @@ -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::{ | ||||
| @@ -28,6 +30,10 @@ impl Buffer { | |||||
| 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>(); | ||||
| @@ -157,7 +163,10 @@ impl Drop for Buffer { | |||||
| } | } | ||||
| } | } | ||||
| impl<'a> Bindable for (Target, &'a Buffer) { | |||||
| impl<T> Bindable for (Target, T) | |||||
| where | |||||
| T: Deref<Target = Buffer>, | |||||
| { | |||||
| fn bind(&self) { | fn bind(&self) { | ||||
| gl::bind_buffer(self.0.as_enum(), self.1.id); | gl::bind_buffer(self.0.as_enum(), self.1.id); | ||||
| } | } | ||||
| @@ -215,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, | ||||
| @@ -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 { | ||||
| @@ -253,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)] | ||||
| @@ -278,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> { | ||||
| @@ -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::{ | ||||
| buffer::{Buffer, Target}, | |||||
| 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<Buffer>, | |||||
| 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<Buffer> { | |||||
| pub fn buffers(&self) -> &[T] { | |||||
| &self.buffers | &self.buffers | ||||
| } | } | ||||
| pub fn buffers_mut(&mut self) -> &mut Vec<Buffer> { | |||||
| 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: Buffer) -> 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,7 +78,7 @@ 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((Target::ArrayBuffer, &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))?; | ||||
| @@ -128,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: Buffer) -> Self { | |||||
| impl<T> BindingBuilder<T> { | |||||
| pub fn bind_buffer(self, buffer: T) -> Self { | |||||
| self.builder.bind_buffer(buffer) | self.builder.bind_buffer(buffer) | ||||
| } | } | ||||
| @@ -187,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, | ||||
| @@ -234,19 +274,32 @@ impl AsEnum for DataType { | |||||
| /* Binding */ | /* Binding */ | ||||
| struct Binding { | |||||
| buffer: Buffer, | |||||
| 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>, | |||||
| } | } | ||||
| @@ -1,3 +1,4 @@ | |||||
| layout (std140) uniform Global { | layout (std140) uniform Global { | ||||
| float time; | float time; | ||||
| float delta; | |||||
| } uGlobal; | } uGlobal; | ||||
| @@ -1,28 +0,0 @@ | |||||
| #version 450 core | |||||
| #pragma include ./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,23 @@ | |||||
| #version 450 core | |||||
| #pragma include ./glow_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; | |||||
| out vec4 outColor; | |||||
| void main() { | |||||
| float alpha = glow(GLOW_ARGS, fragmentData.texCoords, uGlobal.time); | |||||
| outColor = vec4(fragmentData.color, GLOW_ALPHA * alpha); | |||||
| } | |||||
| @@ -0,0 +1,44 @@ | |||||
| #version 450 core | |||||
| #pragma include ./glow_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 = 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, 1.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(); | |||||
| } | |||||
| @@ -0,0 +1,12 @@ | |||||
| struct FragmentData { | |||||
| vec2 texCoords; | |||||
| vec3 color; | |||||
| }; | |||||
| struct VertexData { | |||||
| vec2 pos; | |||||
| vec3 color; | |||||
| }; | |||||
| const float GLOW_SIZE = 100.00; | |||||
| const float GLOW_ALPHA = 0.05; | |||||
| @@ -0,0 +1,13 @@ | |||||
| #version 450 core | |||||
| #pragma include ./glow_shared.glsl | |||||
| layout (location = 0) in vec2 inPosition; | |||||
| layout (location = 1) in vec3 inColor; | |||||
| out VertexData vertexData; | |||||
| void main() { | |||||
| vertexData.pos = inPosition; | |||||
| vertexData.color = inColor; | |||||
| } | |||||
| @@ -1,15 +0,0 @@ | |||||
| struct FragmentData { | |||||
| vec2 texCoords; | |||||
| vec3 color; | |||||
| }; | |||||
| struct VertexData { | |||||
| vec2 pos; | |||||
| vec2 dir; | |||||
| vec3 color; | |||||
| int texture; | |||||
| }; | |||||
| const float SHIP_SIZE = 25.0; // absolute ship size | |||||
| const float GLOW_SIZE = 4.0; // relative to ship size | |||||
| const float GLOW_ALPHA = 0.1; | |||||
| @@ -0,0 +1,14 @@ | |||||
| #version 450 core | |||||
| #pragma include ./ship_shared.glsl | |||||
| in FragmentData fragmentData; | |||||
| flat in int textureId; | |||||
| uniform sampler2D uTexture[3]; | |||||
| out vec4 outColor; | |||||
| void main() { | |||||
| outColor = texture(uTexture[textureId], fragmentData.texCoords); | |||||
| } | |||||
| @@ -1,6 +1,6 @@ | |||||
| #version 450 core | #version 450 core | ||||
| #pragma include ./shared.glsl | |||||
| #pragma include ./ship_shared.glsl | |||||
| #pragma include ../misc/camera.glsl | #pragma include ../misc/camera.glsl | ||||
| in VertexData vertexData[]; | in VertexData vertexData[]; | ||||
| @@ -15,7 +15,7 @@ void main() { | |||||
| VertexData d = vertexData[0]; | VertexData d = vertexData[0]; | ||||
| vec2 pos = d.pos; | vec2 pos = d.pos; | ||||
| vec2 dir = d.dir * SHIP_SIZE * GLOW_SIZE; | |||||
| vec2 dir = d.dir * SHIP_SIZE; | |||||
| mat4 m = uCamera.projection * uCamera.view * mat4( | mat4 m = uCamera.projection * uCamera.view * mat4( | ||||
| vec4(dir.y, -dir.x, 0.0, 0.0), | vec4(dir.y, -dir.x, 0.0, 0.0), | ||||
| @@ -24,14 +24,13 @@ void main() { | |||||
| vec4(pos.x, pos.y, 0.0, 1.0)); | vec4(pos.x, pos.y, 0.0, 1.0)); | ||||
| textureId = d.texture; | textureId = d.texture; | ||||
| fragmentData.color = d.color; | |||||
| gl_Position = m * vec4(-1.0, -1.0, 0.0, 1.0); | gl_Position = m * vec4(-1.0, -1.0, 0.0, 1.0); | ||||
| fragmentData.texCoords = vec2(-1.0, 1.0); | |||||
| fragmentData.texCoords = vec2( 0.0, 1.0); | |||||
| EmitVertex(); | EmitVertex(); | ||||
| gl_Position = m * vec4(-1.0, 1.0, 0.0, 1.0); | gl_Position = m * vec4(-1.0, 1.0, 0.0, 1.0); | ||||
| fragmentData.texCoords = vec2(-1.0, -1.0); | |||||
| fragmentData.texCoords = vec2( 0.0, 0.0); | |||||
| EmitVertex(); | EmitVertex(); | ||||
| gl_Position = m * vec4( 1.0, -1.0, 0.0, 1.0); | gl_Position = m * vec4( 1.0, -1.0, 0.0, 1.0); | ||||
| @@ -39,7 +38,7 @@ void main() { | |||||
| EmitVertex(); | EmitVertex(); | ||||
| gl_Position = m * vec4( 1.0, 1.0, 0.0, 1.0); | gl_Position = m * vec4( 1.0, 1.0, 0.0, 1.0); | ||||
| fragmentData.texCoords = vec2( 1.0, -1.0); | |||||
| fragmentData.texCoords = vec2( 1.0, 0.0); | |||||
| EmitVertex(); | EmitVertex(); | ||||
| EndPrimitive(); | EndPrimitive(); | ||||
| @@ -0,0 +1,11 @@ | |||||
| struct FragmentData { | |||||
| vec2 texCoords; | |||||
| }; | |||||
| struct VertexData { | |||||
| vec2 pos; | |||||
| vec2 dir; | |||||
| int texture; | |||||
| }; | |||||
| const float SHIP_SIZE = 25.00; | |||||
| @@ -1,17 +1,15 @@ | |||||
| #version 450 core | #version 450 core | ||||
| #pragma include ./shared.glsl | |||||
| #pragma include ./ship_shared.glsl | |||||
| layout (location = 0) in vec2 inPosition; | layout (location = 0) in vec2 inPosition; | ||||
| layout (location = 1) in vec2 inDirection; | layout (location = 1) in vec2 inDirection; | ||||
| layout (location = 2) in vec3 inColor; | |||||
| layout (location = 3) in int inTexture; | |||||
| layout (location = 2) in int inTexture; | |||||
| out VertexData vertexData; | out VertexData vertexData; | ||||
| void main() { | void main() { | ||||
| vertexData.pos = inPosition; | vertexData.pos = inPosition; | ||||
| vertexData.dir = inDirection; | vertexData.dir = inDirection; | ||||
| vertexData.color = inColor; | |||||
| vertexData.texture = inTexture; | 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,160 @@ | |||||
| #version 450 core | |||||
| #pragma include ./tail_render_shared.glsl | |||||
| #pragma include ../misc/camera.glsl | |||||
| /* | |||||
| Vertex Layout: | |||||
| .-- 0 --- 3 --- 6 --- 9 --- 12 --- 15 | |||||
| / | \ | \ | \ | \ | \ | | |||||
| SHIP ----- 1 --- 4 --- 7 --- 10 --- 13 --- 16 | |||||
| \ | / | / | / | / | / | | |||||
| `-- 2 --- 5 --- 8 --- 11 --- 14 --- 17 | |||||
| */ | |||||
| in VertexData vertexData[]; | |||||
| layout (points) in; | |||||
| layout (triangle_strip, max_vertices = 24) out; | |||||
| out FragmentData fragmentData; | |||||
| struct Vertex { | |||||
| vec2 pos; | |||||
| vec4 clr; | |||||
| }; | |||||
| vec2 ortho2(vec2 pos, vec2 ref) { | |||||
| vec2 dir = normalize(pos - ref); | |||||
| return vec2(dir.y, -dir.x); | |||||
| } | |||||
| vec2 ortho3(vec2 ref0, vec2 pos, vec2 ref1) { | |||||
| vec2 dir0 = ortho2(ref0, pos); | |||||
| vec2 dir1 = ortho2(pos, ref1); | |||||
| return normalize(dir0 + dir1); | |||||
| } | |||||
| void emit(Vertex v) { | |||||
| gl_Position = uCamera.projection * uCamera.view * vec4(v.pos, 0.0, 1.0); | |||||
| fragmentData.color = v.clr; | |||||
| EmitVertex(); | |||||
| } | |||||
| void main() { | |||||
| VertexData d = vertexData[0]; | |||||
| vec2 ortho; | |||||
| Vertex vertices[18]; | |||||
| /* tail[0] */ | |||||
| ortho = ortho2(d.tail[0], d.tail[1]); | |||||
| vertices[0].pos = d.tail[0] + TAIL_WIDTH * ortho; | |||||
| vertices[0].clr = vec4(d.color, 0.8 * TAIL_ALPHA); | |||||
| vertices[1].pos = d.tail[0]; | |||||
| vertices[1].clr = vec4(d.color, 1.0 * TAIL_ALPHA); | |||||
| vertices[2].pos = d.tail[0] - TAIL_WIDTH * ortho; | |||||
| vertices[2].clr = vec4(d.color, 0.8 * TAIL_ALPHA); | |||||
| /* tail[1] */ | |||||
| ortho = ortho3(d.tail[0], d.tail[1], d.tail[2]); | |||||
| vertices[3].pos = d.tail[1] + TAIL_WIDTH * ortho; | |||||
| vertices[3].clr = vec4(d.color, 0.6 * TAIL_ALPHA); | |||||
| vertices[4].pos = d.tail[1]; | |||||
| vertices[4].clr = vec4(d.color, 0.8 * TAIL_ALPHA); | |||||
| vertices[5].pos = d.tail[1] - TAIL_WIDTH * ortho; | |||||
| vertices[5].clr = vec4(d.color, 0.6 * TAIL_ALPHA); | |||||
| /* tail[2] */ | |||||
| ortho = ortho3(d.tail[1], d.tail[2], d.tail[3]); | |||||
| vertices[6].pos = d.tail[2] + TAIL_WIDTH * ortho; | |||||
| vertices[6].clr = vec4(d.color, 0.4 * TAIL_ALPHA); | |||||
| vertices[7].pos = d.tail[2]; | |||||
| vertices[7].clr = vec4(d.color, 0.6 * TAIL_ALPHA); | |||||
| vertices[8].pos = d.tail[2] - TAIL_WIDTH * ortho; | |||||
| vertices[8].clr = vec4(d.color, 0.4 * TAIL_ALPHA); | |||||
| /* tail[3] */ | |||||
| ortho = ortho3(d.tail[2], d.tail[3], d.tail[4]); | |||||
| vertices[9].pos = d.tail[3] + TAIL_WIDTH * ortho; | |||||
| vertices[9].clr = vec4(d.color, 0.2 * TAIL_ALPHA); | |||||
| vertices[10].pos = d.tail[3]; | |||||
| vertices[10].clr = vec4(d.color, 0.4 * TAIL_ALPHA); | |||||
| vertices[11].pos = d.tail[3] - TAIL_WIDTH * ortho; | |||||
| vertices[11].clr = vec4(d.color, 0.2 * TAIL_ALPHA); | |||||
| /* tail[4] */ | |||||
| ortho = ortho3(d.tail[3], d.tail[4], d.tail[5]); | |||||
| vertices[12].pos = d.tail[4] + TAIL_WIDTH * ortho; | |||||
| vertices[12].clr = vec4(d.color, 0.0 * TAIL_ALPHA); | |||||
| vertices[13].pos = d.tail[4]; | |||||
| vertices[13].clr = vec4(d.color, 0.2 * TAIL_ALPHA); | |||||
| vertices[14].pos = d.tail[4] - TAIL_WIDTH * ortho; | |||||
| vertices[14].clr = vec4(d.color, 0.0 * TAIL_ALPHA); | |||||
| /* tail[5] */ | |||||
| ortho = ortho2(d.tail[4], d.tail[5]); | |||||
| vertices[15].pos = d.tail[5] + TAIL_WIDTH * ortho; | |||||
| vertices[15].clr = vec4(d.color, 0.0 * TAIL_ALPHA); | |||||
| vertices[16].pos = d.tail[5]; | |||||
| vertices[16].clr = vec4(d.color, 0.0 * TAIL_ALPHA); | |||||
| vertices[17].pos = d.tail[5] - TAIL_WIDTH * ortho; | |||||
| vertices[17].clr = vec4(d.color, 0.0 * TAIL_ALPHA); | |||||
| /* emit */ | |||||
| emit(vertices[1]); | |||||
| emit(vertices[0]); | |||||
| emit(vertices[4]); | |||||
| emit(vertices[3]); | |||||
| emit(vertices[7]); | |||||
| emit(vertices[6]); | |||||
| emit(vertices[10]); | |||||
| emit(vertices[9]); | |||||
| emit(vertices[13]); | |||||
| emit(vertices[12]); | |||||
| emit(vertices[16]); | |||||
| emit(vertices[15]); | |||||
| EndPrimitive(); | |||||
| emit(vertices[1]); | |||||
| emit(vertices[2]); | |||||
| emit(vertices[4]); | |||||
| emit(vertices[5]); | |||||
| emit(vertices[7]); | |||||
| emit(vertices[8]); | |||||
| emit(vertices[10]); | |||||
| emit(vertices[11]); | |||||
| emit(vertices[13]); | |||||
| emit(vertices[14]); | |||||
| emit(vertices[16]); | |||||
| emit(vertices[17]); | |||||
| EndPrimitive(); | |||||
| } | |||||
| @@ -0,0 +1,11 @@ | |||||
| struct FragmentData { | |||||
| vec4 color; | |||||
| }; | |||||
| struct VertexData { | |||||
| vec3 color; | |||||
| vec2 tail[6]; | |||||
| }; | |||||
| const float TAIL_WIDTH = 3.0; | |||||
| const float TAIL_ALPHA = 0.2; | |||||
| @@ -0,0 +1,23 @@ | |||||
| #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; | |||||
| layout (location = 6) in vec2 inTail5; | |||||
| 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; | |||||
| vertexData.tail[5] = inTail5; | |||||
| } | |||||
| @@ -0,0 +1,40 @@ | |||||
| #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; | |||||
| out vec2 outTail5; | |||||
| 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]); | |||||
| outTail5 = move(d.tail[4], d.tail[5]); | |||||
| EmitVertex(); | |||||
| EndPrimitive(); | |||||
| } | |||||
| @@ -0,0 +1,7 @@ | |||||
| struct VertexData { | |||||
| vec2 pos; | |||||
| vec2 tail[6]; | |||||
| }; | |||||
| const float TAIL_LEN = 10.0; | |||||
| const float TAIL_FORCE = 10.0; | |||||
| @@ -0,0 +1,23 @@ | |||||
| #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; | |||||
| layout (location = 6) in vec2 inTail5; | |||||
| 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; | |||||
| vertexData.tail[5] = inTail5; | |||||
| } | |||||
| @@ -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> { | ||||
| @@ -167,10 +167,10 @@ impl<'a> System<'a> for Asteroids { | |||||
| let _guard = BindGuard::new(&self.vertex_array); | let _guard = BindGuard::new(&self.vertex_array); | ||||
| gl::active_texture(gl::TEXTURE1); | gl::active_texture(gl::TEXTURE1); | ||||
| let _guard = BindGuard::new(&self.texture_crystal); | |||||
| self.texture_crystal.bind(); | |||||
| gl::active_texture(gl::TEXTURE0); | gl::active_texture(gl::TEXTURE0); | ||||
| let _guard = BindGuard::new(&self.texture_metal); | |||||
| self.texture_metal.bind(); | |||||
| gl::enable(gl::BLEND); | gl::enable(gl::BLEND); | ||||
| gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | ||||
| @@ -155,7 +155,8 @@ impl<'a> System<'a> for Planets { | |||||
| /* render planets */ | /* 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.vertex_array); | ||||
| let _guard = BindGuard::new(&self.texture); | |||||
| self.texture.bind(); | |||||
| gl::enable(gl::BLEND); | gl::enable(gl::BLEND); | ||||
| gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | ||||
| @@ -1,10 +1,13 @@ | |||||
| use std::mem::size_of; | |||||
| use std::cell::RefCell; | |||||
| use std::mem::{size_of, swap}; | |||||
| use std::rc::Rc; | |||||
| use glc::{ | use glc::{ | ||||
| buffer::{Buffer, Usage}, | buffer::{Buffer, Usage}, | ||||
| misc::{BindGuard, Bindable}, | misc::{BindGuard, Bindable}, | ||||
| shader::{Program, Type, Uniform}, | |||||
| shader::{Program, TransformFeedbackVaryingsMode, Type, Uniform}, | |||||
| texture::Texture, | texture::Texture, | ||||
| transform_feedback::TransformFeedback, | |||||
| vector::{Vector2f, Vector3f}, | vector::{Vector2f, Vector3f}, | ||||
| vertex_array::{DataType, VertexArray}, | vertex_array::{DataType, VertexArray}, | ||||
| }; | }; | ||||
| @@ -12,7 +15,12 @@ use space_crush_common::{ | |||||
| components::{Player, PlayerOwned, Position, Ship, ShipType, Velocity}, | components::{Player, PlayerOwned, Position, Ship, ShipType, Velocity}, | ||||
| misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, | misc::{ComponentEvent, LogResult, StorageHelper, StorageHelperMut}, | ||||
| }; | }; | ||||
| use specs::{prelude::*, ReadStorage, System, World}; | |||||
| use specs::{ | |||||
| hibitset::{BitSet, BitSetAll, BitSetLike}, | |||||
| prelude::*, | |||||
| world::Index as Id, | |||||
| ReadStorage, System, World, | |||||
| }; | |||||
| use crate::{ | use crate::{ | ||||
| constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | constants::{PLAYER_COLOR_DEFAULT, UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | ||||
| @@ -21,154 +29,444 @@ use crate::{ | |||||
| }; | }; | ||||
| pub struct Ships { | pub struct Ships { | ||||
| program: Program, | |||||
| vertex_array: VertexArray, | |||||
| program_ship: Program, | |||||
| program_glow: Program, | |||||
| program_tail_update: Program, | |||||
| program_tail_render: Program, | |||||
| ship_data: BufferRef, | |||||
| ship_glow: VertexArray<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, | ||||
| reader_id: ReaderId<ComponentEvent<Ship>>, | reader_id: ReaderId<ComponentEvent<Ship>>, | ||||
| ship_count: usize, | |||||
| 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)] | #[repr(C, packed)] | ||||
| struct VertexData { | |||||
| #[derive(Debug, Clone, Copy)] | |||||
| struct ShipData { | |||||
| pos: Vector2f, | pos: Vector2f, | ||||
| dir: Vector2f, | dir: Vector2f, | ||||
| color: Vector3f, | color: Vector3f, | ||||
| texture: gl::GLint, | texture: gl::GLint, | ||||
| } | } | ||||
| #[repr(C, packed)] | |||||
| #[derive(Debug, Clone, Copy)] | |||||
| struct TailData { | |||||
| pos: [Vector2f; 6], | |||||
| } | |||||
| 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::Geometry, "resources/shader/ship/geom.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.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | |||||
| program.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; | |||||
| program_ship.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | |||||
| program.bind(); | |||||
| program.uniform("uTexture", Uniform::TextureVec(&[0, 1, 2]))?; | |||||
| program.unbind(); | |||||
| program_ship.bind(); | |||||
| program_ship.uniform("uTexture", Uniform::TextureVec(&[0, 1, 2]))?; | |||||
| program_ship.unbind(); | |||||
| const STRIDE: gl::GLsizei = size_of::<VertexData>() as gl::GLsizei; | |||||
| /* program glow */ | |||||
| let program_glow = world.load_program(vec![ | |||||
| (Type::Vertex, SHDR_GLOW_VERT), | |||||
| (Type::Geometry, SHDR_GLOW_GEOM), | |||||
| (Type::Fragment, SHDR_GLOW_FRAG), | |||||
| ])?; | |||||
| const OFFSET_POS: gl::GLsizei = 0; | |||||
| const OFFSET_DIR: gl::GLsizei = OFFSET_POS + size_of::<Vector2f>() as gl::GLsizei; | |||||
| const OFFSET_CLR: gl::GLsizei = OFFSET_DIR + size_of::<Vector2f>() as gl::GLsizei; | |||||
| const OFFSET_TEX: gl::GLsizei = OFFSET_CLR + size_of::<Vector3f>() as gl::GLsizei; | |||||
| program_glow.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | |||||
| program_glow.uniform_block_binding("Global", UNIFORM_BUFFER_INDEX_UNIFORM)?; | |||||
| let vertex_array = VertexArray::builder() | |||||
| .bind_buffer(Buffer::new()?) | |||||
| .vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE, OFFSET_POS)? | |||||
| .vertex_attrib_pointer(1, 2, DataType::Float, false, STRIDE, OFFSET_DIR)? | |||||
| .vertex_attrib_pointer(2, 3, DataType::Float, false, STRIDE, OFFSET_CLR)? | |||||
| .vertex_attrib_pointer(3, 1, DataType::Int, false, STRIDE, OFFSET_TEX)? | |||||
| /* 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()?; | .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_tail_render.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?; | |||||
| /* ship data */ | |||||
| let ship_data = Rc::new(RefCell::new(Buffer::new()?)); | |||||
| /* vertex array glow */ | |||||
| let ship_glow = VertexArray::builder() | |||||
| .bind_buffer(ship_data.clone()) | |||||
| .vertex_attrib_pointer(0, 2, DataType::Float, false, SHIP_STRIDE, SHIP_OFFSET_POS)? | |||||
| .vertex_attrib_pointer(1, 3, DataType::Float, false, SHIP_STRIDE, SHIP_OFFSET_CLR)? | |||||
| .build()?; | |||||
| /* 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, 1, DataType::Int, false, SHIP_STRIDE, SHIP_OFFSET_TEX)? | |||||
| .build()?; | |||||
| /* 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 | let reader_id = world | ||||
| .system_data::<WriteStorage<Ship>>() | .system_data::<WriteStorage<Ship>>() | ||||
| .register_event_reader(); | .register_event_reader(); | ||||
| let ship_count = 0; | |||||
| /* rest */ | |||||
| let need_init = BitSet::new(); | |||||
| let id_to_index = Vec::new(); | |||||
| let index_to_id = Vec::new(); | |||||
| Ok(Self { | Ok(Self { | ||||
| program, | |||||
| vertex_array, | |||||
| program_ship, | |||||
| program_glow, | |||||
| program_tail_update, | |||||
| program_tail_render, | |||||
| ship_data, | |||||
| ship_glow, | |||||
| ship_render, | |||||
| input, | |||||
| output, | |||||
| texture_bomber, | texture_bomber, | ||||
| texture_fighter, | texture_fighter, | ||||
| texture_transporter, | texture_transporter, | ||||
| reader_id, | reader_id, | ||||
| ship_count, | |||||
| need_init, | |||||
| id_to_index, | |||||
| index_to_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>, | |||||
| } | |||||
| impl<'a> System<'a> for Ships { | |||||
| type SystemData = ShipsData<'a>; | |||||
| fn run(&mut self, data: Self::SystemData) { | |||||
| let ShipsData { | |||||
| positions, | |||||
| velocities, | |||||
| players, | |||||
| owned, | |||||
| ships, | |||||
| } = data; | |||||
| /* handle events */ | |||||
| let old_count = self.ship_count; | |||||
| let events = ships.channel().read(&mut self.reader_id); | |||||
| 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 { | for event in events { | ||||
| match event { | match event { | ||||
| ComponentEvent::Inserted(_, _) => self.ship_count += 1, | |||||
| ComponentEvent::Removed(_, _) => self.ship_count -= 1, | |||||
| ComponentEvent::Inserted(id, _) => self.add_ship(*id), | |||||
| ComponentEvent::Removed(id, _) => self.remove_ship(*id), | |||||
| ComponentEvent::Modified(_, _) => { | ComponentEvent::Modified(_, _) => { | ||||
| unreachable!("Updates of the ship component should not be tracked!") | unreachable!("Updates of the ship component should not be tracked!") | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| /* update vertex array */ | |||||
| let buffer = &mut self.vertex_array.buffers_mut()[0]; | |||||
| if old_count != self.ship_count { | |||||
| buffer | |||||
| .buffer_size(Usage::StaticDraw, self.ship_count * size_of::<VertexData>()) | |||||
| .panic("Unable to change buffer size for ship data"); | |||||
| } | |||||
| let data = (&positions, &velocities, &ships, owned.maybe()); | |||||
| let mut buffer = buffer | |||||
| .map_mut::<VertexData>(true) | |||||
| 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"); | .panic("Unable to map buffer for ship data"); | ||||
| for (i, (position, velocity, ship, owned)) in data.join().enumerate() { | |||||
| let mut d = &mut buffer[i]; | |||||
| d.pos = *position.pos(); | |||||
| d.dir = *velocity.dir(); | |||||
| d.color = match owned.and_then(|owned| players.get(owned.owner())) { | |||||
| Some(pv) => *pv.color(), | |||||
| None => PLAYER_COLOR_DEFAULT, | |||||
| }; | |||||
| d.texture = match ship.type_() { | |||||
| ShipType::Fighter => 0, | |||||
| ShipType::Bomber => 1, | |||||
| ShipType::Transporter => 2, | |||||
| }; | |||||
| 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_tails(&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(buffer); | |||||
| drop(guard_trfm); | |||||
| drop(guard_data); | |||||
| drop(guard_prog); | |||||
| /* render ships */ | |||||
| let _guard = BindGuard::new(&self.program); | |||||
| let _guard = BindGuard::new(&self.vertex_array); | |||||
| swap(&mut self.input, &mut self.output); | |||||
| } | |||||
| fn render_glow(&self) { | |||||
| let _guard = BindGuard::new(&self.program_glow); | |||||
| let _guard = BindGuard::new(&self.ship_glow); | |||||
| 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_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); | gl::active_texture(gl::TEXTURE2); | ||||
| let _guard = BindGuard::new(&self.texture_transporter); | |||||
| self.texture_transporter.bind(); | |||||
| gl::active_texture(gl::TEXTURE1); | gl::active_texture(gl::TEXTURE1); | ||||
| let _guard = BindGuard::new(&self.texture_bomber); | |||||
| self.texture_bomber.bind(); | |||||
| gl::active_texture(gl::TEXTURE0); | gl::active_texture(gl::TEXTURE0); | ||||
| let _guard = BindGuard::new(&self.texture_fighter); | |||||
| self.texture_fighter.bind(); | |||||
| gl::enable(gl::BLEND); | gl::enable(gl::BLEND); | ||||
| gl::blend_func(gl::SRC_ALPHA, gl::ONE); | |||||
| gl::draw_arrays(gl::POINTS, 0, self.ship_count as _); | |||||
| gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); | |||||
| gl::draw_arrays(gl::POINTS, 0, self.index_to_id.len() as _); | |||||
| gl::disable(gl::BLEND); | 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 index = self.id_to_index[id as usize]; | |||||
| /* update id/index maps */ | |||||
| let last_index = self.index_to_id.len() - 1; | |||||
| let last_id = self.index_to_id.pop().unwrap(); | |||||
| self.id_to_index[last_id as usize] = index; | |||||
| /* move ship data */ | |||||
| let mut buffer = self.ship_data.borrow_mut(); | |||||
| let mut buffer = buffer | |||||
| .map_mut::<ShipData>(false) | |||||
| .panic("Unable to map buffer for ship data"); | |||||
| buffer[index as usize] = buffer[last_index as usize]; | |||||
| /* move tail data */ | |||||
| let mut buffer = self.input.tail_data.borrow_mut(); | |||||
| let mut buffer = buffer | |||||
| .map_mut::<TailData>(false) | |||||
| .panic("Unable to map buffer for tail data"); | |||||
| buffer[index as usize] = buffer[last_index as usize]; | |||||
| } | |||||
| } | } | ||||
| impl<'a> System<'a> for Ships { | |||||
| type SystemData = ShipsData<'a>; | |||||
| fn run(&mut self, data: Self::SystemData) { | |||||
| self.handle_events(&data); | |||||
| self.update_vertices(&data); | |||||
| self.update_tails(); | |||||
| self.render_glow(); | |||||
| self.render_tails(); | |||||
| self.render_ships(); | |||||
| } | |||||
| } | |||||
| 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 _)?; | |||||
| /* 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)? | |||||
| .vertex_attrib_pointer(6, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL5)? | |||||
| .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)? | |||||
| .vertex_attrib_pointer(6, 2, DataType::Float, false, TAIL_STRIDE, TAIL_OFFSET_TL5)? | |||||
| .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_GLOW_VERT: &str = "resources/shader/ship/glow_vert.glsl"; | |||||
| const SHDR_GLOW_GEOM: &str = "resources/shader/ship/glow_geom.glsl"; | |||||
| const SHDR_GLOW_FRAG: &str = "resources/shader/ship/glow_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", "outTail5", | |||||
| ]; | |||||
| 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; | |||||
| const TAIL_OFFSET_TL5: gl::GLsizei = TAIL_OFFSET_TL4 + size_of::<Vector2f>() as gl::GLsizei; | |||||
| @@ -8,30 +8,46 @@ use glc::{ | |||||
| pub struct Uniform { | pub struct Uniform { | ||||
| buffer: Buffer, | 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 = Buffer::new()?; | let mut buffer = Buffer::new()?; | ||||
| buffer.buffer_data(Usage::StaticDraw, &[Data { time: 0.0 }])?; | |||||
| 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(()) | ||||
| } | } | ||||