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