| @@ -1,3 +1,4 @@ | |||
| use std::ffi::NulError; | |||
| use std::io::Error as IoError; | |||
| use std::str::Utf8Error; | |||
| @@ -12,6 +13,9 @@ pub enum Error { | |||
| #[error("UTF-8 Error: {0}")] | |||
| Utf8Error(Utf8Error), | |||
| #[error("FFI Error: {0}")] | |||
| NulError(NulError), | |||
| #[error("Image Format Error: {0}")] | |||
| ImageFmtError(ImageFmtError), | |||
| @@ -24,6 +28,12 @@ pub enum Error { | |||
| #[error("Error while linking shader program: {0}")] | |||
| ShaderLink(String), | |||
| #[error("Error while resolving include: {0}")] | |||
| ShaderInclude(String), | |||
| #[error("Unknown Uniform: {0}")] | |||
| ShaderUnknownUniform(String), | |||
| #[error("Vertex Array: Index is already in use: {0}!")] | |||
| VertexArrayIndexAlreadyInUse(gl::GLuint), | |||
| @@ -79,6 +89,12 @@ impl From<Utf8Error> for Error { | |||
| } | |||
| } | |||
| impl From<NulError> for Error { | |||
| fn from(err: NulError) -> Self { | |||
| Self::NulError(err) | |||
| } | |||
| } | |||
| impl From<ImageFmtError> for Error { | |||
| fn from(err: ImageFmtError) -> Self { | |||
| Self::ImageFmtError(err) | |||
| @@ -1,3 +1,4 @@ | |||
| use std::ffi::CString; | |||
| use std::fs::File; | |||
| use std::io::Read; | |||
| use std::path::Path; | |||
| @@ -74,11 +75,60 @@ impl Program { | |||
| self.id | |||
| } | |||
| pub fn uniform(&self, location: gl::GLint, uniform: Uniform<'_>) { | |||
| pub fn uniform<T>(&self, location: T, uniform: Uniform<'_>) -> Result<(), Error> | |||
| where | |||
| T: IntoUniformLocation, | |||
| { | |||
| let location = IntoUniformLocation::into_location(location, &self)?; | |||
| match uniform { | |||
| Uniform::Matrix4f(v) => gl::uniform_matrix_4fv(location, 1, gl::FALSE, v.as_ptr()), | |||
| Uniform::Vector4f(v) => gl::uniform_4fv(location, 1, v.as_ptr()), | |||
| Uniform::Texture(i) => gl::uniform_1i(location, i), | |||
| } | |||
| Ok(()) | |||
| } | |||
| pub fn uniform_location<T>(&self, name: T) -> Result<gl::GLint, Error> | |||
| where | |||
| T: Into<String>, | |||
| { | |||
| let name = Into::<String>::into(name); | |||
| let name = CString::new(name)?; | |||
| let location = Error::checked(|| gl::get_uniform_location(self.id, name.as_ptr()))?; | |||
| if location >= 0 { | |||
| Ok(location) | |||
| } else { | |||
| Err(Error::ShaderUnknownUniform(name.into_string().unwrap())) | |||
| } | |||
| } | |||
| pub fn uniform_block_index<T>(&self, name: T) -> Result<gl::GLuint, Error> | |||
| where | |||
| T: Into<String>, | |||
| { | |||
| let name = Into::<String>::into(name); | |||
| let name = CString::new(name)?; | |||
| let location = Error::checked(|| gl::get_uniform_block_index(self.id, name.as_ptr()))?; | |||
| if location != gl::INVALID_INDEX { | |||
| Ok(location) | |||
| } else { | |||
| Err(Error::ShaderUnknownUniform(name.into_string().unwrap())) | |||
| } | |||
| } | |||
| pub fn uniform_block_binding<T>(&self, index: T, binding: gl::GLuint) -> Result<(), Error> | |||
| where | |||
| T: IntoUniformBlockIndex, | |||
| { | |||
| let index = IntoUniformBlockIndex::into_index(index, &self)?; | |||
| gl::uniform_block_binding(self.id, index, binding); | |||
| Ok(()) | |||
| } | |||
| } | |||
| @@ -105,15 +155,26 @@ pub struct Shader { | |||
| } | |||
| impl Shader { | |||
| pub fn from_string(type_: Type, mut source: String) -> Result<Self, Error> { | |||
| pub fn from_string<F>(type_: Type, mut source: String, f: F) -> Result<Self, Error> | |||
| where | |||
| F: Fn(&str) -> Result<String, Error>, | |||
| { | |||
| while let Some(p) = source.find("#pragma include ") { | |||
| let s = &source[p..]; | |||
| let e = s.find('\n').unwrap_or_else(|| s.len()); | |||
| let s = &s[..e]; | |||
| let c = f(&s[16..])?; | |||
| source = source.replace(s, &c); | |||
| } | |||
| let id = gl::create_shader(type_.as_enum()); | |||
| let id = Error::err_if(&0, id)?; | |||
| source.push('\0'); | |||
| let source_ptr = source.as_ptr() as *const i8; | |||
| let source_ptr: *const *const i8 = &source_ptr; | |||
| gl::shader_source(id, 1, source_ptr, null()); | |||
| let source = CString::new(source)?; | |||
| let ptr = source.as_ptr(); | |||
| let ptr: *const *const _ = &ptr; | |||
| gl::shader_source(id, 1, ptr as *const *const _, null()); | |||
| gl::compile_shader(id); | |||
| let mut success = 1; | |||
| @@ -134,9 +195,15 @@ impl Shader { | |||
| ); | |||
| let msg = from_utf8(&buffer)?; | |||
| let code = source.into_string().unwrap(); | |||
| let code = code | |||
| .lines() | |||
| .enumerate() | |||
| .map(|(i, s)| format!("{:03}: {}\n", i + 1, s)) | |||
| .collect(); | |||
| return Err(Error::ShaderCompile { | |||
| code: source, | |||
| code, | |||
| error: msg.into(), | |||
| }); | |||
| } | |||
| @@ -144,23 +211,25 @@ impl Shader { | |||
| Ok(Self { id }) | |||
| } | |||
| pub fn from_reader<R>(type_: Type, reader: &mut R) -> Result<Self, Error> | |||
| pub fn from_reader<R, F>(type_: Type, reader: &mut R, f: F) -> Result<Self, Error> | |||
| where | |||
| R: Read, | |||
| F: Fn(&str) -> Result<String, Error>, | |||
| { | |||
| let mut source = String::new(); | |||
| reader.read_to_string(&mut source)?; | |||
| Self::from_string(type_, source) | |||
| Self::from_string(type_, source, f) | |||
| } | |||
| pub fn from_file<P>(type_: Type, path: P) -> Result<Self, Error> | |||
| pub fn from_file<P, F>(type_: Type, path: P, f: F) -> Result<Self, Error> | |||
| where | |||
| P: AsRef<Path>, | |||
| F: Fn(&str) -> Result<String, Error>, | |||
| { | |||
| let mut file = File::open(&path)?; | |||
| match Self::from_reader(type_, &mut file) { | |||
| match Self::from_reader(type_, &mut file, f) { | |||
| Ok(v) => Ok(v), | |||
| Err(Error::ShaderCompile { code, error }) => Err(Error::ShaderCompile { | |||
| code: format!("{}\n{}", path.as_ref().display(), code), | |||
| @@ -211,4 +280,53 @@ impl AsEnum for Type { | |||
| pub enum Uniform<'a> { | |||
| Matrix4f(&'a Matrix4f), | |||
| Vector4f(&'a Vector4f), | |||
| Texture(gl::GLint), | |||
| } | |||
| /* IntoUniformLocation */ | |||
| pub trait IntoUniformLocation { | |||
| fn into_location(self, program: &Program) -> Result<gl::GLint, Error>; | |||
| } | |||
| impl IntoUniformLocation for gl::GLint { | |||
| fn into_location(self, _program: &Program) -> Result<gl::GLint, Error> { | |||
| Ok(self) | |||
| } | |||
| } | |||
| impl IntoUniformLocation for &str { | |||
| fn into_location(self, program: &Program) -> Result<gl::GLint, Error> { | |||
| program.uniform_location(self) | |||
| } | |||
| } | |||
| impl IntoUniformLocation for String { | |||
| fn into_location(self, program: &Program) -> Result<gl::GLint, Error> { | |||
| program.uniform_location(self) | |||
| } | |||
| } | |||
| /* IntoUniformBlockIndex */ | |||
| pub trait IntoUniformBlockIndex { | |||
| fn into_index(self, program: &Program) -> Result<gl::GLuint, Error>; | |||
| } | |||
| impl IntoUniformBlockIndex for gl::GLuint { | |||
| fn into_index(self, _program: &Program) -> Result<gl::GLuint, Error> { | |||
| Ok(self) | |||
| } | |||
| } | |||
| impl IntoUniformBlockIndex for &str { | |||
| fn into_index(self, program: &Program) -> Result<gl::GLuint, Error> { | |||
| program.uniform_block_index(self) | |||
| } | |||
| } | |||
| impl IntoUniformBlockIndex for String { | |||
| fn into_index(self, program: &Program) -> Result<gl::GLuint, Error> { | |||
| program.uniform_block_index(self) | |||
| } | |||
| } | |||
| @@ -0,0 +1,5 @@ | |||
| layout (std140) uniform Camera { | |||
| mat4 projection; | |||
| mat4 view; | |||
| vec2 size; | |||
| } uCamera; | |||
| @@ -0,0 +1,3 @@ | |||
| layout (std140) uniform Global { | |||
| float time; | |||
| } uGlobal; | |||
| @@ -0,0 +1,18 @@ | |||
| struct GlowArgs { | |||
| float step0; | |||
| float step1; | |||
| float pulseSize0; | |||
| float pulseSize1; | |||
| float pulseTime; | |||
| }; | |||
| float glow(GlowArgs args, vec2 pos, float time) { | |||
| float radius = length(pos); | |||
| float pulse = sin(args.pulseTime * time); | |||
| float glow = 1.0 - smoothstep( | |||
| args.step0 + args.pulseSize0 * pulse, | |||
| args.step1 + args.pulseSize1 * pulse, | |||
| radius); | |||
| return glow; | |||
| } | |||
| @@ -1,7 +0,0 @@ | |||
| #version 450 core | |||
| layout (location = 0) in vec3 position; | |||
| void main() { | |||
| gl_Position = vec4(2.0 * position, 1.0); | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| #version 450 core | |||
| out vec4 color; | |||
| out vec4 outColor; | |||
| const float NOISE_RANGE = 0.05; | |||
| const float NOISE_BASE = 0.05; | |||
| @@ -13,5 +13,5 @@ void main() { | |||
| float rnd = random(gl_FragCoord); | |||
| vec3 rgb = vec3(NOISE_BASE + NOISE_RANGE * rnd); | |||
| color = vec4(rgb, 1.0); | |||
| outColor = vec4(rgb, 1.0); | |||
| } | |||
| @@ -0,0 +1,7 @@ | |||
| #version 450 core | |||
| in vec3 inPosition; | |||
| void main() { | |||
| gl_Position = vec4(2.0 * inPosition, 1.0); | |||
| } | |||
| @@ -1,35 +0,0 @@ | |||
| #version 450 core | |||
| const float GLOW_STEP_0 = 0.480; // inner (min = 0.0) | |||
| const float GLOW_STEP_1 = 0.975; // outer (max = 0.5) | |||
| const float GLOW_PULSE_SIZE_0 = 0.010; // inner (+/-) | |||
| const float GLOW_PULSE_SIZE_1 = 0.025; // outer (+/-) | |||
| const float GLOW_PULSE_TIME = 2.000; | |||
| in FragmentData { | |||
| vec2 texCoords; | |||
| } data; | |||
| layout (std140, binding = 2) uniform Global { | |||
| float time; | |||
| } global; | |||
| layout(location = 3) uniform vec4 glowColor; | |||
| uniform sampler2D tex; | |||
| out vec4 color; | |||
| void main() { | |||
| vec2 texCoords = data.texCoords - vec2(0.5); | |||
| float radius = length(texCoords); | |||
| float bgPulse = sin(GLOW_PULSE_TIME * global.time); | |||
| float alpha = 1.0 - smoothstep( | |||
| GLOW_STEP_0 + GLOW_PULSE_SIZE_0 * bgPulse, | |||
| GLOW_STEP_1 + GLOW_PULSE_SIZE_1 * bgPulse, | |||
| radius); | |||
| vec4 tex = texture(tex, data.texCoords); | |||
| vec4 glow = vec4(glowColor.rgb, glowColor.a * alpha); | |||
| color = tex * tex.a + glow * (1.0 - tex.a); | |||
| } | |||
| @@ -1,22 +0,0 @@ | |||
| #version 450 core | |||
| const float GLOW_SIZE_FACTOR = 2.00; | |||
| layout (location = 0) in vec3 position; | |||
| layout (std140, binding = 0) uniform Camera { | |||
| mat4 projection; | |||
| mat4 view; | |||
| vec2 size; | |||
| } camera; | |||
| layout (location = 1) uniform mat4 model; | |||
| out FragmentData { | |||
| vec2 texCoords; | |||
| } data; | |||
| void main() { | |||
| data.texCoords = position.xy * GLOW_SIZE_FACTOR + vec2(0.5); | |||
| gl_Position = camera.projection * camera.view * model * vec4(position * GLOW_SIZE_FACTOR, 1.0); | |||
| } | |||
| @@ -0,0 +1,28 @@ | |||
| #version 450 core | |||
| #pragma include ./shared.glsl | |||
| #pragma include ../misc/glow.glsl | |||
| #pragma include ../misc/global.glsl | |||
| const GlowArgs GLOW_ARGS = { | |||
| /* step0 */ 0.480, | |||
| /* step1 */ 0.975, | |||
| /* pulseSize0 */ 0.010, | |||
| /* pulseSize1 */ 0.025, | |||
| /* 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); | |||
| vec4 tex = texture(uTexture, fragmentData.texCoords); | |||
| outColor = tex * tex.a + glow * (1.0 - tex.a); | |||
| } | |||
| @@ -0,0 +1,3 @@ | |||
| struct FragmentData { | |||
| vec2 texCoords; | |||
| }; | |||
| @@ -0,0 +1,17 @@ | |||
| #version 450 core | |||
| #pragma include ./shared.glsl | |||
| #pragma include ../misc/camera.glsl | |||
| const float GLOW_SIZE_FACTOR = 2.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(inPosition * GLOW_SIZE_FACTOR, 1.0); | |||
| } | |||
| @@ -1,13 +0,0 @@ | |||
| #version 450 core | |||
| in FragmentData { | |||
| vec2 texCoords; | |||
| } data; | |||
| uniform sampler2D tex; | |||
| out vec4 color; | |||
| void main() { | |||
| color = texture(tex, data.texCoords); | |||
| } | |||
| @@ -1,20 +0,0 @@ | |||
| #version 450 core | |||
| layout (location = 0) in vec3 position; | |||
| layout (std140, binding = 0) uniform Camera { | |||
| mat4 projection; | |||
| mat4 view; | |||
| vec2 size; | |||
| } camera; | |||
| layout (location = 1) uniform mat4 model; | |||
| out FragmentData { | |||
| vec2 texCoords; | |||
| } data; | |||
| void main() { | |||
| data.texCoords = position.xy + vec2(0.5); | |||
| gl_Position = camera.projection * camera.view * model * vec4(position, 1.0); | |||
| } | |||
| @@ -1,20 +0,0 @@ | |||
| #version 450 core | |||
| in FragmentData { | |||
| vec2 texCoords; | |||
| vec4 color; | |||
| } data; | |||
| uniform sampler2D tex; | |||
| out vec4 color; | |||
| void main() { | |||
| float alpha = texture(tex, data.texCoords).r; | |||
| if (alpha <= 0.0) { | |||
| discard; | |||
| } | |||
| color = data.color * vec4(1.0, 1.0, 1.0, alpha); | |||
| } | |||
| @@ -1,59 +0,0 @@ | |||
| #version 450 core | |||
| layout (location = 0) in vec2 pos_min; | |||
| layout (location = 1) in vec2 pos_max; | |||
| layout (location = 2) in vec2 tex_min; | |||
| layout (location = 3) in vec2 tex_max; | |||
| layout (location = 4) in vec4 color; | |||
| layout (std140, binding = 0) uniform Camera { | |||
| mat4 projection; | |||
| mat4 view; | |||
| vec2 size; | |||
| } camera; | |||
| layout (location = 1) uniform mat4 model; | |||
| out FragmentData { | |||
| vec2 texCoords; | |||
| vec4 color; | |||
| } data; | |||
| void main() { | |||
| vec2 position = vec2(0.0); | |||
| vec2 texCoords = vec2(0.0); | |||
| switch (gl_VertexID) { | |||
| case 0: | |||
| position = vec2(pos_min.x, pos_max.y); | |||
| texCoords = vec2(tex_min.x, tex_max.y); | |||
| break; | |||
| case 1: | |||
| position = vec2(pos_min.x, pos_min.y); | |||
| texCoords = vec2(tex_min.x, tex_min.y); | |||
| break; | |||
| case 2: | |||
| position = vec2(pos_max.x, pos_max.y); | |||
| texCoords = vec2(tex_max.x, tex_max.y); | |||
| break; | |||
| case 3: | |||
| position = vec2(pos_max.x, pos_min.y); | |||
| texCoords = vec2(tex_max.x, tex_min.y); | |||
| break; | |||
| } | |||
| mat4 ortho = mat4( | |||
| vec4(2.0 / camera.size.x, 0.0, 0.0, 0.0), | |||
| vec4(0.0, -2.0 / camera.size.y, 0.0, 0.0), | |||
| vec4(0.0, 0.0, 1.0, 0.0), | |||
| vec4(-1.0, 1.0, 1.0, 1.0) | |||
| ); | |||
| gl_Position = ortho * vec4(position, 0.0, 1.0); | |||
| data.texCoords = texCoords; | |||
| data.color = color; | |||
| } | |||
| @@ -0,0 +1,19 @@ | |||
| #version 450 core | |||
| #pragma include ./shared.glsl | |||
| in FragmentData fragmentData; | |||
| uniform sampler2D uTexture; | |||
| out vec4 outColor; | |||
| void main() { | |||
| float alpha = texture(uTexture, fragmentData.texCoords).r; | |||
| if (alpha <= 0.0) { | |||
| discard; | |||
| } | |||
| outColor = fragmentData.color * vec4(1.0, 1.0, 1.0, alpha); | |||
| } | |||
| @@ -0,0 +1,4 @@ | |||
| struct FragmentData { | |||
| vec2 texCoords; | |||
| vec4 color; | |||
| }; | |||
| @@ -0,0 +1,51 @@ | |||
| #version 450 core | |||
| #pragma include ./shared.glsl | |||
| #pragma include ../misc/camera.glsl | |||
| layout (location = 0) in vec2 inPosMin; | |||
| layout (location = 1) in vec2 inPosMax; | |||
| layout (location = 2) in vec2 inTexMin; | |||
| layout (location = 3) in vec2 inTexMax; | |||
| layout (location = 4) in vec4 inColor; | |||
| out FragmentData fragmentData; | |||
| void main() { | |||
| vec2 position = vec2(0.0); | |||
| vec2 texCoords = vec2(0.0); | |||
| switch (gl_VertexID) { | |||
| case 0: | |||
| position = vec2(inPosMin.x, inPosMax.y); | |||
| texCoords = vec2(inTexMin.x, inTexMax.y); | |||
| break; | |||
| case 1: | |||
| position = vec2(inPosMin.x, inPosMin.y); | |||
| texCoords = vec2(inTexMin.x, inTexMin.y); | |||
| break; | |||
| case 2: | |||
| position = vec2(inPosMax.x, inPosMax.y); | |||
| texCoords = vec2(inTexMax.x, inTexMax.y); | |||
| break; | |||
| case 3: | |||
| position = vec2(inPosMax.x, inPosMin.y); | |||
| texCoords = vec2(inTexMax.x, inTexMin.y); | |||
| break; | |||
| } | |||
| mat4 ortho = mat4( | |||
| vec4(2.0 / uCamera.size.x, 0.0, 0.0, 0.0), | |||
| vec4(0.0, -2.0 / uCamera.size.y, 0.0, 0.0), | |||
| vec4(0.0, 0.0, 1.0, 0.0), | |||
| vec4(-1.0, 1.0, 1.0, 1.0) | |||
| ); | |||
| gl_Position = ortho * vec4(position, 0.0, 1.0); | |||
| fragmentData.texCoords = texCoords; | |||
| fragmentData.color = inColor; | |||
| } | |||
| @@ -0,0 +1,2 @@ | |||
| pub const UNIFORM_BUFFER_INDEX_CAMERA: gl::GLuint = 0; | |||
| pub const UNIFORM_BUFFER_INDEX_UNIFORM: gl::GLuint = 1; | |||
| @@ -1,3 +1,4 @@ | |||
| mod constants; | |||
| mod error; | |||
| mod misc; | |||
| mod render; | |||
| @@ -46,8 +46,8 @@ impl TextManager { | |||
| pub fn new(world: &World) -> Result<Self, Error> { | |||
| let vfs = world.resource::<Vfs>()?.deref().clone(); | |||
| let program = world.load_program(vec![ | |||
| (Type::Vertex, "resources/shader/text.vert"), | |||
| (Type::Fragment, "resources/shader/text.frag"), | |||
| (Type::Vertex, "resources/shader/text/vert.glsl"), | |||
| (Type::Fragment, "resources/shader/text/frag.glsl"), | |||
| ])?; | |||
| let program = Rc::new(program); | |||
| @@ -1,6 +1,7 @@ | |||
| use std::iter::Iterator; | |||
| use glc::{ | |||
| error::Error as GlcError, | |||
| shader::{Program, Shader, Type}, | |||
| texture::{Data, FilterMag, FilterMin, Target, Texture, Wrap}, | |||
| }; | |||
| @@ -25,8 +26,33 @@ impl WorldHelper for World { | |||
| let vfs = self.fetch::<Vfs>(); | |||
| Program::from_shaders_result(iter.into_iter().map(|(t, p)| { | |||
| let mut file = vfs.join(p)?.open_file()?; | |||
| let shader = Shader::from_reader(t, &mut file)?; | |||
| 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) | |||
| })) | |||
| @@ -10,6 +10,7 @@ use space_crush_common::misc::WorldHelper as _; | |||
| use specs::{prelude::*, ReadExpect, System, World, WriteExpect}; | |||
| use crate::{ | |||
| constants::{UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||
| misc::{MouseEvent, WorldHelper}, | |||
| resources::{Camera, Config, Geometry, State, Uniform}, | |||
| Error, | |||
| @@ -24,12 +25,19 @@ pub struct Init { | |||
| impl Init { | |||
| pub fn new(world: &mut World) -> Result<Self, Error> { | |||
| let program = world.load_program(vec![ | |||
| (Type::Vertex, "resources/shader/noise.vert"), | |||
| (Type::Fragment, "resources/shader/noise.frag"), | |||
| (Type::Vertex, "resources/shader/noise/vert.glsl"), | |||
| (Type::Fragment, "resources/shader/noise/frag.glsl"), | |||
| ])?; | |||
| let resolution = (0, 0); | |||
| let mouse_event_id = world.register_event_reader::<MouseEvent>()?; | |||
| world | |||
| .resource::<Camera>()? | |||
| .bind(UNIFORM_BUFFER_INDEX_CAMERA)?; | |||
| world | |||
| .resource::<Uniform>()? | |||
| .bind(UNIFORM_BUFFER_INDEX_UNIFORM)?; | |||
| Ok(Self { | |||
| program, | |||
| resolution, | |||
| @@ -5,38 +5,49 @@ use glc::{ | |||
| texture::Texture, | |||
| vector::Vector4f, | |||
| }; | |||
| use space_crush_common::{ | |||
| components::{Planet, Position}, | |||
| misc::WorldHelper as _, | |||
| }; | |||
| use log::error; | |||
| use space_crush_common::components::{Planet, Position}; | |||
| use specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | |||
| use crate::{ | |||
| constants::{UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||
| misc::WorldHelper, | |||
| resources::{Camera, Geometry, Uniform as GlobalUniform}, | |||
| resources::Geometry, | |||
| Error, | |||
| }; | |||
| pub struct Planets { | |||
| program: Program, | |||
| texture: Texture, | |||
| model_location: gl::GLint, | |||
| } | |||
| impl Planets { | |||
| pub fn new(world: &World) -> Result<Self, Error> { | |||
| let program = world.load_program(vec![ | |||
| (Type::Vertex, "resources/shader/planet.vert"), | |||
| (Type::Fragment, "resources/shader/planet.frag"), | |||
| (Type::Vertex, "resources/shader/planet/vert.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 glow_color = Vector4f::new(1.0, 1.0, 1.0, 0.1); | |||
| let glow_color = Uniform::Vector4f(&glow_color); | |||
| let model_location = program.uniform_location("uModel")?; | |||
| program.bind(); | |||
| world.resource::<Camera>()?.bind(0)?; | |||
| world.resource::<GlobalUniform>()?.bind(2)?; | |||
| program.uniform(3, Uniform::Vector4f(&Vector4f::new(1.0, 1.0, 1.0, 0.1))); | |||
| program.uniform("uTexture", Uniform::Texture(0))?; | |||
| program.uniform("uGlowColor", glow_color)?; | |||
| program.unbind(); | |||
| let texture = world.load_texture("resources/textures/planet01.png")?; | |||
| Ok(Self { program, texture }) | |||
| Ok(Self { | |||
| program, | |||
| texture, | |||
| model_location, | |||
| }) | |||
| } | |||
| } | |||
| @@ -75,7 +86,12 @@ impl<'a> System<'a> for Planets { | |||
| Vector4f::new(x, y, 0.0, 1.0), | |||
| ); | |||
| self.program.uniform(1, Uniform::Matrix4f(&m)); | |||
| if let Err(err) = self | |||
| .program | |||
| .uniform(self.model_location, Uniform::Matrix4f(&m)) | |||
| { | |||
| error!("Error while updating model matrix: {}", err); | |||
| } | |||
| geometry.render_quad(); | |||
| } | |||