summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/teleia/src/assets/meshes/cube.obj38
-rw-r--r--crates/teleia/src/assets/shaders/skybox/frag.glsl8
-rw-r--r--crates/teleia/src/assets/shaders/skybox/vert.glsl7
-rw-r--r--crates/teleia/src/renderer.rs29
-rw-r--r--crates/teleia/src/state.rs10
-rw-r--r--crates/teleia/src/texture.rs58
6 files changed, 139 insertions, 11 deletions
diff --git a/crates/teleia/src/assets/meshes/cube.obj b/crates/teleia/src/assets/meshes/cube.obj
new file mode 100644
index 0000000..2f3a670
--- /dev/null
+++ b/crates/teleia/src/assets/meshes/cube.obj
@@ -0,0 +1,38 @@
+# Blender 4.1.1
+# www.blender.org
+o Cube
+v 1.000000 1.000000 -1.000000
+v 1.000000 -1.000000 -1.000000
+v 1.000000 1.000000 1.000000
+v 1.000000 -1.000000 1.000000
+v -1.000000 1.000000 -1.000000
+v -1.000000 -1.000000 -1.000000
+v -1.000000 1.000000 1.000000
+v -1.000000 -1.000000 1.000000
+vn -0.0000 1.0000 -0.0000
+vn -0.0000 -0.0000 1.0000
+vn -1.0000 -0.0000 -0.0000
+vn -0.0000 -1.0000 -0.0000
+vn 1.0000 -0.0000 -0.0000
+vn -0.0000 -0.0000 -1.0000
+vt 0.625000 0.500000
+vt 0.875000 0.500000
+vt 0.875000 0.750000
+vt 0.625000 0.750000
+vt 0.375000 0.750000
+vt 0.625000 1.000000
+vt 0.375000 1.000000
+vt 0.375000 0.000000
+vt 0.625000 0.000000
+vt 0.625000 0.250000
+vt 0.375000 0.250000
+vt 0.125000 0.500000
+vt 0.375000 0.500000
+vt 0.125000 0.750000
+s 0
+f 1/1/1 5/2/1 7/3/1 3/4/1
+f 4/5/2 3/4/2 7/6/2 8/7/2
+f 8/8/3 7/9/3 5/10/3 6/11/3
+f 6/12/4 2/13/4 4/5/4 8/14/4
+f 2/13/5 1/1/5 3/4/5 4/5/5
+f 6/11/6 5/10/6 1/1/6 2/13/6
diff --git a/crates/teleia/src/assets/shaders/skybox/frag.glsl b/crates/teleia/src/assets/shaders/skybox/frag.glsl
new file mode 100644
index 0000000..27efd37
--- /dev/null
+++ b/crates/teleia/src/assets/shaders/skybox/frag.glsl
@@ -0,0 +1,8 @@
+uniform samplerCube skybox;
+
+in vec3 vertex_texcoord_3d;
+
+void main() {
+ vec3 v = vec3(vertex_texcoord_3d.x, -vertex_texcoord_3d.z, vertex_texcoord_3d.y);
+ frag_color = texture(skybox, v);
+}
diff --git a/crates/teleia/src/assets/shaders/skybox/vert.glsl b/crates/teleia/src/assets/shaders/skybox/vert.glsl
new file mode 100644
index 0000000..3a6d881
--- /dev/null
+++ b/crates/teleia/src/assets/shaders/skybox/vert.glsl
@@ -0,0 +1,7 @@
+out vec3 vertex_texcoord_3d;
+
+void main() {
+ vertex_texcoord_3d = vertex;
+ vec4 pos = projection * view * vec4(vertex, 1.0);
+ gl_Position = pos.xyww;
+}
diff --git a/crates/teleia/src/renderer.rs b/crates/teleia/src/renderer.rs
index 7384f0d..dd0ffd0 100644
--- a/crates/teleia/src/renderer.rs
+++ b/crates/teleia/src/renderer.rs
@@ -49,13 +49,19 @@ pub trait Assets {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ShaderMode { TwoDimension, ThreeDimension, ThreeDimensionOrth }
#[derive(Debug, Clone, Copy)]
-enum BoundShader<A: Assets> { None, Uber(UberFlags, ShaderMode), Shader(A::Shader, ShaderMode) }
+enum BoundShader<A: Assets> {
+ None,
+ Uber(UberFlags, ShaderMode),
+ Shader(A::Shader, ShaderMode),
+ Skybox,
+}
impl<A: Assets> PartialEq for BoundShader<A> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::None, Self::None) => true,
(Self::Uber(sf, sm), Self::Uber(of, om)) => sf == of && sm == om,
(Self::Shader(ss, sm), Self::Shader(os, om)) => ss == os && sm == om,
+ (Self::Skybox, Self::Skybox) => true,
_ => false,
}
}
@@ -298,12 +304,23 @@ impl<A: Assets> Renderer<A> {
pub fn bind_shader_3d(&mut self, ctx: &context::Context, st: &mut state::State, shader: A::Shader) {
self.bind_shader(ctx, st, shader, ShaderMode::ThreeDimension);
}
+ pub fn bind_shader_skybox(&mut self, ctx: &context::Context, st: &mut state::State) {
+ if BoundShader::Skybox == self.shader { return }
+ let view = glam::Mat4::from_mat3(glam::Mat3::from_mat4(st.view()));
+ st.shader_skybox.bind(ctx);
+ st.shader_skybox.set_mat4(ctx, "projection", &st.projection);
+ st.shader_skybox.set_mat4(ctx, "view", &view);
+ self.shader = BoundShader::Skybox;
+ }
pub fn render(&self, ctx: &context::Context, _st: &state::State, mesh: A::Mesh) {
self.assets.mesh(mesh).render(ctx)
}
pub fn render_square(&self, ctx: &context::Context, st: &state::State) {
st.mesh_square.render(ctx)
}
+ pub fn render_cube(&self, ctx: &context::Context, st: &state::State) {
+ st.mesh_cube.render(ctx)
+ }
pub fn set_position_2d_mat(&self, ctx: &context::Context, st: &state::State, pos: glam::Mat4) {
if let Some((s, sm)) = self.shader() {
debug_assert!(sm == ShaderMode::TwoDimension, "attempted to set_position_2d in wrong mode");
@@ -445,4 +462,14 @@ impl<A: Assets> Renderer<A> {
offset: None,
}
}
+
+ /// Common case: draw a cubemap as a skybox
+ pub fn skybox(&mut self,
+ ctx: &context::Context, st: &mut state::State,
+ skybox: &texture::Cubemap,
+ ) {
+ self.bind_shader_skybox(ctx, st);
+ skybox.bind(ctx);
+ self.render_cube(ctx, st);
+ }
}
diff --git a/crates/teleia/src/state.rs b/crates/teleia/src/state.rs
index d4c9742..0f202ee 100644
--- a/crates/teleia/src/state.rs
+++ b/crates/teleia/src/state.rs
@@ -164,7 +164,9 @@ pub struct State {
pub render_dims: glam::Vec2,
pub postprocessing: postprocessing::Pipeline,
pub shader_text_bitmap: shader::Shader,
+ pub shader_skybox: shader::Shader,
pub mesh_square: mesh::Mesh,
+ pub mesh_cube: mesh::Mesh,
pub font_default: font::Bitmap,
pub font_small: font::Bitmap,
pub audio: Option<audio::Assets>,
@@ -239,7 +241,13 @@ impl State {
include_str!("assets/shaders/bitmap/vert.glsl"),
include_str!("assets/shaders/bitmap/frag.glsl"),
);
+ let shader_skybox = shader::Shader::new(
+ ctx,
+ include_str!("assets/shaders/skybox/vert.glsl"),
+ include_str!("assets/shaders/skybox/frag.glsl"),
+ );
let mesh_square = mesh::Mesh::from_obj(ctx, include_bytes!("assets/meshes/square.obj"));
+ let mesh_cube = mesh::Mesh::from_obj(ctx, include_bytes!("assets/meshes/cube.obj"));
let nextframe = now(ctx);
@@ -262,7 +270,9 @@ impl State {
render_dims: glam::Vec2::new(ctx.render_width, ctx.render_height),
postprocessing: postprocessing::Pipeline::new(ctx),
shader_text_bitmap,
+ shader_skybox,
mesh_square,
+ mesh_cube,
font_default: font::Bitmap::default(ctx),
font_small: font::Bitmap::small(ctx),
audio: None,
diff --git a/crates/teleia/src/texture.rs b/crates/teleia/src/texture.rs
index e20ae05..71a39d8 100644
--- a/crates/teleia/src/texture.rs
+++ b/crates/teleia/src/texture.rs
@@ -8,7 +8,6 @@ pub struct Texture {
pub width: i32,
pub height: i32,
}
-
impl Texture {
pub fn new_empty(ctx: &context::Context) -> Self {
unsafe {
@@ -24,7 +23,6 @@ impl Texture {
}
}
}
-
pub fn new(ctx: &context::Context, bytes: &[u8]) -> Self {
let rgba = image::ImageReader::new(std::io::Cursor::new(bytes))
.with_guessed_format()
@@ -52,7 +50,6 @@ impl Texture {
Some(pixels),
);
ctx.gl.generate_mipmap(glow::TEXTURE_2D);
-
Self {
tex,
width: rgba.width() as i32,
@@ -60,7 +57,6 @@ impl Texture {
}
}
}
-
pub fn upload(&mut self, ctx: &context::Context, bytes: &[u8]) {
let rgba = image::ImageReader::new(std::io::Cursor::new(bytes))
.with_guessed_format()
@@ -71,7 +67,6 @@ impl Texture {
let pixels = rgba.as_bytes();
self.upload_rgba8(ctx, rgba.width() as i32, rgba.height() as i32, pixels);
}
-
pub fn upload_rgba8(&mut self, ctx: &context::Context, width: i32, height: i32, data: &[u8]) {
unsafe {
ctx.gl.bind_texture(glow::TEXTURE_2D, Some(self.tex));
@@ -95,7 +90,6 @@ impl Texture {
self.width = width;
self.height = height;
}
-
pub fn set_repeat(&self, ctx: &context::Context) {
unsafe {
ctx.gl.bind_texture(glow::TEXTURE_2D, Some(self.tex));
@@ -103,7 +97,6 @@ impl Texture {
ctx.gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::REPEAT as i32);
}
}
-
pub fn set_anisotropic_filtering(&self, ctx: &context::Context) {
unsafe {
ctx.gl.bind_texture(glow::TEXTURE_2D, Some(self.tex));
@@ -114,21 +107,18 @@ impl Texture {
ctx.gl.tex_parameter_f32(glow::TEXTURE_2D, glow::TEXTURE_MAX_ANISOTROPY_EXT, 4.0);
}
}
-
pub fn bind(&self, ctx: &context::Context) {
unsafe {
ctx.gl.active_texture(glow::TEXTURE0);
ctx.gl.bind_texture(glow::TEXTURE_2D, Some(self.tex));
}
}
-
pub fn bind_initial(ctx: &context::Context) {
unsafe {
ctx.gl.active_texture(glow::TEXTURE0);
ctx.gl.bind_texture(glow::TEXTURE_2D, None);
}
}
-
pub fn bind_index(&self, ctx: &context::Context, idx: u32) {
unsafe {
ctx.gl.active_texture(glow::TEXTURE0 + idx);
@@ -154,3 +144,51 @@ impl Material {
self.normal.bind_index(ctx, 1);
}
}
+
+pub struct Cubemap {
+ pub tex: glow::Texture,
+}
+impl Cubemap {
+ // expects an iterator of side image bytes in this order:
+ // right, left, top, bottom, front, back
+ pub fn new<'a>(ctx: &context::Context, sides: impl IntoIterator<Item = &'a [u8]>) -> Self {
+ unsafe {
+ let tex = ctx.gl.create_texture().expect("failed to create texture");
+ ctx.gl.bind_texture(glow::TEXTURE_CUBE_MAP, Some(tex));
+ ctx.gl.tex_parameter_i32(glow::TEXTURE_CUBE_MAP, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32);
+ ctx.gl.tex_parameter_i32(glow::TEXTURE_CUBE_MAP, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32);
+ ctx.gl.tex_parameter_i32(glow::TEXTURE_CUBE_MAP, glow::TEXTURE_WRAP_R, glow::CLAMP_TO_EDGE as i32);
+ ctx.gl.tex_parameter_i32(glow::TEXTURE_CUBE_MAP, glow::TEXTURE_MIN_FILTER, glow::LINEAR as i32);
+ ctx.gl.tex_parameter_i32(glow::TEXTURE_CUBE_MAP, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32);
+ for (i, bytes) in sides.into_iter().enumerate() {
+ let rgba = image::ImageReader::new(std::io::Cursor::new(bytes))
+ .with_guessed_format()
+ .expect("failed to guess image format")
+ .decode()
+ .expect("failed to decode image")
+ .into_rgba8();
+ let pixels = rgba.as_bytes();
+ ctx.gl.tex_image_2d(
+ glow::TEXTURE_CUBE_MAP_POSITIVE_X + i as u32,
+ 0,
+ glow::RGBA as i32,
+ rgba.width() as i32,
+ rgba.height() as i32,
+ 0,
+ glow::RGBA,
+ glow::UNSIGNED_BYTE,
+ Some(pixels),
+ );
+ }
+ Self {
+ tex,
+ }
+ }
+ }
+ pub fn bind(&self, ctx: &context::Context) {
+ unsafe {
+ ctx.gl.active_texture(glow::TEXTURE0);
+ ctx.gl.bind_texture(glow::TEXTURE_CUBE_MAP, Some(self.tex));
+ }
+ }
+}