This commit is contained in:
jusax23 2023-04-18 14:17:53 +02:00
commit 21295e7eb5
Signed by: jusax23
GPG key ID: 499E2AA870C1CD41
22 changed files with 2008 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/target
assets/blocks
assets/break
assets/font

245
Cargo.lock generated Normal file
View file

@ -0,0 +1,245 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crc32fast"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
dependencies = [
"cfg-if",
]
[[package]]
name = "fdeflate"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10"
dependencies = [
"simd-adler32",
]
[[package]]
name = "flate2"
version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
dependencies = [
"crc32fast",
"miniz_oxide 0.6.2",
]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "gl_matrix"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df64d0245c589931a0b5a385a63e7db2aeff209bdd471df0417e0f230a4c33ae"
dependencies = [
"rand",
]
[[package]]
name = "jucraft"
version = "0.1.0"
dependencies = [
"gl_matrix",
"miniquad",
"opensimplex_noise_rs",
"png",
"quad-rand",
]
[[package]]
name = "libc"
version = "0.2.141"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
[[package]]
name = "malloc_buf"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
dependencies = [
"libc",
]
[[package]]
name = "miniquad"
version = "0.3.15"
dependencies = [
"libc",
"ndk-sys",
"objc",
"winapi",
]
[[package]]
name = "miniz_oxide"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
dependencies = [
"adler",
]
[[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 = "ndk-sys"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121"
[[package]]
name = "objc"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [
"malloc_buf",
]
[[package]]
name = "opensimplex_noise_rs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba77c545f2291bb66897afe90c8583c4fdc427fae9cb552db032e74d7526e8b5"
[[package]]
name = "png"
version = "0.17.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa"
dependencies = [
"bitflags",
"crc32fast",
"fdeflate",
"flate2",
"miniz_oxide 0.7.1",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "quad-rand"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "658fa1faf7a4cc5f057c9ee5ef560f717ad9d8dc66d975267f709624d6e1ab88"
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
]
[[package]]
name = "simd-adler32"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f"
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

16
Cargo.toml Normal file
View file

@ -0,0 +1,16 @@
[package]
name = "jucraft"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
gl_matrix = "0.0.2"
miniquad = { path = '../../jucraft/miniquad' }
opensimplex_noise_rs = "0.3.0"
png = "0.17.8"
quad-rand = "0.2.1"
# [replace]
# "miniquad:0.3.14" = { path = '../../jucraft/miniquad' }

View file

@ -0,0 +1,20 @@
#version 100
precision mediump float;
varying vec2 texcoord;
varying float v_position;
uniform sampler2D u_image0;
uniform sampler2D u_image1;
uniform vec2 fog;
void main() {
float fogAmount = smoothstep(fog.x, fog.y, v_position);
gl_FragColor =
texture2D(u_image0, texcoord)
* texture2D(u_image1, texcoord)
* vec4(1.0 - fogAmount, 1.0 - fogAmount, 1.0 - fogAmount, 1.0 - fogAmount);
if(gl_FragColor.a < 0.0000001)
discard;
}

View file

@ -0,0 +1,26 @@
#version 100
precision mediump float;
attribute vec3 pos;
attribute vec2 uv;
attribute vec3 wpos;
varying vec2 texcoord;
varying float v_position;
uniform mat4 view;
uniform mat4 proj;
void main() {
mat4 drawProj = mat4(
vec4(-1.0, 0.0, 0.0, 0.0),
vec4(0.0, 1.0, 0.0, 0.0),
vec4(0.0, 0.0, -1.0, 0.0),
vec4(-wpos.x, wpos.y, -wpos.z, 1.0)
);
texcoord = uv;
gl_Position = proj * view * drawProj * vec4(pos, 1.0);
v_position = length((view * drawProj * vec4(pos, 1.0)).xyz);
}

View file

@ -0,0 +1,29 @@
#version 100
precision lowp float;
varying vec2 texcoord;
uniform sampler2D tex;
uniform vec2 wobble;
uniform vec3 invert;
uniform vec2 blur;
// Source: https://github.com/Jam3/glsl-fast-gaussian-blur/blob/master/5.glsl
vec4 blur5(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
vec4 color = vec4(0.0);
vec2 off1 = vec2(1.3333333333333333) * direction;
color += texture2D(image, uv) * 0.29411764705882354;
color += texture2D(image, uv + (off1 / resolution)) * 0.35294117647058826;
color += texture2D(image, uv - (off1 / resolution)) * 0.35294117647058826;
return color;
}
void main() {
vec2 offset = wobble.x * vec2(
sin(wobble.y + texcoord.y) * 0.1,
cos(wobble.y + texcoord.x) * 0.1
);
vec4 col = texture2D(tex, texcoord + offset * (1.0 - length(texcoord - 0.5) ));
gl_FragColor = (1.0 - col) * vec4(invert, 1.0) + col * (1.0 - vec4(invert, 1.0));//blur5(tex, texcoord, blur, vec2(3.0));
}

View file

@ -0,0 +1,8 @@
#version 100
attribute vec2 pos;
attribute vec2 uv;
varying lowp vec2 texcoord;
void main() {
gl_Position = vec4(pos, 0, 1);
texcoord = uv;
}

88
src/game.rs Normal file
View file

@ -0,0 +1,88 @@
use crate::{
tools::{WPos, Sides}, graphics::DrawType,
};
use self::{block::BlockType, world::World};
pub mod block;
pub mod chunk;
pub mod world;
pub struct Game {
worlds: Vec<World>,
types: Vec<Box<dyn BlockType>>,
type_names: Vec<String>,
}
impl Game {
pub fn new() -> Self {
let mut g = Game {
worlds: vec![],
types: vec![],
type_names: vec![],
};
g.add_type(Box::new(Air {
id: "air".to_string(),
}));
g
}
pub fn get_type(&self, id: usize) -> Option<&Box<dyn BlockType>> {
self.types.get(id)
}
pub fn find_type(&self, id: String) -> Option<(usize, &Box<dyn BlockType>)> {
let index = self.type_names.iter().position(|r| r.eq(&id));
if let Some(i) = index {
return Some((i,&self.types[i]));
}
None
}
pub fn do_tick(&mut self, instant: bool) -> usize {
let mut num = 0;
for w in 0..self.worlds.len() {
num += self.worlds[w].do_tick(instant, &self.types);
}
num
}
pub fn do_tex_tick(&mut self) {
for w in 0..self.worlds.len() {
self.worlds[w].do_tex_tick(&self.types);
}
}
pub fn add_type(&mut self, mut block_type: Box<dyn BlockType>) -> usize {
self.type_names.push(block_type.get_id().to_string());
let index = self.types.len();
block_type.set_index(index);
self.types.push(block_type);
index
}
pub fn add_world(&mut self) -> usize {
self.worlds.push(World::new());
self.worlds.len() - 1
}
pub fn get_world(&mut self, id: usize) -> Option<&mut World> {
self.worlds.get_mut(id)
}
pub fn get_world_im(&self, id: usize) -> Option<&World> {
self.worlds.get(id)
}
}
#[derive(Debug)]
struct Air {
id: String,
}
impl BlockType for Air {
fn get_id(&self) -> String {
self.id.to_string()
}
fn is_sided(&self) -> bool {
false
}
fn texture(&self) -> &DrawType {
&DrawType::None()
}
}

53
src/game/block.rs Normal file
View file

@ -0,0 +1,53 @@
use std::collections::HashMap;
use crate::{graphics::{Draw, DrawType}, tools::PrimitiveData};
use super::{WPos, world::World};
#[derive(Debug)]
pub struct Block {
//pub pos: WPos,
pub block_type: usize,
pub solid: bool,
pub destroy: u8,
string_state: HashMap<String, (PrimitiveData, bool)>,
}
impl Block {
pub fn new(block_type: usize/*, pos: WPos*/) -> Self {
Block {
//pos,
block_type: block_type,
solid: true,
string_state: HashMap::new(),
destroy: 0,
}
}
pub fn get_state(&self, name: &String) -> Option<&PrimitiveData> {
match self.string_state.get(name) {
Some((data, save)) => Some(data),
None => None,
}
}
pub fn set_state(&mut self, name: &String, value: PrimitiveData, save: bool) {
self.string_state.insert(name.to_string(), (value, save));
}
}
pub trait BlockType {
fn get_id(&self) -> String;
fn is_sided(&self) -> bool;
fn set_index(&mut self, _id: usize) {}
fn create(&self, _world: &mut World, _block: WPos, _types: &Vec<Box<dyn BlockType>>, _instant: bool) {}
fn update(&self, _world: &mut World, _block: WPos, _types: &Vec<Box<dyn BlockType>>, _instant: bool) {}
fn render(&self, _world: &mut World, _block: WPos, _types: &Vec<Box<dyn BlockType>>) -> Draw { Draw::None() }
fn texture(&self) -> &DrawType;
}

113
src/game/chunk.rs Normal file
View file

@ -0,0 +1,113 @@
use std::collections::HashMap;
use gl_matrix::{common::*, vec2::clone};
use crate::{tools::Sides, world_generator::WorldGenerator};
use super::{block::Block, WPos};
#[derive(Debug)]
pub enum Instances {
Single(Vec<WPos>),
Sided([Vec<WPos>; 6]),
}
#[derive(Debug)]
pub struct Chunk {
pub blocks: HashMap<(u8, u8, u8), Block>, //[[[Block; 16]; 256]; 16],
pub instances: HashMap<usize, Instances>,
}
impl Chunk {
pub fn new(_chunk_x: i32, _chunk_z: i32) -> Self {
Self {
#[rustfmt::skip]
blocks: HashMap::new(),
instances: HashMap::new(),
}
}
pub fn new_gen(generator: Box<dyn WorldGenerator>,_chunk_x: i32, _chunk_z: i32) -> Self {
let mut c = Self {
blocks: HashMap::new(),
instances: HashMap::new(),
};
generator.generateChunk(&mut c);
c
}
pub fn set_block(&mut self, pos: &WPos, block_type: usize) {
let inner_x = pos[0].rem_euclid(16) as u8;
let inner_z = pos[2].rem_euclid(16) as u8;
self.blocks.insert(
(inner_x, pos[1] as u8, inner_z),
Block::new(block_type/*, *pos*/),
);
}
pub fn remove_pos(&mut self, block_type: usize, pos: &WPos) {
if let Some(data) = self.instances.get_mut(&block_type) {
match data {
Instances::Single(d) => {
d.retain(|f| pos[0] != f[0] || pos[1] != f[1] || pos[2] != f[2]);
if d.len() == 0 {
self.instances.remove(&block_type);
}
}
Instances::Sided(d) => {
for i in 0..6 {
d[i].retain(|f| pos[0] != f[0] || pos[1] != f[1] || pos[2] != f[2]);
}
if d[0].len() == 0
&& d[1].len() == 0
&& d[2].len() == 0
&& d[3].len() == 0
&& d[4].len() == 0
&& d[5].len() == 0
{
self.instances.remove(&block_type);
}
}
}
}
}
pub fn add_tex_pos(&mut self, block_type: usize, pos: &WPos) {
if let Some(inst) = self.instances.get_mut(&block_type) {
if let Instances::Single(vec) = inst {
if !vec.contains(&pos) {
vec.push(pos.clone());
}
} else {
panic!("Wrong side Type")
}
} else {
self.instances
.insert(block_type, Instances::Single(vec![pos.clone()]));
}
}
pub fn add_tex_pos_sided(&mut self, block_type: usize, pos: &WPos, sides: Sides<bool>) {
if let Some(inst) = self.instances.get_mut(&block_type) {
if let Instances::Sided(vec) = inst {
for i in 0..6 {
if sides[i] {
if !vec[i].contains(&pos) {
vec[i].push(pos.clone());
}
} else {
vec[i].retain(|f| pos[0] != f[0] || pos[1] != f[1] || pos[2] != f[2]);
}
}
} else {
panic!("Wrong side Type")
}
} else {
let mut new_arr: [Vec<[i32; 3]>; 6] = [vec![], vec![], vec![], vec![], vec![], vec![]];
for i in 0..6 {
if sides[i] {
new_arr[i].push(pos.clone());
}
}
self.instances.insert(block_type, Instances::Sided(new_arr));
}
}
}

245
src/game/world.rs Normal file
View file

@ -0,0 +1,245 @@
use std::collections::HashMap;
use crate::{graphics::Draw, world_generator::WorldGenerator};
use super::{block::Block, chunk::Chunk, BlockType, Sides, WPos};
pub enum GetBlock<T> {
Some(T),
None,
No,
}
//#[derive(Debug)]
pub struct World {
pub chunks: HashMap<(i32, i32), Chunk>,
generator: Box<dyn WorldGenerator>,
updates: Vec<WPos>,
i_updates: Vec<WPos>,
t_updates: Vec<WPos>,
}
impl World {
pub fn new() -> Self {
World {
chunks: HashMap::new(),
updates: vec![],
i_updates: vec![],
t_updates: vec![],
generator: Box::new(EmptyGenerator {}),
}
}
pub fn get_block(&mut self, pos: &WPos) -> GetBlock<&mut Block> {
if pos[1] < 0 || pos[1] > 256 {
return GetBlock::None;
}
let chunk_x = pos[0].div_euclid(16);
let chunk_z = pos[2].div_euclid(16);
let inner_x = pos[0].rem_euclid(16);
let inner_z = pos[2].rem_euclid(16);
let chunk = self.chunks.get_mut(&(chunk_x, chunk_z));
match chunk {
Some(c) => match c
.blocks
.get_mut(&(inner_x as u8, pos[1] as u8, inner_z as u8))
{
Some(b) => GetBlock::Some(b),
None => GetBlock::No,
},
None => GetBlock::None,
}
}
pub fn get_block_im(&self, pos: &WPos) -> GetBlock<&Block> {
if pos[1] < 0 || pos[1] > 256 {
return GetBlock::None;
}
let chunk_x = pos[0].div_euclid(16);
let chunk_z = pos[2].div_euclid(16);
let inner_x = pos[0].rem_euclid(16);
let inner_z = pos[2].rem_euclid(16);
let chunk = self.chunks.get(&(chunk_x, chunk_z));
match chunk {
Some(c) => match c.blocks.get(&(inner_x as u8, pos[1] as u8, inner_z as u8)) {
Some(b) => GetBlock::Some(b),
None => GetBlock::No,
},
None => GetBlock::None,
}
}
fn loadChunk(&mut self, chunk_x: i32, chunk_z: i32) {
if !self.chunks.contains_key(&(chunk_x, chunk_z)) {
self.chunks
.insert((chunk_x, chunk_z), Chunk::new(chunk_x, chunk_z));
for x in 0..16 {
for y in 0..256 {
self.update_texture(&[chunk_x * 16 + x, y, chunk_z * 16 - 1]);
self.update_texture(&[chunk_x * 16 + x, y, chunk_z * 16 + 16]);
self.update_texture(&[chunk_x * 16 - 1, y, chunk_z * 16 + x]);
self.update_texture(&[chunk_x * 16 + 16, y, chunk_z * 16 + x]);
}
}
}
}
pub fn set_block(
&mut self,
pos: &WPos,
block_type: usize,
update: Sides<bool>,
update_self: bool,
) {
if pos[1] < 0 {
return;
}
let chunk_x = pos[0].div_euclid(16);
let chunk_z = pos[2].div_euclid(16);
//let mut new_c = false;
if !self.chunks.contains_key(&(chunk_x, chunk_z)) {
self.chunks
.insert((chunk_x, chunk_z), Chunk::new(chunk_x, chunk_z));
//new_c = true;
}
/*if new_c {
for x in 0..16 {
for y in 0..256 {
self.update(&[chunk_x * 16 + x, y, chunk_z * 16 - 1], false);
self.update(&[chunk_x * 16 + x, y, chunk_z * 16 + 16], false);
self.update(&[chunk_x * 16 - 1, y, chunk_z * 16 + x], false);
self.update(&[chunk_x * 16 + 16, y, chunk_z * 16 + x], false);
}
}
}*/
if let Some(chunk) = self.chunks.get_mut(&(chunk_x, chunk_z)) {
chunk.set_block(pos, block_type);
self.update_texture(&[pos[0], pos[1], pos[2]]);
self.update_texture(&[pos[0] + 1, pos[1], pos[2]]);
self.update_texture(&[pos[0] - 1, pos[1], pos[2]]);
self.update_texture(&[pos[0], pos[1] + 1, pos[2]]);
self.update_texture(&[pos[0], pos[1] - 1, pos[2]]);
self.update_texture(&[pos[0], pos[1], pos[2] + 1]);
self.update_texture(&[pos[0], pos[1], pos[2] - 1]);
if update_self {
self.update(&[pos[0], pos[1], pos[2]], true);
}
if update.right {
self.update(&[pos[0] - 1, pos[1], pos[2]], false);
}
if update.left {
self.update(&[pos[0] + 1, pos[1], pos[2]], false);
}
if update.top {
self.update(&[pos[0], pos[1] + 1, pos[2]], false);
}
if update.bottom {
self.update(&[pos[0], pos[1] - 1, pos[2]], false);
}
if update.front {
self.update(&[pos[0], pos[1], pos[2] + 1], false);
}
if update.back {
self.update(&[pos[0], pos[1], pos[2] - 1], false);
}
}
}
pub fn update_texture(&mut self, pos: &WPos) {
self.t_updates.push(pos.clone());
}
pub fn update(&mut self, pos: &WPos, instant: bool) {
if instant {
self.i_updates.push(pos.clone())
} else {
self.updates.push(pos.clone())
}
}
pub fn update_surr(&mut self, pos: &WPos, instant: bool) {
self.update(&[pos[0] + 1, pos[1], pos[2]], instant);
self.update(&[pos[0] - 1, pos[1], pos[2]], instant);
self.update(&[pos[0], pos[1] + 1, pos[2]], instant);
self.update(&[pos[0], pos[1] - 1, pos[2]], instant);
self.update(&[pos[0], pos[1], pos[2] + 1], instant);
self.update(&[pos[0], pos[1], pos[2] - 1], instant);
}
pub fn do_tick(&mut self, instant: bool, types: &Vec<Box<dyn BlockType>>) -> usize {
let upd = if instant {
let o = self.i_updates.clone();
self.i_updates = vec![];
o
} else {
let o = self.updates.clone();
self.updates = vec![];
o
};
for p in 0..upd.len() {
let cord = upd[p].clone();
if let GetBlock::Some(block) = self.get_block(&cord) {
if let Some(b_t) = types.get(block.block_type) {
b_t.update(self, cord.clone(), types, instant);
}
}
}
upd.len()
}
pub fn do_tex_tick(&mut self, types: &Vec<Box<dyn BlockType>>) {
let upd = self.t_updates.clone();
self.t_updates = vec![];
for p in 0..upd.len() {
let pos = upd[p];
let chunk_x = pos[0].div_euclid(16);
let chunk_z = pos[2].div_euclid(16);
if let GetBlock::Some(block) = self.get_block(&pos) {
let block_type_num = block.block_type;
if let Some(block_type) = types.get(block_type_num) {
let draw = block_type.render(self, pos.clone(), types);
if let Some(chunk) = self.chunks.get_mut(&(chunk_x, chunk_z)) {
match draw {
Draw::Sides(s) => {
if block_type.is_sided() {
chunk.add_tex_pos_sided(block_type_num, &pos, s);
} else {
chunk.add_tex_pos(block_type_num, &pos);
}
}
Draw::All() => {
if block_type.is_sided() {
chunk.add_tex_pos_sided(block_type_num, &pos, Sides::all(true));
} else {
chunk.add_tex_pos(block_type_num, &pos);
}
}
Draw::None() => {
chunk.remove_pos(block_type_num, &pos);
}
}
}
}
}
}
}
}
struct EmptyGenerator {}
impl WorldGenerator for EmptyGenerator {
fn generateChunk(&self, chunk: &mut Chunk) {}
}

58
src/graphics.rs Normal file
View file

@ -0,0 +1,58 @@
use std::collections::HashMap;
use miniquad::*;
use crate::tools::Sides;
#[derive(Debug)]
pub enum Draw {
All(), //single Model
None(),
Sides(Sides<bool>),
}
pub enum DrawType {
All(Texture), //single Model
None(),
Sides(Sides<Texture>),
}
pub struct Graphics {
pub textures: HashMap<String, Texture>,
pub pipelines: HashMap<String, Pipeline>,
}
impl Graphics {
pub fn new() -> Self {
Graphics { textures: HashMap::new(), pipelines: HashMap::new() }
}
pub fn load_texture(&mut self, ctx: &mut Context, bytes: &[u8], id: String) -> Texture {
let decoder = png::Decoder::new(bytes);
let mut reader = decoder.read_info().unwrap();
let mut buf = vec![0; reader.output_buffer_size()];
let info = reader.next_frame(&mut buf).unwrap();
let bytes = &buf[..info.buffer_size()];
let text = Texture::from_data_and_format(
ctx,
bytes,
TextureParams {
format: TextureFormat::RGBA8,
wrap: TextureWrap::Clamp,
filter: FilterMode::Nearest,
width: info.width,
height: info.height,
},
);
//text.set_filter_min_mag(ctx, FilterMode::Linear, FilterMode::Nearest);
self.textures.insert(id, text);
text
}
pub fn addPipeline(&mut self, pipeline: Pipeline, id:String) {
self.pipelines.insert(id, pipeline);
}
}

108
src/jucraft.rs Normal file
View file

@ -0,0 +1,108 @@
use crate::{game::*, graphics::*, tools::Sides};
use default_solid_block::DefaultSolidBlock;
use miniquad::*;
mod default_solid_block;
pub mod default_solid_shader;
pub fn register(ctx: &mut Context, game: &mut Game, graphics: &mut Graphics) {
graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/break/empty_overlay.png")),
"d-1".to_string(),
);
graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/break/destroy_stage_0.png")),
"d0".to_string(),
);
graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/break/destroy_stage_1.png")),
"d1".to_string(),
);
graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/break/destroy_stage_2.png")),
"d2".to_string(),
);
graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/break/destroy_stage_3.png")),
"d3".to_string(),
);
graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/break/destroy_stage_4.png")),
"d4".to_string(),
);
graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/break/destroy_stage_5.png")),
"d5".to_string(),
);
graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/break/destroy_stage_6.png")),
"d6".to_string(),
);
graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/break/destroy_stage_7.png")),
"d7".to_string(),
);
let stone_tex = graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/blocks/stone.png")),
"stone".to_string(),
);
let dirt_tex = graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/blocks/dirt.png")),
"dirt".to_string(),
);
let cobble_tex = graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/blocks/cobblestone.png")),
"cobblestone".to_string(),
);
let grass_top = graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/blocks/grass_top.png")),
"grass_top".to_string(),
);
let grass_side = graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/blocks/grass_side.png")),
"grass_side".to_string(),
);
let grass_bottom = graphics.load_texture(
ctx,
include_bytes!(concat!("../assets/blocks/grass_bottom.png")),
"grass_bottom".to_string(),
);
let stone = game.add_type(Box::new(DefaultSolidBlock {
id: "stone".to_string(),
texture: DrawType::All(stone_tex),
}));
let dirt = game.add_type(Box::new(DefaultSolidBlock {
id: "dirt".to_string(),
texture: DrawType::All(dirt_tex),
}));
let cobblestone = game.add_type(Box::new(DefaultSolidBlock {
id: "cobblestone".to_string(),
texture: DrawType::All(cobble_tex),
}));
let grassblock = game.add_type(Box::new(DefaultSolidBlock {
id: "grassblock".to_string(),
texture: DrawType::Sides(Sides {
top: grass_top,
bottom: grass_bottom,
left: grass_side,
right: grass_side,
front: grass_side,
back: grass_side,
}),
}));
}

View file

@ -0,0 +1,79 @@
use crate::{
game::{block::*, world::*},
graphics::*,
tools::*,
};
pub struct DefaultSolidBlock {
pub id: String,
pub texture: DrawType,
}
impl BlockType for DefaultSolidBlock {
fn get_id(&self) -> String {
self.id.to_string()
}
fn create(
&self,
world: &mut World,
block: WPos,
_types: &Vec<Box<dyn BlockType>>,
_instant: bool,
) {
if let GetBlock::Some(b) = world.get_block(&block) {
if !b.solid {
b.solid = true;
}
}
}
fn render(
&self,
world: &mut World,
block: WPos,
_types: &Vec<Box<dyn BlockType>>,
) -> Draw {
let mut sides = Sides::all(true);
sides.top = match world.get_block(&[block[0], block[1] + 1, block[2]]) {
GetBlock::Some(bt) => !bt.solid,
GetBlock::None => false,
GetBlock::No => true,
};
sides.bottom = match world.get_block(&[block[0], block[1] - 1, block[2]]) {
GetBlock::Some(bt) => !bt.solid,
GetBlock::None => false,
GetBlock::No => true,
};
sides.right = match world.get_block(&[block[0] - 1, block[1], block[2]]) {
GetBlock::Some(bt) => !bt.solid,
GetBlock::None => false,
GetBlock::No => true,
};
sides.left = match world.get_block(&[block[0] + 1, block[1], block[2]]) {
GetBlock::Some(bt) => !bt.solid,
GetBlock::None => false,
GetBlock::No => true,
};
sides.front = match world.get_block(&[block[0], block[1], block[2] - 1]) {
GetBlock::Some(bt) => !bt.solid,
GetBlock::None => false,
GetBlock::No => true,
};
sides.back = match world.get_block(&[block[0], block[1], block[2] + 1]) {
GetBlock::Some(bt) => !bt.solid,
GetBlock::None => false,
GetBlock::No => true,
};
if sides.are_all(false) {
Draw::None()
} else {
Draw::Sides(sides)
}
}
fn texture(&self) -> &DrawType {
&self.texture
}
fn is_sided(&self) -> bool {
true
}
}

View file

@ -0,0 +1,26 @@
use gl_matrix::common::*;
use miniquad::*;
pub const VERTEX: &str = include_str!(concat!("../../assets/shader/default.vsh.glsl"));
pub const FRAGMENT: &str = include_str!(concat!("../../assets/shader/default.fsh.glsl"));
pub fn meta() -> ShaderMeta {
ShaderMeta {
images: vec!["u_image0".to_string(), "u_image1".to_string()],
uniforms: UniformBlockLayout {
uniforms: vec![
UniformDesc::new("view", UniformType::Mat4),
UniformDesc::new("proj", UniformType::Mat4),
UniformDesc::new("fog", UniformType::Float2),
],
},
}
}
#[repr(C)]
pub struct Uniforms {
pub view: Mat4,
pub proj: Mat4,
pub fog: Vec2,
}

27
src/main.rs Normal file
View file

@ -0,0 +1,27 @@
use miniquad::*;
use stage::Stage;
mod game;
mod shader;
mod stage;
mod graphics;
mod tools;
mod jucraft;
mod player;
mod world_generator;
fn main() {
start(conf::Conf{
window_title: "Jucraft".to_string(),
window_height: 900,
window_width: 900* 16 / 9,
..Default::default()
}, |mut ctx| {
Box::new(Stage::new(&mut ctx))
});
}
// to read: for Map generation: https://www.redblobgames.com/maps/terrain-from-noise/
// with opensimplex_noise_rs crate

218
src/player.rs Normal file
View file

@ -0,0 +1,218 @@
use gl_matrix::{common::*, *};
use crate::{
game::{world::GetBlock, Game},
tools::*,
};
pub struct Player {
pub rot: Vec2,
pub pos: Vec3,
pub motion: Vec3,
pub eyes: f32,
pub size: Vec3,
pub flying: bool,
pub max_speed: f32,
pub world: usize,
// retundant
pub speed: f32,
pub on_gound: bool,
}
impl Player {
pub fn new(rot: Vec2, pos: Vec3) -> Self {
Self {
rot,
pos,
motion: [0., 0., 0.],
eyes: 1.7,
size: [0.8, 1.99, 0.8],
flying: true,
max_speed: 10.,
world: 0,
speed: 0.,
on_gound: false,
}
}
pub fn update(&mut self, game: &mut Game, s_move: &Sides<bool>, delta: f32) {
if self.flying {
if s_move.top {
self.motion[1] += delta * 100.0;
}
if s_move.bottom {
self.motion[1] -= delta * 100.0;
}
let decal = 70. * delta;
if self.motion[1].abs() > decal {
if self.motion[1] > 0. {
self.motion[1] -= decal;
} else {
self.motion[1] += decal;
}
} else {
self.motion[1] = 0.;
}
} else {
if self.on_gound && s_move.top {
self.motion[1] = 10.;
}
self.motion[1] -= delta * 30.;
if self.motion[1].abs() > 30. {
if self.motion[1] > 0. {
self.motion[1] = 30.;
} else {
self.motion[1] = -30.;
}
}
}
let decalerate: f32 = if self.on_gound || self.flying {
50.
} else {
1.
};
let acceleration: f32 = if self.on_gound || self.flying {
100. * 50.
} else {
10. + 1.
};
if s_move.front {
self.motion[2] += self.rot[1].to_radians().cos() * delta * acceleration;
self.motion[0] -= self.rot[1].to_radians().sin() * delta * acceleration;
}
if s_move.back {
self.motion[2] -= self.rot[1].to_radians().cos() * delta * acceleration;
self.motion[0] += self.rot[1].to_radians().sin() * delta * acceleration;
}
if s_move.left {
self.motion[2] += self.rot[1].to_radians().sin() * delta * acceleration;
self.motion[0] += self.rot[1].to_radians().cos() * delta * acceleration;
}
if s_move.right {
self.motion[2] -= self.rot[1].to_radians().sin() * delta * acceleration;
self.motion[0] -= self.rot[1].to_radians().cos() * delta * acceleration;
}
self.speed = (self.motion[0].powi(2) + self.motion[2].powi(2)).sqrt();
if self.speed > self.max_speed {
let modifier = self.max_speed / self.speed;
self.motion[0] = self.motion[0] * modifier;
self.motion[2] = self.motion[2] * modifier;
} else {
if self.speed > 0.1 {
let modi_x = delta * decalerate * self.motion[0] / self.speed;
if (self.motion[0] > 0.) == (self.motion[0] - modi_x > 0.) {
self.motion[0] -= modi_x;
} else {
self.motion[0] = 0.;
}
let modi_z = delta * decalerate * self.motion[2] / self.speed;
if (self.motion[2] > 0.) == (self.motion[2] - modi_z > 0.) {
self.motion[2] -= modi_z;
} else {
self.motion[2] = 0.;
}
} else {
self.motion[0] = 0.;
self.motion[2] = 0.;
}
}
//self.pos[0] += self.motion[0] * delta;
//self.pos[1] += self.motion[1] * delta;
//self.pos[2] += self.motion[2] * delta;
self.on_gound = false;
for cord in 0..3 {
let mut dist = self.motion[cord] * delta;
while dist.abs() > 0. {
let do_dist = if dist.abs() < 0.5 {
let d = dist;
dist = 0.;
d
} else {
if dist > 0. {
dist -= 0.5;
0.5
} else {
dist += 0.5;
-0.5
}
};
if self.is_clipped(game).is_none() {
self.pos[cord] += do_dist;
if let Some((b_pos, b_size)) = self.is_clipped(game) {
let self_offset = if cord == 1 { 0. } else { self.size[cord] / 2. };
if do_dist > 0. {
self.pos[cord] = b_pos[cord] - self_offset - 0.001;
} else if do_dist < 0. {
self.pos[cord] = b_pos[cord] + b_size[cord] + self_offset + 0.001;
if cord == 1 {
self.on_gound = true;
}
}
self.motion[cord] = 0.;
}
} else {
self.pos[cord] += do_dist;
}
}
}
}
pub fn is_clipped(&self, game: &mut Game) -> Option<(Vec3, Vec3)> {
if let Some(world) = game.get_world_im(self.world) {
let mx = self.pos[0].floor() as i32;
let my = self.pos[1].floor() as i32;
let mz = self.pos[2].floor() as i32;
let vx = (self.size[0] / 2.).ceil() as i32;
let vy = (self.size[1]).ceil() as i32;
let vz = (self.size[2] / 2.).ceil() as i32;
for x in mx - vx..=mx + vy {
for z in mz - 1..=mz + vz {
for y in my - vy..=my + vy {
if let GetBlock::Some(_block) = world.get_block_im(&[x, y, z]) {
// TODO: block size
//println!("inner clip");
if check_overlap(
[self.pos[0], self.pos[1] + (self.size[1] / 2.0), self.pos[2]],
[
x as f32 + 1.0 / 2.0,
y as f32 + 1.0 / 2.0,
z as f32 + 1.0 / 2.0,
],
self.size,
[1., 1., 1.],
) {
return Some(([x as f32, y as f32, z as f32], [1., 1., 1.]));
}
}
}
}
}
}
None
}
pub fn rotate(&mut self, x: f32, y: f32) {
self.rot[0] -= y / 10.0;
self.rot[1] += x / 10.0;
while self.rot[0] > 90.0 {
self.rot[0] = 90.;
}
while self.rot[0] < -90.0 {
self.rot[0] = -90.;
}
while self.rot[1] > 180.0 {
self.rot[1] -= 360.;
}
while self.rot[1] < -180.0 {
self.rot[1] += 360.;
}
}
}

141
src/shader.rs Normal file
View file

@ -0,0 +1,141 @@
use std::f64::consts::PI;
use gl_matrix::{common::*, *};
use miniquad::*;
pub mod post;
pub struct RenderHelper {
post_processing_pipeline: Pipeline,
post_processing_bind: Bindings,
offscreen_pass: RenderPass,
post_enabled: bool,
}
impl RenderHelper {
pub fn new(ctx: &mut Context) -> Self {
let (w, h) = ctx.screen_size();
let color_img = Texture::new_render_texture(
ctx,
TextureParams {
width: w as _,
height: h as _,
format: TextureFormat::RGBA8,
..Default::default()
},
);
let depth_img = Texture::new_render_texture(
ctx,
TextureParams {
width: w as _,
height: h as _,
format: TextureFormat::Depth,
..Default::default()
},
);
let offscreen_pass = RenderPass::new(ctx, color_img, depth_img);
#[rustfmt::skip]
let post_vertices: &[f32] = &[
/* pos uvs */
-1.0, -1.0, 0.1, 0.1,
1.0, -1.0, 0.9, 0.1,
1.0, 1.0, 0.9, 0.9,
-1.0, 1.0, 0.1, 0.9,
];
let post_vertex_buffer = Buffer::immutable(ctx, BufferType::VertexBuffer, &post_vertices);
let post_indices: &[u16] = &[0, 1, 2, 0, 2, 3];
let post_index_buffer = Buffer::immutable(ctx, BufferType::IndexBuffer, &post_indices);
let post_processing_bind = Bindings {
vertex_buffers: vec![post_vertex_buffer],
index_buffer: post_index_buffer,
images: vec![color_img],
};
let post_shader = Shader::new(ctx, post::VERTEX, post::FRAGMENT, post::meta()).unwrap();
let post_processing_pipeline = Pipeline::new(
ctx,
&[BufferLayout::default()],
&[
VertexAttribute::new("pos", VertexFormat::Float2),
VertexAttribute::new("uv", VertexFormat::Float2),
],
post_shader,
);
Self {
post_processing_pipeline,
post_processing_bind,
offscreen_pass,
post_enabled: true,
}
}
pub fn resize(&mut self, ctx: &mut Context, width: f32, height: f32) {
let color_img = Texture::new_render_texture(
ctx,
TextureParams {
width: width as _,
height: height as _,
format: TextureFormat::RGBA8,
..Default::default()
},
);
let depth_img = Texture::new_render_texture(
ctx,
TextureParams {
width: width as _,
height: height as _,
format: TextureFormat::Depth,
..Default::default()
},
);
let offscreen_pass = RenderPass::new(ctx, color_img, depth_img);
self.offscreen_pass.delete(ctx);
self.offscreen_pass = offscreen_pass;
self.post_processing_bind.images[0] = color_img;
}
pub fn begin_world(&self, ctx: &mut Context) {
if self.post_enabled {
ctx.begin_pass(
self.offscreen_pass,
PassAction::clear_color(0.75, 0.85, 0.8, 1.0),
);
} else {
ctx.begin_default_pass(PassAction::clear_color(0.75, 0.85, 0.8, 1.0));
}
}
pub fn do_post_begin_ui(&self, ctx: &mut Context) {
ctx.end_render_pass();
if self.post_enabled {
let t = date::now();
ctx.begin_default_pass(PassAction::Nothing);
ctx.apply_pipeline(&self.post_processing_pipeline);
ctx.apply_bindings(&self.post_processing_bind);
let invert = ((t).sin()/2.0 + 0.5) as f32;
ctx.apply_uniforms(&post::Uniforms {
wobble: [1., ((t * 6.0) % (2.0 * PI)) as f32],
invert: [invert, invert, invert],
blur: [1., 1.],
});
ctx.draw(0, 6, 1);
ctx.end_render_pass();
}
ctx.begin_default_pass(PassAction::Nothing);
}
pub fn end_ui(&self, ctx: &mut Context) {
ctx.end_render_pass();
ctx.commit_frame();
}
}

26
src/shader/post.rs Normal file
View file

@ -0,0 +1,26 @@
use gl_matrix::common::*;
use miniquad::*;
pub const VERTEX: &str = include_str!(concat!("../../assets/shader/post.vsh.glsl"));
pub const FRAGMENT: &str = include_str!(concat!("../../assets/shader/post.fsh.glsl"));
pub fn meta() -> ShaderMeta {
ShaderMeta {
images: vec!["tex".to_string()],
uniforms: UniformBlockLayout {
uniforms: vec![
UniformDesc::new("wobble", UniformType::Float2),
UniformDesc::new("invert", UniformType::Float3),
UniformDesc::new("blur", UniformType::Float2),
],
},
}
}
#[repr(C)]
pub struct Uniforms {
pub wobble: Vec2,
pub invert: Vec3,
pub blur: Vec2,
}

400
src/stage.rs Normal file
View file

@ -0,0 +1,400 @@
use gl_matrix::{mat4, common::*};
use miniquad::*;
use crate::{game::{Game, chunk::*}, graphics::{Graphics, DrawType}, jucraft::{*, self}, shader::RenderHelper, tools::*, player::Player};
const MAX_INSTANT_TICKS: i32 = 50;
pub struct Stage {
game: Game,
graphics: Graphics,
render_helper: RenderHelper,
last_tick: f64,
delta: f64,
last_frame: f64,
pipeline: Pipeline,
bindings: Bindings,
fullscreen: bool,
player: Player,
mouse_grab: bool,
s_move: Sides<bool>,
x: i32,
y: i32,
z: i32,
t_fp:f64,
}
impl Stage {
pub fn new(ctx: &mut Context) -> Stage {
let mut game = Game::new();
let mut graphics = Graphics::new();
let world = game.add_world();
jucraft::register(ctx,&mut game, &mut graphics);
let (grass,_) = game.find_type("grassblock".to_string()).unwrap();
let (stone,_) = game.find_type("stone".to_string()).unwrap();
let (cobblestone,_) = game.find_type("cobblestone".to_string()).unwrap();
if let Some(world) = game.get_world(world){
world.set_block(&[162,65,161], cobblestone, Sides::all(true), true);
world.set_block(&[162,64,161], grass, Sides::all(true), true);
world.set_block(&[162,64,162], grass, Sides::all(true), true);
world.set_block(&[163,64,161], stone, Sides::all(true), true);
world.set_block(&[161,64,161], stone, Sides::all(true), true);
}
let mut player = Player::new(
[0.,0.],
[16.*10.,63.,16.*10.],
);
player.world = world;
let post = RenderHelper::new(ctx);
#[rustfmt::skip]
let vertices = vec![
Vertex{pos:[0.0, 0.0, 1.0], uv:[0.0, 1.0]},
Vertex{pos:[1.0, 0.0, 1.0], uv:[1.0, 1.0]},
Vertex{pos:[0.0, 1.0, 1.0], uv:[0.0, 0.0]},
Vertex{pos:[1.0, 1.0, 1.0], uv:[1.0, 0.0]},
Vertex{pos:[0.0, 0.0, 0.0], uv:[0.0, 1.0]},
Vertex{pos:[0.0, 0.0, 1.0], uv:[1.0, 1.0]},
Vertex{pos:[0.0, 1.0, 0.0], uv:[0.0, 0.0]},
Vertex{pos:[0.0, 1.0, 1.0], uv:[1.0, 0.0]},
Vertex{pos:[1.0, 0.0, 0.0], uv:[0.0, 1.0]},
Vertex{pos:[0.0, 0.0, 0.0], uv:[1.0, 1.0]},
Vertex{pos:[1.0, 1.0, 0.0], uv:[0.0, 0.0]},
Vertex{pos:[0.0, 1.0, 0.0], uv:[1.0, 0.0]},
Vertex{pos:[1.0, 0.0, 1.0], uv:[0.0, 1.0]},
Vertex{pos:[1.0, 0.0, 0.0], uv:[1.0, 1.0]},
Vertex{pos:[1.0, 1.0, 1.0], uv:[0.0, 0.0]},
Vertex{pos:[1.0, 1.0, 0.0], uv:[1.0, 0.0]},
Vertex{pos:[0.0, 1.0, 0.0], uv:[0.0, 1.0]},
Vertex{pos:[0.0, 1.0, 1.0], uv:[1.0, 1.0]},
Vertex{pos:[1.0, 1.0, 0.0], uv:[0.0, 0.0]},
Vertex{pos:[1.0, 1.0, 1.0], uv:[1.0, 0.0]},
Vertex{pos:[0.0, 0.0, 0.0], uv:[0.0, 1.0]},
Vertex{pos:[1.0, 0.0, 0.0], uv:[1.0, 1.0]},
Vertex{pos:[0.0, 0.0, 1.0], uv:[0.0, 0.0]},
Vertex{pos:[1.0, 0.0, 1.0], uv:[1.0, 0.0]}
];
let vertex_buffer = Buffer::immutable(ctx, BufferType::VertexBuffer, &vertices);
let indices = vec![
16, 17, 18, // top
19, 18, 17,
20, 21, 22, // bottom
23, 22, 21,
12, 13, 14, // left
15, 14, 13,
4, 5, 6, //right
7, 6, 5,
8, 9, 10, // front
11, 10, 9,
0, 1, 2, // back
3, 2, 1,
];
let index_buffer = Buffer::immutable(ctx, BufferType::IndexBuffer, &indices);
let positions_vertex_buffer = Buffer::stream(
ctx,
BufferType::VertexBuffer,
16*16*256 * std::mem::size_of::<WPos>(),
);
let bindings = Bindings {
vertex_buffers: vec![vertex_buffer, positions_vertex_buffer],
index_buffer: index_buffer,
images: vec![graphics.textures["stone"], graphics.textures["d-1"]],
};
let shader = Shader::new(ctx, default_solid_shader::VERTEX, default_solid_shader::FRAGMENT, default_solid_shader::meta()).unwrap();
let pipeline = Pipeline::with_params(
ctx,
&[BufferLayout::default(), BufferLayout {
step_func: VertexStep::PerInstance,
..Default::default()
},],
&[
VertexAttribute::with_buffer("pos", VertexFormat::Float3,0),
VertexAttribute::with_buffer("uv", VertexFormat::Float2,0),
VertexAttribute::with_buffer("wpos", VertexFormat::Int3, 1),
],
shader,
PipelineParams {
depth_test: Comparison::LessOrEqual,
depth_write: true,
cull_face: CullFace::Back,
front_face_order: FrontFaceOrder::CounterClockwise,
color_blend: Some(BlendState::new(Equation::Add, BlendFactor::One, BlendFactor::OneMinusValue(BlendValue::SourceAlpha))),
alpha_blend: Some(BlendState::new(Equation::Add, BlendFactor::One, BlendFactor::Zero)),
..Default::default()
}
);
println!("created");
Self {
game,
graphics,
last_tick: date::now(),
delta: 0.1,
last_frame: date::now(),
render_helper: post,
pipeline,
bindings,
fullscreen: false,
player,
mouse_grab: false,
s_move: Sides::all(false),
x: 2,
y: 1,
z: 1,
t_fp: 20.,
}
}
}
impl EventHandler for Stage {
fn update(&mut self, _ctx: &mut Context) {
let t = date::now();
self.delta = t - self.last_frame;
self.last_frame = t;
let mut l_a = 1;
let mut count = 0;
while l_a > 0 {
if count > MAX_INSTANT_TICKS {
eprintln!("Instant tick overflow");
break;
}
l_a = self.game.do_tick(true);
count += 1;
}
if self.last_tick < t - 1. / 20. {
self.last_tick += 1. / 20.;
self.game.do_tick(false);
//eprintln!("fps: {}|{}", 1. / self.delta, self.t_fp);
if self.last_tick < t - 5. {
self.last_tick = t - 1. / 20.;
}
}
self.game.do_tex_tick();
self.player.update(&mut self.game, &self.s_move, self.delta as f32);
let (index,_) = self.game.find_type("stone".to_string()).unwrap();
if self.z < 16*20 {
if let Some(world) = self.game.get_world(0) {
for _ in 0..10000 {
if self.z >= 16*20 {break;}
world.set_block(&[self.x, self.y, self.z], index+((self.x+ self.y + self.z) as usize)%4, Sides::all(true), true);
self.x+=1;
if self.x >= 16*20 {
self.x = 0;
self.y += 1;
if self.y > 63{
self.y = 0;
self.z += 1;
}
}
}
}
}
}
fn draw(&mut self, ctx: &mut Context) {
self.render_helper.begin_world(ctx);
let t = date::now();
ctx.apply_pipeline(&self.pipeline);
ctx.apply_bindings(&self.bindings);
let (w,h) = ctx.screen_size();
let mut proj_matrix = mat4::create();
mat4::perspective(&mut proj_matrix, 90.0f32.to_radians(), w as f32 / h as f32, 0.1, Some(10000.0));
let mut cammat = mat4::create();
let mut cammat1 = mat4::create();
mat4::identity(&mut cammat);
mat4::rotate_x(&mut cammat1, &cammat, -(self.player.rot[0] / 180. * PI));
mat4::rotate_y(&mut cammat, &cammat1, self.player.rot[1] / 180. * PI);
mat4::translate(&mut cammat1, &cammat, &[self.player.pos[0], -self.player.pos[1]- self.player.eyes, self.player.pos[2]]);
let mut view_matrix = mat4::create();
mat4::look_at(&mut view_matrix, &[0., 0., 0.], &[0., 0., 0.], &[0., 0., 0.]);
mat4::multiply(&mut cammat, &cammat1, &view_matrix);
ctx.apply_uniforms(&default_solid_shader::Uniforms {
proj: proj_matrix,
view: cammat,
fog: [140.0, 160.0]
});
if let Some(world) = self.game.get_world_im(self.player.world){
for (_,chunk) in &world.chunks {
for (b_type, inst) in &chunk.instances{
if let Some(b_t) = self.game.get_type(*b_type){
let tex = b_t.texture();
if let DrawType::All(ttt) = tex {
self.bindings.images[0] = *ttt;
ctx.apply_bindings(&self.bindings);
}
match inst {
Instances::Single(c) => {
if c.len() > 0{
self.bindings.vertex_buffers[1].update(ctx, &c);
ctx.draw(0, 36, c.len() as i32);
}
},
Instances::Sided(s) => {
for i in 0..6 {
let len = s[i].len() as i32;
if len > 0{
if let DrawType::Sides(ttt) = tex {
self.bindings.images[0] = ttt[i];
ctx.apply_bindings(&self.bindings);
}
self.bindings.vertex_buffers[1].update(ctx, &s[i]);
ctx.draw(6 * i as i32, 6, len);
}
}
},
}
}
}
}
}
self.render_helper.do_post_begin_ui(ctx);
let end = date::now();
self.t_fp = self.t_fp *0.9 + 0.1/(end-t);
// TODO: render 2D UI
self.render_helper.end_ui(ctx);
}
fn resize_event(&mut self, ctx: &mut Context, width: f32, height: f32) {
self.render_helper.resize(ctx, width, height);
}
fn key_down_event(&mut self, _ctx: &mut Context, keycode: KeyCode, _keymods: KeyMods,_repeatt: bool) {
if keycode == KeyCode::Space{
self.s_move.top = true;
}else if keycode == KeyCode::LeftShift{
self.s_move.bottom = true;
}else if keycode == KeyCode::W{
self.s_move.front = true;
}else if keycode == KeyCode::A{
self.s_move.left = true;
}else if keycode == KeyCode::S{
self.s_move.back = true;
}else if keycode == KeyCode::D{
self.s_move.right = true;
}
}
fn key_up_event(&mut self, ctx: &mut Context, keycode: KeyCode, _keymods: KeyMods) {
if keycode == KeyCode::F11 {
if self.fullscreen {
ctx.set_fullscreen(false);
ctx.set_window_size(900* 16 / 9, 900);
self.fullscreen = false;
}else {
ctx.set_fullscreen(true);
self.fullscreen = true;
}
if self.mouse_grab {
//println!("reloc");
ctx.set_cursor_grab(false);
ctx.show_mouse(true);
self.mouse_grab = false;
}
}else if keycode == KeyCode::Escape {
ctx.set_cursor_grab(false);
ctx.show_mouse(true);
self.mouse_grab = false;
}else if keycode == KeyCode::Space{
self.s_move.top = false;
}else if keycode == KeyCode::LeftShift{
self.s_move.bottom = false;
}else if keycode == KeyCode::W{
self.s_move.front = false;
}else if keycode == KeyCode::A{
self.s_move.left = false;
}else if keycode == KeyCode::S{
self.s_move.back = false;
}else if keycode == KeyCode::D{
self.s_move.right = false;
}else if keycode == KeyCode::F{
self.player.flying = !self.player.flying;
}
}
fn window_minimized_event(&mut self, ctx: &mut Context) {
ctx.set_cursor_grab(false);
ctx.show_mouse(true);
self.mouse_grab = false;
}
fn mouse_button_down_event(&mut self,ctx: &mut Context,button: MouseButton,_x: f32,_y: f32) {
if button == MouseButton::Left {
if !self.mouse_grab {
ctx.set_cursor_grab(true);
ctx.show_mouse(false);
self.mouse_grab = true;
}
}
}
fn raw_mouse_motion(&mut self, _ctx: &mut Context, x: f32, y: f32) {
if self.mouse_grab {
self.player.rotate(x, y);
}
}
fn touch_event(&mut self, ctx: &mut Context, phase: TouchPhase, _id: u64, x: f32, y: f32) {
}
}

71
src/tools.rs Normal file
View file

@ -0,0 +1,71 @@
use std::ops::Index;
use gl_matrix::common::*;
pub type WPos = [i32; 3];
#[derive(Debug)]
pub struct Sides<T: Copy + PartialEq> {
pub top: T,
pub bottom: T,
pub left: T,
pub right: T,
pub front: T,
pub back: T,
}
impl<T: Copy + PartialEq> Sides<T> {
pub fn all(v: T) -> Sides<T> {
Sides {
top: v,
bottom: v,
left: v,
right: v,
front: v,
back: v,
}
}
pub fn are_all(&self, v: T) -> bool {
self.top == v
&& self.bottom == v
&& self.left == v
&& self.right == v
&& self.front == v
&& self.back == v
}
}
impl<T: Copy + PartialEq> Index<usize> for Sides<T> {
type Output = T;
fn index(&self, i: usize) -> &Self::Output {
match i {
0 => {&self.top},
1 => {&self.bottom},
2 => {&self.left},
3 => {&self.right},
4 => {&self.front},
5 => {&self.back},
_ => {panic!("SidesOutOfBoundsException");}
}
}
}
#[repr(C)]
pub struct Vertex {
pub pos: Vec3,
pub uv: Vec2,
}
pub fn check_overlap(pos1: Vec3, pos2: Vec3, size1: Vec3, size2: Vec3) -> bool {
(pos1[0] - pos2[0]).abs() < (size1[0] + size2[0]) / 2.
&& (pos1[1] - pos2[1]).abs() < (size1[1] + size2[1]) / 2.
&& (pos1[2] - pos2[2]).abs() < (size1[2] + size2[2]) / 2.
}
#[derive(Debug)]
pub enum PrimitiveData {
String(String),
Number(i32),
Boolean(bool)
}

7
src/world_generator.rs Normal file
View file

@ -0,0 +1,7 @@
use crate::game::chunk::Chunk;
pub trait WorldGenerator {
fn generateChunk(&self, chunk: &mut Chunk);
}