Verified Commit 09c3c1be authored by insert's avatar insert

Add resources, atlas and collisions.

parent b70a862b
......@@ -348,6 +348,11 @@ dependencies = [
"adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "itoa"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "jpeg-decoder"
version = "0.1.18"
......@@ -825,6 +830,11 @@ dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ryu"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "scoped_threadpool"
version = "0.1.9"
......@@ -874,6 +884,34 @@ name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.15.44"
......@@ -961,6 +999,8 @@ dependencies = [
"engine 0.1.0 (git+https://gitlab.insrt.uk/insert/engine-rs)",
"hashbrown 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"noise 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
......@@ -1042,6 +1082,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum image 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4be8aaefbe7545dc42ae925afb55a0098f226a3fe5ef721872806f44f57826"
"checksum inflate 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f5f9f47468e9a76a6452271efadc88fe865a82be91fe75e6c0c57b87ccea59d4"
"checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum jpeg-decoder 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0256f0aec7352539102a9efbcb75543227b7ab1117e0f95450023af730128451"
"checksum khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
......@@ -1097,12 +1138,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
"checksum sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d051a07231e303f5f719da78cb6f7394f6d5b54f733aef5b0b447804a83edd7b"
"checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7"
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
"checksum tar 0.4.26 (registry+https://github.com/rust-lang/crates.io-index)" = "b3196bfbffbba3e57481b6ea32249fbaf590396a52505a2615adbb79d9d826d3"
......
......@@ -10,3 +10,5 @@ edition = "2018"
engine = { git = "https://gitlab.insrt.uk/insert/engine-rs" }
hashbrown = "0.6.3"
noise = "0.6.0"
serde = { version = "1.0.104", features = ["derive"] }
serde_json = "1.0.44"
mod resources;
mod registry;
mod physics;
mod world;
mod game;
use registry::GameRegistry;
use resources::{ pack::ResourcePack, atlas::AtlasGenerator };
use world::{ ChunkLocation, World };
use engine::{ native, render, mesh };
use engine::{ native, render, glm };
use hashbrown::HashSet;
use std::time::Instant;
fn main() {
let sdl = native::SDL::init();
let window = native::Window::create(&sdl);
// ? GAME CODE
let mut registry = GameRegistry::new();
game::init(&mut registry);
// ! REGISTER MOD BLOCKS, ETC
//
let mut rm = ResourcePack::new();
rm.load_path("packs/default").unwrap();
rm.blocks.generate_atlas();
let mut world = World::new();
world.load_chunks(ChunkLocation ( 0, 0 ), 2);
// ? ENGINE CODE
let sdl = native::SDL::init();
let window = native::Window::create(&sdl);
let mut shader = render::shader::ShaderProgram::new()
.lighting().textured()
.create().unwrap();
......@@ -32,10 +36,8 @@ fn main() {
shader.enable();
sdl.lock_mouse(true);
render::texture::Texture::from("packs/default/textures/blocks/grass.png").unwrap();
let mut camera = render::camera::Camera::new(); camera.move_up(20.0);
let voxel = mesh::generator::cube(1.0).create();
let mut camera = render::camera::Camera::new();
camera.position = glm::vec3(8.0, 20.0, 8.0);
let mut pressed: HashSet<native::Keycode> = HashSet::new();
let mut now = Instant::now();
......@@ -66,6 +68,7 @@ fn main() {
}
}
let prev = camera.position;
for key in &pressed {
match key {
native::Keycode::W => camera.move_forward(delta * 12.0),
......@@ -78,14 +81,20 @@ fn main() {
}
}
if world.check_collisions(&physics::AABB::from_radius ( camera.position, glm::vec3(0.5, 0.5, 0.5) )) {
camera.position = prev;
}
window.clear();
camera.update(&window.viewport);
shader.upload_vec3("viewPos", &camera.position);
world.load_chunks(ChunkLocation (
(camera.position.x / 16.0).floor() as isize, (camera.position.z / 16.0).floor() as isize ), 2);
world.render(&mut shader, &camera.view_projection);
// world.load_chunks(ChunkLocation (
// (camera.position.x / 16.0).floor() as isize, (camera.position.z / 16.0).floor() as isize ), 2);
rm.blocks.atlas.as_ref().unwrap().texture.enable();
world.render(&mut shader, &camera.view_projection, &rm.blocks);
window.swap();
}
......
use engine::glm;
#[derive(Debug)]
pub struct AABB (
pub glm::Vec3,
pub glm::Vec3,
);
impl AABB {
pub fn from_radius(position: glm::Vec3, radius: glm::Vec3) -> AABB {
AABB (
position - radius,
position + radius,
)
}
pub fn from(position: glm::Vec3, size: glm::Vec3) -> AABB {
AABB (
position,
position + size,
)
}
pub fn collides_with(&self, AABB ( b0, b1 ): AABB) -> bool {
/*(a.minX <= b.maxX && a.maxX >= b.minX) &&
(a.minY <= b.maxY && a.maxY >= b.minY) &&
(a.minZ <= b.maxZ && a.maxZ >= b.minZ)*/
let AABB ( a0, a1 ) = self;
if a0.x <= b1.x && a1.x >= b0.x {
if a0.y <= b1.y && a1.y >= b0.y {
if a0.z <= b1.z && a1.z >= b0.z {
return true
}
}
}
false
}
}
use crate::resources::Resource;
use engine::{ image, image::GenericImageView, render::texture::Texture };
use hashbrown::HashMap;
struct AtlasObj {
id: usize,
x: usize,
y: usize,
}
struct ConstructedAtlas {
size: usize,
entries: Vec<AtlasObj>,
}
#[derive(Debug)]
pub struct AtlasCoordinate (
pub f32,
......@@ -5,3 +20,72 @@ pub struct AtlasCoordinate (
pub f32,
pub f32,
);
pub struct Atlas {
pub texture: Texture,
pub entries: HashMap<usize, AtlasCoordinate>,
}
pub trait AtlasGenerator {
fn atlas_prebuild(&self) -> ConstructedAtlas;
fn atlas_build(&self, pre: &ConstructedAtlas) -> Atlas;
fn generate_atlas(&mut self);
}
impl AtlasGenerator for Resource<image::DynamicImage> {
fn atlas_prebuild(&self) -> ConstructedAtlas {
let mut entries = Vec::new();
// ! TODO: write a better atlas packer
let mut total = 0;
for ( index, texture ) in self.items.iter().enumerate() {
total += texture.width();
entries.push(AtlasObj {
id: index,
x: index * (texture.width() as usize),
y: 0,
});
}
let size = (2 as usize).pow((total as f32).log2().ceil() as u32);
ConstructedAtlas {
size,
entries,
}
}
fn atlas_build(&self, pre: &ConstructedAtlas) -> Atlas {
let mut buf = image::ImageBuffer::<image::Rgba<u8>, Vec<u8>>::new(pre.size as u32, pre.size as u32);
let mut entries = HashMap::new();
for entry in &pre.entries {
let texture = &self.items[entry.id];
let w = texture.width();
let h = texture.height();
for x in 0..w {
for y in 0..h {
buf.put_pixel(entry.x as u32 + x, entry.y as u32 + y, texture.get_pixel(x, y));
}
}
let x0 = entry.x as f32 / pre.size as f32;
let y0 = entry.y as f32 / pre.size as f32;
let x1 = x0 + w as f32 / pre.size as f32;
let y1 = y0 + h as f32 / pre.size as f32;
entries.insert(entry.id, AtlasCoordinate ( x0, x1, y0, y1 ));
}
Atlas {
texture: Texture::from_buf(buf.into_raw(), pre.size as i32, pre.size as i32).unwrap(),
entries
}
}
fn generate_atlas(&mut self) {
self.atlas = Some(self.atlas_build(&self.atlas_prebuild()));
}
}
// loader
\ No newline at end of file
use std::path::Path;
use std::fs::read_dir;
use engine::image;
use crate::resources::Resource;
pub trait ResourceLoader {
fn load_path(&mut self, path: &str) -> Result<(), String> {
match read_dir(path) {
Ok(paths) => {
for path in paths {
self.load(&path.unwrap().path())?;
}
Ok(())
},
Err(..) => Ok(())
}
}
fn load(&mut self, path: &Path) -> Result<(), String>;
}
impl ResourceLoader for Resource<image::DynamicImage> {
fn load(&mut self, path: &Path) -> Result<(), String> {
let id = path.file_stem().unwrap().to_string_lossy().to_string();
let tex = image::open(path).expect(&format!("Could not load image! {}", path.to_str().unwrap()));
self.lookup.insert(id, self.items.len());
self.items.push(tex);
Ok(())
}
}
pub mod loader;
pub mod atlas;
pub mod pack;
use hashbrown::HashMap;
use atlas::Atlas;
pub struct Resource<T> {
pub items: Vec<T>,
pub lookup: HashMap<String, usize>,
pub atlas: Option<Atlas>,
}
impl <T> Resource<T> {
pub fn new() -> Resource<T> {
Resource {
items: Vec::new(),
lookup: HashMap::new(),
atlas: None,
}
}
pub fn retrieve(&self, id: &str) -> &T {
self.items.get(*self.lookup.get(id).unwrap()).unwrap()
}
}
//
\ No newline at end of file
use std::path::Path;
use std::fs::read_to_string;
use serde::{ Serialize, Deserialize };
use serde_json;
use crate::resources::{ Resource, loader::ResourceLoader };
use engine::image;
pub struct ResourcePack {
pub blocks: Resource<image::DynamicImage>,
}
#[derive(Serialize, Deserialize)]
struct Manifest {
version: usize,
name: String,
}
impl ResourcePack {
pub fn new() -> ResourcePack {
ResourcePack {
blocks: Resource::new()
}
}
pub fn load_path(&mut self, path: &str) -> Result<(), String> {
if Path::new(path).exists() {
match read_to_string(format!("{}/manifest.json", path)) {
Ok(contents) => {
match serde_json::from_str::<Manifest>(&contents) {
Ok(manifest) => {
println!("Manifest version {}, loaded {}.", manifest.version, manifest.name);
self.blocks.load_path(&format!("{}/textures/blocks", path))?;
Ok(())
},
Err(err) => Err(format!("Could not parse manifest!\n{}", err))
}
},
Err(..) => Err(format!("Could not load manifest!"))
}
} else {
Err(format!("Resource path does not exist: {}", path))
}
}
}
use hashbrown::HashMap;
use engine::{ mesh::{ Mesh, data::{ MeshData, Render } }, render::{ shader::Program, object::Translation }, glm };
use crate::resources::{ Resource, atlas::AtlasCoordinate };
use crate::physics::AABB;
use engine::{ mesh::{ Mesh, data::{ MeshData, Render } }, render::{ shader::Program, object::Translation }, glm, image };
use noise::{ Perlin, NoiseFn };
use hashbrown::HashMap;
static CHUNK_SIZE: usize = 16;
static CHUNK_HEIGHT: usize = 256;
......@@ -45,7 +48,7 @@ impl Chunk {
let h = ((perlin.get([ (x as isize + self.loc.0 * CHUNK_SIZE as isize) as f64 * 0.03, (z as isize + self.loc.1 * CHUNK_SIZE as isize) as f64 * 0.03 ]) + 1.0) * 10.0) as usize;
for y in 0..h {
self.blocks[y * ROW_COUNT + z * CHUNK_SIZE + x] = 1;
self.blocks[y * ROW_COUNT + z * CHUNK_SIZE + x] = if y > 10 { 2 } else { 1 };
}
}
}
......@@ -61,9 +64,10 @@ impl Chunk {
}*/
self.id_map.push("stone".to_owned());
self.id_map.push("grass".to_owned());
}
pub fn render(&mut self, shader: &mut Program, view_projection: &glm::Mat4) {
pub fn render(&mut self, shader: &mut Program, view_projection: &glm::Mat4, resource: &Resource<image::DynamicImage>) {
if let Some(mesh) = &self.mesh {
// ? RENDER MESH
Translation::new()
......@@ -77,6 +81,17 @@ impl Chunk {
let mut normal = Vec::new();
let mut uv = Vec::new();
// ? FIND ATLAS COORDINATES
let atlas = resource.atlas.as_ref().unwrap();
let mut coords = Vec::new();
for ( i, key ) in self.id_map.iter().enumerate() {
if i > 0 {
coords.push(
atlas.entries.get(resource.lookup.get(key).unwrap()).unwrap()
)
}
}
let ROW_COUNT = CHUNK_SIZE.pow(2);
for x in 0..CHUNK_SIZE {
for y in 0..CHUNK_HEIGHT {
......@@ -184,11 +199,7 @@ impl Chunk {
0.0, -1.0, 0.0,
]);
let x0 = 0.0;
let x1 = 1.0;
let y0 = 0.0;
let y1 = 1.0;
let AtlasCoordinate ( x0, x1, y0, y1 ) = *coords[block - 1];
uv.append(&mut vec![
x1, y1,
x0, y1,
......@@ -242,8 +253,46 @@ impl Chunk {
.normal(normal)
.render(Render::UV(uv))
.create());
self.render(shader, view_projection);
self.render(shader, view_projection, resource);
}
}
pub fn check_collisions(&self, AABB ( l, u ): &AABB) -> bool {
let offset = glm::vec3((self.loc.0 * CHUNK_SIZE as isize) as f32, 0.0, (self.loc.1 * CHUNK_SIZE as isize) as f32);
let l = l - offset;
let u = u - offset;
let a = glm::floor(&l);
let b = glm::ceil(&u);
let ROW_COUNT = CHUNK_SIZE.pow(2);
for x in a.x as isize..b.x as isize {
if x < 0 || x >= CHUNK_SIZE as isize {
continue
}
for y in a.y as isize..b.y as isize {
if y < 0 || x >= CHUNK_HEIGHT as isize {
continue
}
for z in a.z as isize..b.z as isize {
if z < 0 || z >= CHUNK_SIZE as isize {
continue
}
let block = self.blocks[y as usize * ROW_COUNT + z as usize * CHUNK_SIZE + x as usize];
if block != 0 {
if AABB::from(glm::vec3(x as f32, y as f32, z as f32), glm::vec3(1.0, 1.0, 1.0))
.collides_with(AABB ( l, u )) {
return true
}
}
}
}
}
false
}
}
......@@ -281,9 +330,19 @@ impl World {
}
}
pub fn render(&mut self, shader: &mut Program, view_projection: &glm::Mat4) {
pub fn render(&mut self, shader: &mut Program, view_projection: &glm::Mat4, resource: &Resource<image::DynamicImage>) {
for (_, chunk) in &mut self.chunks {
chunk.render(shader, view_projection);
chunk.render(shader, view_projection, resource);
}
}
pub fn check_collisions(&self, bounds: &AABB) -> bool {
for (_, chunk) in &self.chunks {
if chunk.check_collisions(&bounds) {
return true
}
}
false
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment