summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2023-11-02 20:22:33 +0100
committerHampusM <hampus@hampusmat.com>2023-11-02 20:22:33 +0100
commit9aafb51e0be1720019db1c3d0a294ce9a42653df (patch)
tree40881ff26bff5a928280223d8aced87e1370d63b
parentf2c54d47e6b61198520824117339aaa21c32accd (diff)
feat(engine): add texturing
-rw-r--r--Cargo.lock342
-rw-r--r--engine/Cargo.toml1
-rw-r--r--engine/fragment-color.glsl (renamed from engine/fragment.glsl)0
-rw-r--r--engine/fragment-texture.glsl11
-rw-r--r--engine/src/lib.rs1
-rw-r--r--engine/src/object.rs43
-rw-r--r--engine/src/opengl/mod.rs1
-rw-r--r--engine/src/opengl/texture.rs144
-rw-r--r--engine/src/renderer/mod.rs44
-rw-r--r--engine/src/texture.rs100
-rw-r--r--engine/src/vector.rs2
-rw-r--r--engine/src/vertex.rs26
-rw-r--r--engine/vertex.glsl3
13 files changed, 688 insertions, 30 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7010e6c..5e04147 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,6 +3,12 @@
version = 3
[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
name = "aho-corasick"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -12,12 +18,18 @@ dependencies = [
]
[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
name = "bindgen"
version = "0.68.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078"
dependencies = [
- "bitflags",
+ "bitflags 2.4.0",
"cexpr",
"clang-sys",
"lazy_static",
@@ -35,12 +47,36 @@ dependencies = [
]
[[package]]
+name = "bit_field"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
name = "bitflags"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
+name = "bytemuck"
+version = "1.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -76,6 +112,60 @@ dependencies = [
]
[[package]]
+name = "color_quant"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
+
+[[package]]
+name = "crc32fast"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
+dependencies = [
+ "cfg-if",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
+dependencies = [
+ "autocfg",
+ "cfg-if",
+ "crossbeam-utils",
+ "memoffset",
+ "scopeguard",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
name = "cstr"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -95,10 +185,11 @@ checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
name = "engine"
version = "0.1.0"
dependencies = [
- "bitflags",
+ "bitflags 2.4.0",
"cstr",
"gl",
"glfw",
+ "image",
"thiserror",
"tracing",
]
@@ -125,6 +216,50 @@ dependencies = [
]
[[package]]
+name = "exr"
+version = "1.71.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "832a761f35ab3e6664babfbdc6cef35a4860e816ec3916dcfd0882954e98a8a8"
+dependencies = [
+ "bit_field",
+ "flume",
+ "half",
+ "lebe",
+ "miniz_oxide",
+ "rayon-core",
+ "smallvec",
+ "zune-inflate",
+]
+
+[[package]]
+name = "fdeflate"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64d6dafc854908ff5da46ff3f8f473c6984119a2876a383a860246dd7841a868"
+dependencies = [
+ "simd-adler32",
+]
+
+[[package]]
+name = "flate2"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "flume"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
+dependencies = [
+ "spin",
+]
+
+[[package]]
name = "game-newest"
version = "0.1.0"
dependencies = [
@@ -134,6 +269,16 @@ dependencies = [
]
[[package]]
+name = "gif"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045"
+dependencies = [
+ "color_quant",
+ "weezl",
+]
+
+[[package]]
name = "gl"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -169,6 +314,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
+name = "half"
+version = "2.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0"
+dependencies = [
+ "crunchy",
+]
+
+[[package]]
name = "home"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -178,6 +332,34 @@ dependencies = [
]
[[package]]
+name = "image"
+version = "0.24.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711"
+dependencies = [
+ "bytemuck",
+ "byteorder",
+ "color_quant",
+ "exr",
+ "gif",
+ "jpeg-decoder",
+ "num-rational",
+ "num-traits",
+ "png",
+ "qoi",
+ "tiff",
+]
+
+[[package]]
+name = "jpeg-decoder"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e"
+dependencies = [
+ "rayon",
+]
+
+[[package]]
name = "khronos_api"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -196,6 +378,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
+name = "lebe"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
+
+[[package]]
name = "libc"
version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -218,6 +406,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db"
[[package]]
+name = "lock_api"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -230,12 +428,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
+name = "memoffset"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
name = "minimal-lexical"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
[[package]]
+name = "miniz_oxide"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+dependencies = [
+ "adler",
+ "simd-adler32",
+]
+
+[[package]]
name = "nom"
version = "7.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -256,6 +473,36 @@ dependencies = [
]
[[package]]
+name = "num-integer"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-rational"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -280,6 +527,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]]
+name = "png"
+version = "0.17.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64"
+dependencies = [
+ "bitflags 1.3.2",
+ "crc32fast",
+ "fdeflate",
+ "flate2",
+ "miniz_oxide",
+]
+
+[[package]]
name = "prettyplease"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -299,6 +559,15 @@ dependencies = [
]
[[package]]
+name = "qoi"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -308,6 +577,26 @@ dependencies = [
]
[[package]]
+name = "rayon"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
name = "regex"
version = "1.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -348,7 +637,7 @@ version = "0.38.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7"
dependencies = [
- "bitflags",
+ "bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys",
@@ -356,6 +645,12 @@ dependencies = [
]
[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
name = "sharded-slab"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -371,12 +666,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
[[package]]
+name = "simd-adler32"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
+
+[[package]]
name = "smallvec"
version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+dependencies = [
+ "lock_api",
+]
+
+[[package]]
name = "syn"
version = "2.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -418,6 +728,17 @@ dependencies = [
]
[[package]]
+name = "tiff"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211"
+dependencies = [
+ "flate2",
+ "jpeg-decoder",
+ "weezl",
+]
+
+[[package]]
name = "tracing"
version = "0.1.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -487,6 +808,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
+name = "weezl"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
+
+[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -591,3 +918,12 @@ name = "xml-rs"
version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
+
+[[package]]
+name = "zune-inflate"
+version = "0.2.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02"
+dependencies = [
+ "simd-adler32",
+]
diff --git a/engine/Cargo.toml b/engine/Cargo.toml
index 023c711..d3de446 100644
--- a/engine/Cargo.toml
+++ b/engine/Cargo.toml
@@ -13,3 +13,4 @@ gl = "0.14.0"
bitflags = "2.4.0"
cstr = "0.2.11"
tracing = { version = "0.1.39", optional = true }
+image = "0.24.7"
diff --git a/engine/fragment.glsl b/engine/fragment-color.glsl
index 8b209c4..8b209c4 100644
--- a/engine/fragment.glsl
+++ b/engine/fragment-color.glsl
diff --git a/engine/fragment-texture.glsl b/engine/fragment-texture.glsl
new file mode 100644
index 0000000..a4d378b
--- /dev/null
+++ b/engine/fragment-texture.glsl
@@ -0,0 +1,11 @@
+#version 330 core
+out vec4 FragColor;
+
+in vec2 in_texture_coords;
+
+uniform sampler2D input_texture;
+
+void main()
+{
+ FragColor = texture(input_texture, in_texture_coords);
+}
diff --git a/engine/src/lib.rs b/engine/src/lib.rs
index ec969f8..9f82b26 100644
--- a/engine/src/lib.rs
+++ b/engine/src/lib.rs
@@ -19,6 +19,7 @@ mod transform;
pub mod camera;
pub mod color;
pub mod object;
+pub mod texture;
pub mod vector;
pub mod vertex;
diff --git a/engine/src/object.rs b/engine/src/object.rs
index f2591f2..a8cd076 100644
--- a/engine/src/object.rs
+++ b/engine/src/object.rs
@@ -5,16 +5,21 @@ use crate::opengl::shader::{
Shader,
};
use crate::renderer::Renderable;
+use crate::texture::Texture;
use crate::transform::Transform;
use crate::vector::Vec3;
use crate::vertex::Vertex;
+const FRAG_SHADER_COLOR: &str = include_str!("../fragment-color.glsl");
+const FRAG_SHADER_TEXTURE: &str = include_str!("../fragment-texture.glsl");
+
#[derive(Debug)]
pub struct Object
{
id: Id,
renderable: Renderable,
transform: Transform,
+ texture: Option<Texture>,
}
impl Object
@@ -42,6 +47,12 @@ impl Object
self.transform.set_scaling(scaling);
}
+ #[must_use]
+ pub fn texture(&self) -> Option<&Texture>
+ {
+ self.texture.as_ref()
+ }
+
pub(crate) fn renderable(&self) -> &Renderable
{
&self.renderable
@@ -54,11 +65,12 @@ impl Object
}
/// Object builder.
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Default)]
pub struct Builder
{
vertices: Vec<Vertex>,
indices: Option<Vec<u32>>,
+ texture: Option<Texture>,
}
impl Builder
@@ -86,21 +98,35 @@ impl Builder
self
}
+ #[must_use]
+ pub fn texture(mut self, texture: Texture) -> Self
+ {
+ self.texture = Some(texture);
+
+ self
+ }
+
/// Builds a new [`Object`].
///
/// # Errors
/// Will return `Err` if:
/// - Creating shaders fails
/// - Linking the shader program fails
- pub fn build(&self, id: Id) -> Result<Object, Error>
+ pub fn build(self, id: Id) -> Result<Object, Error>
{
let vertex_shader =
Self::create_shader(ShaderKind::Vertex, include_str!("../vertex.glsl"))
.map_err(Error::CreateVertexShaderFailed)?;
- let fragment_shader =
- Self::create_shader(ShaderKind::Fragment, include_str!("../fragment.glsl"))
- .map_err(Error::CreateFragmentShaderFailed)?;
+ let fragment_shader = Self::create_shader(
+ ShaderKind::Fragment,
+ if self.texture.is_some() {
+ FRAG_SHADER_TEXTURE
+ } else {
+ FRAG_SHADER_COLOR
+ },
+ )
+ .map_err(Error::CreateFragmentShaderFailed)?;
let shader_program = ShaderProgram::new();
@@ -116,7 +142,12 @@ impl Builder
let transform = Transform::new();
- Ok(Object { id, renderable, transform })
+ Ok(Object {
+ id,
+ renderable,
+ transform,
+ texture: self.texture,
+ })
}
fn create_shader(kind: ShaderKind, source: &str) -> Result<Shader, ShaderError>
diff --git a/engine/src/opengl/mod.rs b/engine/src/opengl/mod.rs
index 4f4f96f..d58ca50 100644
--- a/engine/src/opengl/mod.rs
+++ b/engine/src/opengl/mod.rs
@@ -6,6 +6,7 @@ use crate::vector::Vec2;
pub mod buffer;
pub mod currently_bound;
pub mod shader;
+pub mod texture;
pub mod vertex_array;
mod util;
diff --git a/engine/src/opengl/texture.rs b/engine/src/opengl/texture.rs
new file mode 100644
index 0000000..c7bf75b
--- /dev/null
+++ b/engine/src/opengl/texture.rs
@@ -0,0 +1,144 @@
+use crate::opengl::currently_bound::CurrentlyBound;
+use crate::vector::Vec2;
+
+#[derive(Debug)]
+pub struct Texture
+{
+ texture: gl::types::GLuint,
+}
+
+impl Texture
+{
+ pub fn new() -> Self
+ {
+ let mut texture = gl::types::GLuint::default();
+
+ unsafe {
+ gl::GenTextures(1, &mut texture);
+ };
+
+ Self { texture }
+ }
+
+ pub fn bind(&self, cb: impl FnOnce(CurrentlyBound<'_, Self>))
+ {
+ unsafe {
+ gl::BindTexture(gl::TEXTURE_2D, self.texture);
+ }
+
+ // SAFETY: The buffer object is bound above
+ let currently_bound = unsafe { CurrentlyBound::new() };
+
+ cb(currently_bound);
+ }
+
+ pub fn generate(_: &CurrentlyBound<Self>, dimens: &Vec2<u32>, data: &[u8])
+ {
+ #[allow(clippy::cast_possible_wrap)]
+ unsafe {
+ gl::TexImage2D(
+ gl::TEXTURE_2D,
+ 0,
+ gl::RGB as i32,
+ dimens.x as i32,
+ dimens.y as i32,
+ 0,
+ gl::RGB,
+ gl::UNSIGNED_BYTE,
+ data.as_ptr().cast(),
+ );
+
+ gl::GenerateMipmap(gl::TEXTURE_2D);
+ }
+ }
+
+ pub fn set_wrap(_: CurrentlyBound<Self>, wrapping: Wrapping)
+ {
+ let wrapping_gl = wrapping.to_gl();
+
+ #[allow(clippy::cast_possible_wrap)]
+ unsafe {
+ gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, wrapping_gl as i32);
+ gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, wrapping_gl as i32);
+ }
+ }
+
+ pub fn set_magnifying_filter(_: CurrentlyBound<Self>, filtering: Filtering)
+ {
+ let filtering_gl = filtering.to_gl();
+
+ #[allow(clippy::cast_possible_wrap)]
+ unsafe {
+ gl::TexParameteri(
+ gl::TEXTURE_2D,
+ gl::TEXTURE_MAG_FILTER,
+ filtering_gl as i32,
+ );
+ }
+ }
+
+ pub fn set_minifying_filter(_: CurrentlyBound<Self>, filtering: Filtering)
+ {
+ let filtering_gl = filtering.to_gl();
+
+ #[allow(clippy::cast_possible_wrap)]
+ unsafe {
+ gl::TexParameteri(
+ gl::TEXTURE_2D,
+ gl::TEXTURE_MIN_FILTER,
+ filtering_gl as i32,
+ );
+ }
+ }
+}
+
+impl Drop for Texture
+{
+ fn drop(&mut self)
+ {
+ unsafe {
+ gl::DeleteTextures(1, &self.texture);
+ }
+ }
+}
+
+/// Texture wrapping.
+#[derive(Debug, Clone, Copy)]
+pub enum Wrapping
+{
+ Repeat,
+ MirroredRepeat,
+ ClampToEdge,
+ ClampToBorder,
+}
+
+impl Wrapping
+{
+ fn to_gl(self) -> gl::types::GLenum
+ {
+ match self {
+ Self::Repeat => gl::REPEAT,
+ Self::MirroredRepeat => gl::MIRRORED_REPEAT,
+ Self::ClampToEdge => gl::CLAMP_TO_EDGE,
+ Self::ClampToBorder => gl::CLAMP_TO_BORDER,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum Filtering
+{
+ Nearest,
+ Linear,
+}
+
+impl Filtering
+{
+ fn to_gl(self) -> gl::types::GLenum
+ {
+ match self {
+ Self::Linear => gl::LINEAR,
+ Self::Nearest => gl::NEAREST,
+ }
+ }
+}
diff --git a/engine/src/renderer/mod.rs b/engine/src/renderer/mod.rs
index 6c56964..3691f76 100644
--- a/engine/src/renderer/mod.rs
+++ b/engine/src/renderer/mod.rs
@@ -116,23 +116,33 @@ pub fn render<'obj>(
apply_transformation_matrices(obj, camera, window_size);
- obj.renderable().vertex_arr.bind(|vert_arr_curr_bound| {
- if let Some(index_info) = &obj.renderable().index_info {
- VertexArray::draw_elements(
- &vert_arr_curr_bound,
- PrimitiveKind::Triangles,
- 0,
- index_info.cnt,
- );
- } else {
- VertexArray::draw_arrays(
- &vert_arr_curr_bound,
- PrimitiveKind::Triangles,
- 0,
- 3,
- );
- }
- });
+ let draw = || {
+ obj.renderable().vertex_arr.bind(|vert_arr_curr_bound| {
+ if let Some(index_info) = &obj.renderable().index_info {
+ VertexArray::draw_elements(
+ &vert_arr_curr_bound,
+ PrimitiveKind::Triangles,
+ 0,
+ index_info.cnt,
+ );
+ } else {
+ VertexArray::draw_arrays(
+ &vert_arr_curr_bound,
+ PrimitiveKind::Triangles,
+ 0,
+ 3,
+ );
+ }
+ });
+ };
+
+ if let Some(texture) = obj.texture() {
+ texture.inner().bind(|_| {
+ draw();
+ });
+ } else {
+ draw();
+ }
}
}
diff --git a/engine/src/texture.rs b/engine/src/texture.rs
new file mode 100644
index 0000000..7874df4
--- /dev/null
+++ b/engine/src/texture.rs
@@ -0,0 +1,100 @@
+use std::path::Path;
+
+use image::io::Reader as ImageReader;
+use image::{DynamicImage, ImageError};
+
+use crate::opengl::texture::Texture as InnerTexture;
+use crate::vector::Vec2;
+
+mod reexports
+{
+ pub use crate::opengl::texture::{Filtering, Wrapping};
+}
+
+pub use reexports::*;
+
+#[derive(Debug)]
+pub struct Texture
+{
+ inner: InnerTexture,
+}
+
+impl Texture
+{
+ /// Opens a texture image.
+ ///
+ /// # Errors
+ /// Will return `Err` if:
+ /// - Opening the image fails
+ /// - The image data is not 8-bit/color RGB
+ #[allow(clippy::new_without_default)]
+ pub fn open(path: &Path) -> Result<Self, Error>
+ {
+ let image = ImageReader::open(path)
+ .map_err(Error::OpenImageFailed)?
+ .decode()
+ .map_err(Error::DecodeImageFailed)?;
+
+ if !matches!(image, DynamicImage::ImageRgb8(_)) {
+ return Err(Error::UnsupportedImageDataKind);
+ }
+
+ let inner = InnerTexture::new();
+
+ inner.bind(|texture_curr_bound| {
+ InnerTexture::generate(
+ &texture_curr_bound,
+ &Vec2 { x: image.width(), y: image.height() },
+ image.as_bytes(),
+ );
+ });
+
+ let me = Self { inner };
+
+ me.set_wrap(Wrapping::Repeat);
+ me.set_magnifying_filter(Filtering::Linear);
+ me.set_minifying_filter(Filtering::Nearest);
+
+ Ok(me)
+ }
+
+ pub fn set_wrap(&self, wrapping: Wrapping)
+ {
+ self.inner.bind(|texture_curr_bound| {
+ InnerTexture::set_wrap(texture_curr_bound, wrapping);
+ });
+ }
+
+ pub fn set_magnifying_filter(&self, filtering: Filtering)
+ {
+ self.inner.bind(|texture_curr_bound| {
+ InnerTexture::set_magnifying_filter(texture_curr_bound, filtering);
+ });
+ }
+
+ pub fn set_minifying_filter(&self, filtering: Filtering)
+ {
+ self.inner.bind(|texture_curr_bound| {
+ InnerTexture::set_minifying_filter(texture_curr_bound, filtering);
+ });
+ }
+
+ pub(crate) fn inner(&self) -> &InnerTexture
+ {
+ &self.inner
+ }
+}
+
+/// Texture error.
+#[derive(Debug, thiserror::Error)]
+pub enum Error
+{
+ #[error("Failed to open texture image")]
+ OpenImageFailed(#[source] std::io::Error),
+
+ #[error("Failed to decode texture image")]
+ DecodeImageFailed(#[source] ImageError),
+
+ #[error("Unsupported image data kind")]
+ UnsupportedImageDataKind,
+}
diff --git a/engine/src/vector.rs b/engine/src/vector.rs
index e5947d5..00d6a6f 100644
--- a/engine/src/vector.rs
+++ b/engine/src/vector.rs
@@ -1,6 +1,6 @@
use std::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign};
-#[derive(Debug)]
+#[derive(Debug, Default, Clone)]
pub struct Vec2<Value>
{
pub x: Value,
diff --git a/engine/src/vertex.rs b/engine/src/vertex.rs
index 62f629b..9df646f 100644
--- a/engine/src/vertex.rs
+++ b/engine/src/vertex.rs
@@ -1,7 +1,7 @@
use std::mem::size_of;
use crate::color::Color;
-use crate::vector::Vec3;
+use crate::vector::{Vec2, Vec3};
#[derive(Debug, Clone, Default)]
#[repr(C)]
@@ -9,6 +9,7 @@ pub struct Vertex
{
pos: Vec3<f32>,
color: Color<f32>,
+ texture_coords: Vec2<f32>,
}
#[derive(Debug, Default)]
@@ -16,6 +17,7 @@ pub struct Builder
{
pos: Option<Vec3<f32>>,
color: Option<Color<f32>>,
+ texture_coords: Vec2<f32>,
}
impl Builder
@@ -23,7 +25,7 @@ impl Builder
#[must_use]
pub fn new() -> Self
{
- Self { pos: None, color: None }
+ Self::default()
}
#[must_use]
@@ -43,12 +45,24 @@ impl Builder
}
#[must_use]
+ pub fn texture_coords(mut self, texture_coords: Vec2<f32>) -> Self
+ {
+ self.texture_coords = texture_coords;
+
+ self
+ }
+
+ #[must_use]
pub fn build(self) -> Option<Vertex>
{
let pos = self.pos?;
let color = self.color?;
- Some(Vertex { pos, color })
+ Some(Vertex {
+ pos,
+ color,
+ texture_coords: self.texture_coords,
+ })
}
}
@@ -69,6 +83,12 @@ impl Vertex
component_cnt: AttributeComponentCnt::Three,
component_size: size_of::<f32>(),
},
+ Attribute {
+ index: 2,
+ component_type: AttributeComponentType::Float,
+ component_cnt: AttributeComponentCnt::Two,
+ component_size: size_of::<f32>(),
+ },
]
}
}
diff --git a/engine/vertex.glsl b/engine/vertex.glsl
index b0a2a13..61782c2 100644
--- a/engine/vertex.glsl
+++ b/engine/vertex.glsl
@@ -1,8 +1,10 @@
#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec3 color;
+layout (location = 2) in vec2 texture_coords;
out vec3 in_frag_color;
+out vec2 in_texture_coords;
uniform mat4 model;
uniform mat4 view;
@@ -13,4 +15,5 @@ void main()
gl_Position = projection * view * model * vec4(pos, 1.0);
in_frag_color = color;
+ in_texture_coords = texture_coords;
}