7 Commits

50 changed files with 1827 additions and 497 deletions
Split View
  1. +62
    -20
      glc/src/buffer.rs
  2. +6
    -0
      glc/src/error.rs
  3. +2
    -1
      glc/src/lib.rs
  4. +108
    -33
      glc/src/shader.rs
  5. +117
    -0
      glc/src/transform_feedback.rs
  6. +114
    -45
      glc/src/vertex_array.rs
  7. +6
    -6
      space-crush-app/resources/shader/asteroid/frag.glsl
  8. +46
    -0
      space-crush-app/resources/shader/asteroid/geom.glsl
  9. +11
    -0
      space-crush-app/resources/shader/asteroid/shared.glsl
  10. +9
    -8
      space-crush-app/resources/shader/asteroid/vert.glsl
  11. +1
    -0
      space-crush-app/resources/shader/misc/global.glsl
  12. +3
    -4
      space-crush-app/resources/shader/planet/frag.glsl
  13. +44
    -0
      space-crush-app/resources/shader/planet/geom.glsl
  14. +10
    -0
      space-crush-app/resources/shader/planet/shared.glsl
  15. +7
    -8
      space-crush-app/resources/shader/planet/vert.glsl
  16. +0
    -29
      space-crush-app/resources/shader/ship/frag.glsl
  17. +0
    -3
      space-crush-app/resources/shader/ship/shared.glsl
  18. +28
    -0
      space-crush-app/resources/shader/ship/ship_frag.glsl
  19. +46
    -0
      space-crush-app/resources/shader/ship/ship_geom.glsl
  20. +15
    -0
      space-crush-app/resources/shader/ship/ship_shared.glsl
  21. +17
    -0
      space-crush-app/resources/shader/ship/ship_vert.glsl
  22. +11
    -0
      space-crush-app/resources/shader/ship/tail_render_frag.glsl
  23. +40
    -0
      space-crush-app/resources/shader/ship/tail_render_geom.glsl
  24. +8
    -0
      space-crush-app/resources/shader/ship/tail_render_shared.glsl
  25. +21
    -0
      space-crush-app/resources/shader/ship/tail_render_vert.glsl
  26. +38
    -0
      space-crush-app/resources/shader/ship/tail_update_geom.glsl
  27. +7
    -0
      space-crush-app/resources/shader/ship/tail_update_shared.glsl
  28. +21
    -0
      space-crush-app/resources/shader/ship/tail_update_vert.glsl
  29. +0
    -17
      space-crush-app/resources/shader/ship/vert.glsl
  30. +2
    -3
      space-crush-app/src/constants.rs
  31. +2
    -2
      space-crush-app/src/main.rs
  32. +2
    -0
      space-crush-app/src/misc/mod.rs
  33. +222
    -0
      space-crush-app/src/misc/particles.rs
  34. +2
    -4
      space-crush-app/src/misc/text.rs
  35. +35
    -32
      space-crush-app/src/misc/world.rs
  36. +113
    -55
      space-crush-app/src/render/asteroids.rs
  37. +100
    -50
      space-crush-app/src/render/planets.rs
  38. +366
    -82
      space-crush-app/src/render/ships.rs
  39. +4
    -4
      space-crush-app/src/resources/camera.rs
  40. +6
    -6
      space-crush-app/src/resources/geometry.rs
  41. +23
    -7
      space-crush-app/src/resources/uniform.rs
  42. +3
    -1
      space-crush-common/src/components/asteroid.rs
  43. +3
    -1
      space-crush-common/src/components/planet.rs
  44. +4
    -4
      space-crush-common/src/components/player.rs
  45. +3
    -1
      space-crush-common/src/components/ship.rs
  46. +111
    -26
      space-crush-common/src/misc/flagged_storage.rs
  47. +3
    -1
      space-crush-common/src/misc/mod.rs
  48. +7
    -15
      space-crush-common/src/systems/fleet_owned_update.rs
  49. +7
    -15
      space-crush-common/src/systems/orbit_owned_update.rs
  50. +11
    -14
      space-crush-common/src/systems/ships.rs

glc/src/array_buffer.rs → glc/src/buffer.rs View File

@@ -1,6 +1,8 @@
use std::cell::{Ref, RefCell};
use std::mem::size_of;
use std::ops::{Deref, DerefMut};
use std::ptr::null;
use std::rc::Rc;
use std::slice::from_raw_parts_mut;

use crate::{
@@ -8,31 +10,30 @@ use crate::{
misc::{AsEnum, Bindable},
};

/* ArrayBuffer */
/* Buffer */

pub struct ArrayBuffer {
pub struct Buffer {
id: gl::GLuint,
target: Target,
size: usize,
}

impl ArrayBuffer {
pub fn new(target: Target) -> Result<Self, Error> {
impl Buffer {
pub fn new() -> Result<Self, Error> {
let mut id = 0;

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 {
self.id
}

pub fn size(&self) -> usize {
self.size
}

pub fn buffer_data<T>(&mut self, usage: Usage, data: &[T]) -> Result<(), Error> {
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> {
@@ -150,26 +157,29 @@ impl ArrayBuffer {
}
}

impl Drop for ArrayBuffer {
impl Drop for Buffer {
fn drop(&mut self) {
gl::delete_buffers(1, &self.id);
}
}

impl Bindable for ArrayBuffer {
impl<T> Bindable for (Target, T)
where
T: Deref<Target = Buffer>,
{
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) {
gl::bind_buffer(self.target.as_enum(), 0);
gl::bind_buffer(self.0.as_enum(), 0);
}
}

/* Map */

pub struct Map<'a, T> {
buf: &'a ArrayBuffer,
buf: &'a Buffer,
data: &'a [T],
}

@@ -190,7 +200,7 @@ impl<T> Deref for Map<'_, T> {
/* MapMut */

pub struct MapMut<'a, T> {
buf: &'a ArrayBuffer,
buf: &'a Buffer,
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 */

#[derive(Debug, Copy, Clone, Eq, PartialEq)]

+ 6
- 0
glc/src/error.rs View File

@@ -40,6 +40,12 @@ pub enum Error {
#[error("Vertex Array: Expected pointer!")]
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!")]
InvalidParameter,



+ 2
- 1
glc/src/lib.rs View File

@@ -1,6 +1,6 @@
pub mod angle;
pub mod animation;
pub mod array_buffer;
pub mod buffer;
pub mod error;
pub mod math;
pub mod matrix;
@@ -8,5 +8,6 @@ pub mod misc;
pub mod numeric;
pub mod shader;
pub mod texture;
pub mod transform_feedback;
pub mod vector;
pub mod vertex_array;

+ 108
- 33
glc/src/shader.rs View File

@@ -20,6 +20,10 @@ pub struct Program {
}

impl Program {
pub fn builder() -> Builder {
Builder::default()
}

pub fn from_shaders<I>(iter: I) -> Result<Self, Error>
where
I: IntoIterator<Item = Shader>,
@@ -32,43 +36,15 @@ impl Program {
I: IntoIterator<Item = Result<Shader, E>>,
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 {
@@ -87,6 +63,7 @@ impl Program {
Uniform::Vector2f(v) => gl::uniform_2fv(location, 1, v.as_ptr()),
Uniform::Float(v) => gl::uniform_1f(location, v),
Uniform::Texture(i) => gl::uniform_1i(location, i),
Uniform::TextureVec(i) => gl::uniform_1iv(location, i.len() as _, i.as_ptr()),
}

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

#[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 */

pub enum Uniform<'a> {
@@ -285,6 +359,7 @@ pub enum Uniform<'a> {
Vector2f(&'a Vector2f),
Float(f32),
Texture(gl::GLint),
TextureVec(&'a [gl::GLint]),
}

/* IntoUniformLocation */


+ 117
- 0
glc/src/transform_feedback.rs View File

@@ -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,
}

+ 114
- 45
glc/src/vertex_array.rs View File

@@ -1,37 +1,37 @@
use crate::{
array_buffer::ArrayBuffer,
buffer::{Buffer, BufferRef, Target},
error::Error,
misc::{AsEnum, BindGuard, Bindable},
};

/* VertexArray */

pub struct VertexArray {
pub struct VertexArray<T = Buffer> {
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()
}

pub fn buffers(&self) -> &Vec<ArrayBuffer> {
pub fn buffers(&self) -> &[T] {
&self.buffers
}

pub fn buffers_mut(&mut self) -> &mut Vec<ArrayBuffer> {
pub fn buffers_mut(&mut self) -> &mut [T] {
&mut self.buffers
}
}

impl Drop for VertexArray {
impl<T> Drop for VertexArray<T> {
fn drop(&mut self) {
gl::delete_vertex_arrays(1, &self.id);
}
}

impl Bindable for VertexArray {
impl<T> Bindable for VertexArray<T> {
fn bind(&self) {
gl::bind_vertex_array(self.id);
}
@@ -43,13 +43,12 @@ impl Bindable for VertexArray {

/* 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 {
buffer,
pointers: Vec::new(),
@@ -59,8 +58,13 @@ impl Builder {

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;

Error::checked(|| gl::create_vertex_arrays(1, &mut id))?;
@@ -74,25 +78,41 @@ impl Builder {

let mut buffers = Vec::new();
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 {
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 {
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 */

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

@@ -171,15 +210,32 @@ impl BindingBuilder {

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

impl<T> Clone for BindingBuilder<T>
where
T: Clone,
{
fn clone(&self) -> Self {
Self {
builder: self.builder.clone(),
}
}
}

/* DataType */

#[allow(non_camel_case_types)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum DataType {
Byte,
UnsignedByte,
@@ -218,19 +274,32 @@ impl AsEnum for DataType {

/* Binding */

struct Binding {
buffer: ArrayBuffer,
struct Binding<T> {
buffer: T,
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 */

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>,
}

+ 6
- 6
space-crush-app/resources/shader/asteroid/frag.glsl View File

@@ -12,17 +12,17 @@ const GlowArgs GLOW_ARGS = {
/* 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;

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

+ 46
- 0
space-crush-app/resources/shader/asteroid/geom.glsl View File

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

+ 11
- 0
space-crush-app/resources/shader/asteroid/shared.glsl View File

@@ -1,3 +1,14 @@
struct FragmentData {
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;

+ 9
- 8
space-crush-app/resources/shader/asteroid/vert.glsl View File

@@ -3,15 +3,16 @@
#pragma include ./shared.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() {
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
- 0
space-crush-app/resources/shader/misc/global.glsl View File

@@ -1,3 +1,4 @@
layout (std140) uniform Global {
float time;
float delta;
} uGlobal;

+ 3
- 4
space-crush-app/resources/shader/planet/frag.glsl View File

@@ -14,15 +14,14 @@ const GlowArgs GLOW_ARGS = {

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

+ 44
- 0
space-crush-app/resources/shader/planet/geom.glsl View File

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

+ 10
- 0
space-crush-app/resources/shader/planet/shared.glsl View File

@@ -1,3 +1,13 @@
struct FragmentData {
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;

+ 7
- 8
space-crush-app/resources/shader/planet/vert.glsl View File

@@ -3,15 +3,14 @@
#pragma include ./shared.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() {
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;
}

+ 0
- 29
space-crush-app/resources/shader/ship/frag.glsl View File

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

+ 0
- 3
space-crush-app/resources/shader/ship/shared.glsl View File

@@ -1,3 +0,0 @@
struct FragmentData {
vec2 texCoords;
};

+ 28
- 0
space-crush-app/resources/shader/ship/ship_frag.glsl View File

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

+ 46
- 0
space-crush-app/resources/shader/ship/ship_geom.glsl View File

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

+ 15
- 0
space-crush-app/resources/shader/ship/ship_shared.glsl View File

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

+ 17
- 0
space-crush-app/resources/shader/ship/ship_vert.glsl View File

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

+ 11
- 0
space-crush-app/resources/shader/ship/tail_render_frag.glsl View File

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

#pragma include ./tail_render_shared.glsl

in FragmentData fragmentData;

out vec4 outColor;

void main() {
outColor = fragmentData.color;
}

+ 40
- 0
space-crush-app/resources/shader/ship/tail_render_geom.glsl View File

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

+ 8
- 0
space-crush-app/resources/shader/ship/tail_render_shared.glsl View File

@@ -0,0 +1,8 @@
struct FragmentData {
vec4 color;
};

struct VertexData {
vec3 color;
vec2 tail[5];
};

+ 21
- 0
space-crush-app/resources/shader/ship/tail_render_vert.glsl View File

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

+ 38
- 0
space-crush-app/resources/shader/ship/tail_update_geom.glsl View File

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

+ 7
- 0
space-crush-app/resources/shader/ship/tail_update_shared.glsl View File

@@ -0,0 +1,7 @@
struct VertexData {
vec2 pos;
vec2 tail[5];
};

const float TAIL_LEN = 10.0;
const float TAIL_FORCE = 1.0;

+ 21
- 0
space-crush-app/resources/shader/ship/tail_update_vert.glsl View File

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

+ 0
- 17
space-crush-app/resources/shader/ship/vert.glsl View File

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

+ 2
- 3
space-crush-app/src/constants.rs View File

@@ -1,11 +1,10 @@
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_UNIFORM: gl::GLuint = 1;

pub const SHIP_SIZE: f32 = 25.0;
pub const PLANET_SIZE: f32 = 200.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_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);

+ 2
- 2
space-crush-app/src/main.rs View File

@@ -1,4 +1,4 @@
use glc::vector::Vector4f;
use glc::vector::Vector3f;
use log::{error, info};
use rand::random;
use space_crush_app::{App, Error};
@@ -38,7 +38,7 @@ fn run(vfs: Vfs) -> Result<(), Error> {
let mut common = Dispatcher::new(&mut world)?;
let player1 = world
.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();
let mut app = App::new(&mut world, player1)?;



+ 2
- 0
space-crush-app/src/misc/mod.rs View File

@@ -1,4 +1,5 @@
mod events;
// mod particles;
mod text;
mod window;
mod world;
@@ -6,6 +7,7 @@ mod world;
pub use events::{
ControlEvent, Events, KeyboardEvent, MouseButton, MouseEvent, VirtualKeyCode, WindowEvent,
};
// pub use particles::Particles;
pub use text::{HorizontalAlign, Text, TextCache, TextManager, VerticalAlign};
pub use window::Window;
pub use world::WorldHelper;

+ 222
- 0
space-crush-app/src/misc/particles.rs View File

@@ -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>,
}

+ 2
- 4
space-crush-app/src/misc/text.rs View File

@@ -11,7 +11,7 @@ use std::ptr::null;
use std::rc::{Rc, Weak};

use glc::{
array_buffer::{ArrayBuffer, Target, Usage},
buffer::{Buffer, Usage},
error::Error as GlcError,
misc::BindGuard,
shader::{Program, Type, Uniform},
@@ -592,7 +592,7 @@ impl Text {
const OFFSET_TEX_MAX: gl::GLsizei = OFFSET_TEX_MIN + 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()
.bind_buffer(buffer)
.vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE, OFFSET_POS_MIN)?
@@ -643,9 +643,7 @@ impl Text {
.uniform(2, Uniform::Vector2f(pos))
.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_instanced(gl::POINTS, 0, 1, inner.vertex_count as _);
}

pub fn update<S>(&mut self, mut index: usize, text: S) -> Result<&Self, Error>


+ 35
- 32
space-crush-app/src/misc/world.rs View File

@@ -17,6 +17,8 @@ pub trait WorldHelper {
where
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>;
}

@@ -25,39 +27,40 @@ impl WorldHelper for World {
where
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> {


+ 113
- 55
space-crush-app/src/render/asteroids.rs View File

@@ -1,15 +1,18 @@
use std::mem::size_of;

use glc::{
matrix::Matrix4f,
buffer::{Buffer, Usage},
misc::{BindGuard, Bindable},
shader::{Program, Type, Uniform},
texture::Texture,
vector::Vector4f,
vector::{Vector2f, Vector3f},
vertex_array::{DataType, VertexArray},
};
use space_crush_common::{
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::{
constants::{
@@ -17,7 +20,6 @@ use crate::{
UNIFORM_BUFFER_INDEX_UNIFORM,
},
misc::WorldHelper,
resources::Geometry,
Error,
};

@@ -25,47 +27,76 @@ pub struct Asteroids {
program: Program,
texture_metal: 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 {
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![
(Type::Vertex, "resources/shader/asteroid/vert.glsl"),
(Type::Geometry, "resources/shader/asteroid/geom.glsl"),
(Type::Fragment, "resources/shader/asteroid/frag.glsl"),
])?;

program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?;
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.uniform("uTexture", Uniform::Texture(0))?;
program.uniform("uTexture", Uniform::TextureVec(&[0, 1]))?;
program.unbind();

let texture_metal = world.load_texture("resources/textures/asteroid_metal.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 {
program,
texture_metal,
texture_crystal,
location_model,
location_glow_color,
vertex_array,
reader_id,
asteroid_count,
})
}
}

#[derive(SystemData)]
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>,
player: ReadStorage<'a, Player>,
}

impl<'a> System<'a> for Asteroids {
@@ -73,50 +104,77 @@ impl<'a> System<'a> for Asteroids {

fn run(&mut self, data: Self::SystemData) {
let AsteroidsData {
geometry,
position,
asteroid,
positions,
asteroids,
players,
owned,
player,
} = 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.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);
}
}

+ 100
- 50
space-crush-app/src/render/planets.rs View File

@@ -1,15 +1,18 @@
use std::mem::size_of;

use glc::{
matrix::Matrix4f,
buffer::{Buffer, Usage},
misc::{BindGuard, Bindable},
shader::{Program, Type, Uniform},
texture::Texture,
vector::Vector4f,
vector::{Vector2f, Vector3f},
vertex_array::{DataType, VertexArray},
};
use space_crush_common::{
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::{
constants::{
@@ -17,52 +20,77 @@ use crate::{
UNIFORM_BUFFER_INDEX_UNIFORM,
},
misc::WorldHelper,
resources::Geometry,
Error,
};

pub struct Planets {
program: Program,
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 {
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![
(Type::Vertex, "resources/shader/planet/vert.glsl"),
(Type::Geometry, "resources/shader/planet/geom.glsl"),
(Type::Fragment, "resources/shader/planet/frag.glsl"),
])?;

program.uniform_block_binding("Camera", UNIFORM_BUFFER_INDEX_CAMERA)?;
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.uniform("uTexture", Uniform::Texture(0))?;
program.unbind();

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 {
program,
texture,
location_model,
location_glow_color,
vertex_array,
reader_id,
planet_count,
})
}
}

#[derive(SystemData)]
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>,
player: ReadStorage<'a, Player>,
}

impl<'a> System<'a> for Planets {
@@ -70,46 +98,68 @@ impl<'a> System<'a> for Planets {

fn run(&mut self, data: Self::SystemData) {
let PlanetsData {
geometry,
position,
planet,
positions,
planets,
players,
owned,
player,
} = 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.vertex_array);
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);
}
}

+ 366
- 82
space-crush-app/src/render/ships.rs View File

@@ -1,129 +1,413 @@
use std::cell::RefCell;
use std::mem::{size_of, swap};
use std::rc::Rc;

use glc::{
matrix::Matrix4f,
buffer::{Buffer, Usage},
misc::{BindGuard, Bindable},
shader::{Program, Type, Uniform},
shader::{Program, TransformFeedbackVaryingsMode, Type, Uniform},
texture::Texture,
vector::Vector4f,
transform_feedback::TransformFeedback,
vector::{Vector2f, Vector3f},
vertex_array::{DataType, VertexArray},
};
use space_crush_common::{
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::{
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,
resources::Geometry,
Error,
};

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_fighter: 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 {
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_fighter = world.load_texture("resources/textures/ship_fighter.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 {
program,
program_ship,
program_tail_update,
program_tail_render,

ship_data,
ship_render,

input,
output,

texture_bomber,
texture_fighter,
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 {
type SystemData = ShipsData<'a>;

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;

+ 4
- 4
space-crush-app/src/resources/camera.rs View File

@@ -1,14 +1,14 @@
#![allow(dead_code)]

use glc::{
array_buffer::{ArrayBuffer, Target, Usage},
buffer::{Buffer, Target, Usage},
error::Error,
matrix::Matrix4f,
vector::Vector2f,
};

pub struct Camera {
buffer: ArrayBuffer,
buffer: Buffer,
data: Data,
view_invert: Matrix4f,
projection_invert: Matrix4f,
@@ -30,7 +30,7 @@ impl Camera {
view: Matrix4f::identity(),
size: Vector2f::default(),
};
let mut buffer = ArrayBuffer::new(Target::UniformBuffer)?;
let mut buffer = Buffer::new()?;
buffer.buffer_data(Usage::StaticDraw, &[data.clone()])?;

Ok(Self {
@@ -100,7 +100,7 @@ impl Camera {
}

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 {


+ 6
- 6
space-crush-app/src/resources/geometry.rs View File

@@ -3,7 +3,7 @@
use std::mem::size_of;

use glc::{
array_buffer::{ArrayBuffer, Target, Usage},
buffer::{Buffer, Usage},
misc::Bindable,
shader::{Program, Type, Uniform},
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 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()
.bind_buffer(array_buffer)
.bind_buffer(buffer)
.vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE_POS, OFFSET_POS)?
.build()?;

@@ -93,10 +93,10 @@ fn create_array_line() -> Result<VertexArray, Error> {
const STRIDE_POS: gl::GLsizei = size_of::<Vector2f>() as gl::GLsizei;
const OFFSET_POS: gl::GLsizei = 0;

let array_buffer = ArrayBuffer::new(Target::ArrayBuffer)?;
let buffer = Buffer::new()?;

let vertex_array = VertexArray::builder()
.bind_buffer(array_buffer)
.bind_buffer(buffer)
.vertex_attrib_pointer(0, 2, DataType::Float, false, STRIDE_POS, OFFSET_POS)?
.build()?;



+ 23
- 7
space-crush-app/src/resources/uniform.rs View File

@@ -1,42 +1,58 @@
use std::time::Instant;

use glc::{
array_buffer::{ArrayBuffer, Target, Usage},
buffer::{Buffer, Target, Usage},
error::Error,
};

pub struct Uniform {
buffer: ArrayBuffer,
buffer: Buffer,
start_time: Instant,
last_time: Instant,
}

#[repr(C, packed)]
struct Data {
time: f32,
delta: f32,
}

impl Uniform {
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 {
buffer,
start_time: Instant::now(),
start_time: now,
last_time: now,
})
}

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

data[0].time = time;
data[0].delta = delta;

Ok(())
}

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

+ 3
- 1
space-crush-common/src/components/asteroid.rs View File

@@ -1,6 +1,8 @@
use serde::{Deserialize, Serialize};
use specs::{Component, HashMapStorage};

use crate::misc::FlaggedStorage;

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Asteroid {
type_: Type,
@@ -25,5 +27,5 @@ impl Asteroid {
}

impl Component for Asteroid {
type Storage = HashMapStorage<Self>;
type Storage = FlaggedStorage<Self, HashMapStorage<Self>>;
}

+ 3
- 1
space-crush-common/src/components/planet.rs View File

@@ -1,9 +1,11 @@
use serde::{Deserialize, Serialize};
use specs::{Component, NullStorage};

use crate::misc::FlaggedStorage;

#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Planet {}

impl Component for Planet {
type Storage = NullStorage<Self>;
type Storage = FlaggedStorage<Self, NullStorage<Self>>;
}

+ 4
- 4
space-crush-common/src/components/player.rs View File

@@ -1,4 +1,4 @@
use glc::vector::Vector4f;
use glc::vector::Vector3f;
use serde::{Deserialize, Serialize};
use specs::{
error::NoError,
@@ -9,7 +9,7 @@ use specs::{
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Player {
index: usize,
color: Vector4f,
color: Vector3f,
}

#[derive(Copy, Clone, Debug)]
@@ -24,7 +24,7 @@ pub struct OwnedData<M> {

impl Player {
#[inline]
pub fn new(color: Vector4f) -> Self {
pub fn new(color: Vector3f) -> Self {
Self {
index: next_index(),
color,
@@ -37,7 +37,7 @@ impl Player {
}

#[inline]
pub fn color(&self) -> &Vector4f {
pub fn color(&self) -> &Vector3f {
&self.color
}
}


+ 3
- 1
space-crush-common/src/components/ship.rs View File

@@ -5,6 +5,8 @@ use glc::vector::Vector2f;
use serde::{Deserialize, Serialize};
use specs::{Component, Entity, VecStorage};

use crate::misc::FlaggedStorage;

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Ship {
type_: Type,
@@ -84,7 +86,7 @@ impl Ship {
}

impl Component for Ship {
type Storage = VecStorage<Self>;
type Storage = FlaggedStorage<Self, VecStorage<Self>>;
}

impl Default for Obstacle {


+ 111
- 26
space-crush-common/src/misc/flagged_storage.rs View File

@@ -1,59 +1,53 @@
#![allow(dead_code)]

use std::ops::{Deref, DerefMut};

use hibitset::BitSetLike;
use shrev::EventChannel;
use shrev::{Event, EventChannel, ReaderId};
use specs::{
storage::{TryDefault, UnprotectedStorage},
storage::{DistinctStorage, MaskedStorage, Storage, TryDefault, UnprotectedStorage},
world::Index,
Component, DenseVecStorage,
};

/* FlaggedStorage */

pub struct FlaggedStorage<C, T = DenseVecStorage<C>>
where
C: Send + Sync + 'static,
C: Event,
{
event_emission: bool,
channel: EventChannel<ComponentEvent<C>>,
storage: T,
}

pub enum ComponentEvent<C>
where
C: Send + Sync + 'static,
C: Event,
{
Inserted(Index, C),
Modified(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>
where
C: Send + Sync + 'static,
C: Event,
T: TryDefault,
{
fn default() -> Self {
FlaggedStorage {
event_emission: true,
channel: EventChannel::new(),
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
C: Send + Sync + 'static,
C: Component + Event + Clone,
T: UnprotectedStorage<C>,
{
unsafe fn clean<B>(&mut self, has: B)
where
@@ -69,8 +63,10 @@ where
unsafe fn get_mut(&mut self, id: Index) -> &mut C {
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
}
@@ -78,16 +74,105 @@ where
unsafe fn insert(&mut self, id: Index, component: C) {
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 {
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
}
}

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

+ 3
- 1
space-crush-common/src/misc/mod.rs View File

@@ -7,7 +7,9 @@ mod world;

pub use self::log::init as init_logger;
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 persistence::{PersistWorld, Persistence};
pub use world::WorldHelper;

+ 7
- 15
space-crush-common/src/systems/fleet_owned_update.rs View File

@@ -5,7 +5,7 @@ use specs::{prelude::*, world::Index, Entities, ReadStorage, System, World, Writ

use crate::{
components::{Fleet, FleetOwned, Ship},
misc::ComponentEvent,
misc::{ComponentEvent, StorageHelper, StorageHelperMut},
};

pub struct FleetOwnedUpdate {
@@ -17,19 +17,14 @@ pub struct FleetOwnedUpdate {

impl FleetOwnedUpdate {
pub fn new(world: &mut World) -> Self {
WriteStorage::<FleetOwned>::setup(world);

let fleet_ids = BitSet::new();
let fleet_owned_ids = BitSet::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 {
fleet_ids,
@@ -64,10 +59,7 @@ impl<'a> System<'a> for FleetOwnedUpdate {
self.old_fleet_ids.clear();

/* 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 {
match event {
ComponentEvent::Inserted(id, fleet_owned) => {


+ 7
- 15
space-crush-common/src/systems/orbit_owned_update.rs View File

@@ -8,7 +8,7 @@ use specs::{

use crate::{
components::{Orbit, OrbitOwned, PlayerOwned},
misc::ComponentEvent,
misc::{ComponentEvent, StorageHelper, StorageHelperMut},
};

pub struct OrbitOwnedUpdate {
@@ -20,19 +20,14 @@ pub struct OrbitOwnedUpdate {

impl OrbitOwnedUpdate {
pub fn new(world: &mut World) -> Self {
WriteStorage::<OrbitOwned>::setup(world);

let orbit_ids = BitSet::new();
let orbit_owned_ids = BitSet::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 {
orbit_ids,
@@ -67,10 +62,7 @@ impl<'a> System<'a> for OrbitOwnedUpdate {
self.old_orbit_ids.clear();

/* 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 {
match event {
ComponentEvent::Inserted(id, orbit_owned) => {


+ 11
- 14
space-crush-common/src/systems/ships.rs View File

@@ -16,7 +16,7 @@ use crate::{
SHIP_ORBIT_AGILITY, SHIP_ORBIT_ANGLE_DELTA_MIN, SHIP_ORBIT_ANGLE_DELTA_RND,
SHIP_ORBIT_DISTANCE_MAX, VECTOR_2F_POS_X,
},
misc::ComponentEvent,
misc::{ComponentEvent, StorageHelper, StorageHelperMut},
resources::Global,
return_if_none,
};
@@ -51,16 +51,12 @@ struct Processor<'a> {

impl Ships {
pub fn new(world: &mut World) -> Self {
WriteStorage::<FleetOwned>::setup(world);

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 {
need_update,
@@ -70,10 +66,7 @@ impl Ships {

fn progress_events(&mut self, fleet_owned: &ReadStorage<'_, FleetOwned>) {
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 {
let id = match event {
ComponentEvent::Inserted(id, _) => id,
@@ -115,6 +108,8 @@ impl<'a> System<'a> for Ships {
delta: global.delta * global.world_speed,
};

ships.set_event_emission(false);

let data = (
positions.mask(),
&mut ships,
@@ -127,6 +122,8 @@ impl<'a> System<'a> for Ships {
.for_each(|(id, ship, velocity, position, fleet_owned)| {
processor.progress_ship(id, ship, velocity, position, fleet_owned);
});

ships.set_event_emission(true);
}
}



Loading…
Cancel
Save