| @@ -1,3 +1,4 @@ | |||||
| use std::ffi::NulError; | |||||
| use std::io::Error as IoError; | use std::io::Error as IoError; | ||||
| use std::str::Utf8Error; | use std::str::Utf8Error; | ||||
| @@ -12,6 +13,9 @@ pub enum Error { | |||||
| #[error("UTF-8 Error: {0}")] | #[error("UTF-8 Error: {0}")] | ||||
| Utf8Error(Utf8Error), | Utf8Error(Utf8Error), | ||||
| #[error("FFI Error: {0}")] | |||||
| NulError(NulError), | |||||
| #[error("Image Format Error: {0}")] | #[error("Image Format Error: {0}")] | ||||
| ImageFmtError(ImageFmtError), | ImageFmtError(ImageFmtError), | ||||
| @@ -24,6 +28,12 @@ pub enum Error { | |||||
| #[error("Error while linking shader program: {0}")] | #[error("Error while linking shader program: {0}")] | ||||
| ShaderLink(String), | 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}!")] | #[error("Vertex Array: Index is already in use: {0}!")] | ||||
| VertexArrayIndexAlreadyInUse(gl::GLuint), | 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 { | impl From<ImageFmtError> for Error { | ||||
| fn from(err: ImageFmtError) -> Self { | fn from(err: ImageFmtError) -> Self { | ||||
| Self::ImageFmtError(err) | Self::ImageFmtError(err) | ||||
| @@ -1,3 +1,4 @@ | |||||
| use std::ffi::CString; | |||||
| use std::fs::File; | use std::fs::File; | ||||
| use std::io::Read; | use std::io::Read; | ||||
| use std::path::Path; | use std::path::Path; | ||||
| @@ -74,11 +75,60 @@ impl Program { | |||||
| self.id | 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 { | match uniform { | ||||
| Uniform::Matrix4f(v) => gl::uniform_matrix_4fv(location, 1, gl::FALSE, v.as_ptr()), | 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::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 { | 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 = gl::create_shader(type_.as_enum()); | ||||
| let id = Error::err_if(&0, id)?; | 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); | gl::compile_shader(id); | ||||
| let mut success = 1; | let mut success = 1; | ||||
| @@ -134,9 +195,15 @@ impl Shader { | |||||
| ); | ); | ||||
| let msg = from_utf8(&buffer)?; | 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 { | return Err(Error::ShaderCompile { | ||||
| code: source, | |||||
| code, | |||||
| error: msg.into(), | error: msg.into(), | ||||
| }); | }); | ||||
| } | } | ||||
| @@ -144,23 +211,25 @@ impl Shader { | |||||
| Ok(Self { id }) | 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 | where | ||||
| R: Read, | R: Read, | ||||
| F: Fn(&str) -> Result<String, Error>, | |||||
| { | { | ||||
| let mut source = String::new(); | let mut source = String::new(); | ||||
| reader.read_to_string(&mut source)?; | 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 | where | ||||
| P: AsRef<Path>, | P: AsRef<Path>, | ||||
| F: Fn(&str) -> Result<String, Error>, | |||||
| { | { | ||||
| let mut file = File::open(&path)?; | 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), | Ok(v) => Ok(v), | ||||
| Err(Error::ShaderCompile { code, error }) => Err(Error::ShaderCompile { | Err(Error::ShaderCompile { code, error }) => Err(Error::ShaderCompile { | ||||
| code: format!("{}\n{}", path.as_ref().display(), code), | code: format!("{}\n{}", path.as_ref().display(), code), | ||||
| @@ -211,4 +280,53 @@ impl AsEnum for Type { | |||||
| pub enum Uniform<'a> { | pub enum Uniform<'a> { | ||||
| Matrix4f(&'a Matrix4f), | Matrix4f(&'a Matrix4f), | ||||
| Vector4f(&'a Vector4f), | 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 | #version 450 core | ||||
| out vec4 color; | |||||
| out vec4 outColor; | |||||
| const float NOISE_RANGE = 0.05; | const float NOISE_RANGE = 0.05; | ||||
| const float NOISE_BASE = 0.05; | const float NOISE_BASE = 0.05; | ||||
| @@ -13,5 +13,5 @@ void main() { | |||||
| float rnd = random(gl_FragCoord); | float rnd = random(gl_FragCoord); | ||||
| vec3 rgb = vec3(NOISE_BASE + NOISE_RANGE * rnd); | 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 error; | ||||
| mod misc; | mod misc; | ||||
| mod render; | mod render; | ||||
| @@ -46,8 +46,8 @@ impl TextManager { | |||||
| pub fn new(world: &World) -> Result<Self, Error> { | pub fn new(world: &World) -> Result<Self, Error> { | ||||
| let vfs = world.resource::<Vfs>()?.deref().clone(); | let vfs = world.resource::<Vfs>()?.deref().clone(); | ||||
| let program = world.load_program(vec![ | 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); | let program = Rc::new(program); | ||||
| @@ -1,6 +1,7 @@ | |||||
| use std::iter::Iterator; | use std::iter::Iterator; | ||||
| use glc::{ | use glc::{ | ||||
| error::Error as GlcError, | |||||
| shader::{Program, Shader, Type}, | shader::{Program, Shader, Type}, | ||||
| texture::{Data, FilterMag, FilterMin, Target, Texture, Wrap}, | texture::{Data, FilterMag, FilterMin, Target, Texture, Wrap}, | ||||
| }; | }; | ||||
| @@ -25,8 +26,33 @@ impl WorldHelper for World { | |||||
| let vfs = self.fetch::<Vfs>(); | let vfs = self.fetch::<Vfs>(); | ||||
| Program::from_shaders_result(iter.into_iter().map(|(t, p)| { | 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) | Ok(shader) | ||||
| })) | })) | ||||
| @@ -10,6 +10,7 @@ use space_crush_common::misc::WorldHelper as _; | |||||
| use specs::{prelude::*, ReadExpect, System, World, WriteExpect}; | use specs::{prelude::*, ReadExpect, System, World, WriteExpect}; | ||||
| use crate::{ | use crate::{ | ||||
| constants::{UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||||
| misc::{MouseEvent, WorldHelper}, | misc::{MouseEvent, WorldHelper}, | ||||
| resources::{Camera, Config, Geometry, State, Uniform}, | resources::{Camera, Config, Geometry, State, Uniform}, | ||||
| Error, | Error, | ||||
| @@ -24,12 +25,19 @@ pub struct Init { | |||||
| impl Init { | impl Init { | ||||
| pub fn new(world: &mut World) -> Result<Self, Error> { | pub fn new(world: &mut World) -> Result<Self, Error> { | ||||
| let program = world.load_program(vec![ | 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 resolution = (0, 0); | ||||
| let mouse_event_id = world.register_event_reader::<MouseEvent>()?; | 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 { | Ok(Self { | ||||
| program, | program, | ||||
| resolution, | resolution, | ||||
| @@ -5,38 +5,49 @@ use glc::{ | |||||
| texture::Texture, | texture::Texture, | ||||
| vector::Vector4f, | 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 specs::{prelude::*, ReadExpect, ReadStorage, System, World}; | ||||
| use crate::{ | use crate::{ | ||||
| constants::{UNIFORM_BUFFER_INDEX_CAMERA, UNIFORM_BUFFER_INDEX_UNIFORM}, | |||||
| misc::WorldHelper, | misc::WorldHelper, | ||||
| resources::{Camera, Geometry, Uniform as GlobalUniform}, | |||||
| resources::Geometry, | |||||
| Error, | Error, | ||||
| }; | }; | ||||
| pub struct Planets { | pub struct Planets { | ||||
| program: Program, | program: Program, | ||||
| texture: Texture, | texture: Texture, | ||||
| model_location: gl::GLint, | |||||
| } | } | ||||
| impl Planets { | impl Planets { | ||||
| pub fn new(world: &World) -> Result<Self, Error> { | pub fn new(world: &World) -> Result<Self, Error> { | ||||
| let program = world.load_program(vec![ | 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(); | 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(); | program.unbind(); | ||||
| let texture = world.load_texture("resources/textures/planet01.png")?; | 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), | 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(); | geometry.render_quad(); | ||||
| } | } | ||||