mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
fix merge conflicts
Former-commit-id: 72614e5d57607a2095161857df45ce746e8c1b06
This commit is contained in:
commit
164feaa616
8
.gitignore
vendored
8
.gitignore
vendored
@ -15,9 +15,7 @@
|
||||
*.code-workspace
|
||||
|
||||
# Veloren
|
||||
**/server_conf.toml
|
||||
**/keybinds.toml
|
||||
**/settings.toml
|
||||
assets/voxygen
|
||||
voxygen/keybinds.toml
|
||||
settings.toml
|
||||
*.rar
|
||||
|
||||
*.log
|
||||
|
@ -10,12 +10,14 @@ variables:
|
||||
GIT_STRATEGY: none
|
||||
before_script:
|
||||
- mkdir -p /cache/veloren
|
||||
- rm -rf /cache/veloren/bin
|
||||
- cd /cache/veloren
|
||||
- if [ -d .git ]; then
|
||||
echo "is git dir";
|
||||
else
|
||||
git clone $CI_REPOSITORY_URL . ;
|
||||
fi;
|
||||
- mkdir -p /cache/veloren/bin
|
||||
- rm -f .git/index.lock
|
||||
- rm -f .git/shallow.lock
|
||||
- rm -f .git/HEAD.lock
|
||||
@ -28,7 +30,7 @@ before_script:
|
||||
git pull "https://gitlab.com/${SOURCE_PROJECT}/veloren.git" "${SOURCE_BRANCH}";
|
||||
fi;
|
||||
- git submodule sync --recursive
|
||||
- git submodule update --remote --recursive
|
||||
- git submodule update --init --recursive --depth 20
|
||||
- git status
|
||||
- if [ -d target ]; then
|
||||
ls -la target;
|
||||
@ -42,7 +44,7 @@ build-voxygen:
|
||||
stage: build
|
||||
image: registry.gitlab.com/veloren/veloren-docker-ci
|
||||
tags:
|
||||
- docker
|
||||
- veloren-docker
|
||||
script:
|
||||
- (cd voxygen && cargo build)
|
||||
|
||||
@ -50,7 +52,7 @@ build-server-cli:
|
||||
stage: build
|
||||
image: registry.gitlab.com/veloren/veloren-docker-ci
|
||||
tags:
|
||||
- docker
|
||||
- veloren-docker
|
||||
script:
|
||||
- (cd server-cli && cargo build)
|
||||
|
||||
@ -62,7 +64,7 @@ unittests:
|
||||
stage: test
|
||||
image: registry.gitlab.com/veloren/veloren-docker-ci
|
||||
tags:
|
||||
- docker
|
||||
- veloren-docker
|
||||
script:
|
||||
- cargo test
|
||||
|
||||
@ -70,7 +72,7 @@ benchmarktests:
|
||||
stage: test
|
||||
image: registry.gitlab.com/veloren/veloren-docker-ci
|
||||
tags:
|
||||
- docker
|
||||
- veloren-docker
|
||||
script:
|
||||
- cargo bench
|
||||
allow_failure: true
|
||||
@ -84,25 +86,27 @@ clean-code:
|
||||
stage: post-build
|
||||
image: registry.gitlab.com/veloren/veloren-docker-ci
|
||||
tags:
|
||||
- docker
|
||||
- veloren-docker
|
||||
script:
|
||||
- cargo fmt --all -- --check
|
||||
allow_failure: true
|
||||
|
||||
coverage:
|
||||
stage: post-build
|
||||
image: registry.gitlab.com/veloren/veloren-docker-ci
|
||||
tags:
|
||||
- docker
|
||||
script:
|
||||
- cargo tarpaulin --skip-clean --all || echo "There is a problem in tarpaulin which sometimes fails"
|
||||
allow_failure: true
|
||||
# # Coverage needs to be disabled until an issue in the Rust compiler is fixed
|
||||
# # https://github.com/rust-lang/rust/issues/58375
|
||||
# coverage:
|
||||
# stage: post-build
|
||||
# image: registry.gitlab.com/veloren/veloren-docker-ci
|
||||
# tags:
|
||||
# - veloren-docker
|
||||
# script:
|
||||
# - cargo tarpaulin --all
|
||||
# allow_failure: true
|
||||
|
||||
clippy:
|
||||
stage: post-build
|
||||
image: registry.gitlab.com/veloren/veloren-docker-ci
|
||||
tags:
|
||||
- docker
|
||||
- veloren-docker
|
||||
script:
|
||||
- cargo clippy --all -- -D clippy || echo "This job is disabled, because we are not activly using it now, so we dont want to see yellow failed partly"
|
||||
allow_failure: true
|
||||
@ -115,7 +119,7 @@ commit-linux-debug:
|
||||
stage: executable
|
||||
image: registry.gitlab.com/veloren/veloren-docker-ci
|
||||
tags:
|
||||
- docker
|
||||
- veloren-docker
|
||||
script:
|
||||
- (cd voxygen && VELOREN_ASSETS=assets cargo build)
|
||||
- (cd server-cli && VELOREN_ASSETS=assets cargo build)
|
||||
@ -125,9 +129,8 @@ commit-linux-debug:
|
||||
- cp target/debug/veloren-voxygen commit-build
|
||||
- cp -r assets commit-build/
|
||||
- cp -r voxygen/shaders commit-build/
|
||||
- rm -f commit-linux-debug.tar.bz2
|
||||
- tar -cvjSf commit-linux-debug.tar.bz2 commit-build
|
||||
- cp commit-linux-debug.tar.bz2 $CI_PROJECT_DIR
|
||||
- tar -cvjSf bin/commit-linux-debug.tar.bz2 commit-build
|
||||
- cp bin/commit-linux-debug.tar.bz2 $CI_PROJECT_DIR
|
||||
artifacts:
|
||||
paths:
|
||||
- commit-linux-debug.tar.bz2
|
||||
@ -137,13 +140,12 @@ commit-linux-debug:
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
- add-docker-gitlab-ci
|
||||
|
||||
commit-windows-debug:
|
||||
stage: executable
|
||||
image: registry.gitlab.com/veloren/veloren-docker-ci
|
||||
tags:
|
||||
- docker
|
||||
- veloren-docker
|
||||
script:
|
||||
- (cd voxygen && VELOREN_ASSETS=assets cargo build --target=x86_64-pc-windows-gnu)
|
||||
- (cd server-cli && VELOREN_ASSETS=assets cargo build --target=x86_64-pc-windows-gnu)
|
||||
@ -153,9 +155,8 @@ commit-windows-debug:
|
||||
- cp target/x86_64-pc-windows-gnu/debug/veloren-voxygen.exe commit-build
|
||||
- cp -r assets commit-build/
|
||||
- cp -r voxygen/shaders commit-build/
|
||||
- rm -f commit-windows-debug.zip
|
||||
- zip -r commit-windows-debug.zip commit-build
|
||||
- cp commit-windows-debug.zip $CI_PROJECT_DIR
|
||||
- zip -r bin/commit-windows-debug.zip commit-build
|
||||
- cp bin/commit-windows-debug.zip $CI_PROJECT_DIR
|
||||
artifacts:
|
||||
paths:
|
||||
- commit-windows-debug.zip
|
||||
@ -165,7 +166,6 @@ commit-windows-debug:
|
||||
only:
|
||||
refs:
|
||||
- master
|
||||
- add-docker-gitlab-ci
|
||||
|
||||
#############
|
||||
# NIGHTLY
|
||||
@ -175,7 +175,7 @@ nightly-linux-optimized:
|
||||
stage: executable
|
||||
image: registry.gitlab.com/veloren/veloren-docker-ci
|
||||
tags:
|
||||
- docker
|
||||
- veloren-docker
|
||||
script:
|
||||
- (cd voxygen && VELOREN_ASSETS=assets cargo build --release)
|
||||
- (cd server-cli && VELOREN_ASSETS=assets cargo build --release)
|
||||
@ -185,9 +185,8 @@ nightly-linux-optimized:
|
||||
- cp target/release/veloren-voxygen nightly-build
|
||||
- cp -r assets nightly-build/
|
||||
- cp -r voxygen/shaders nightly-build/
|
||||
- rm -f nightly-linux-optimized.tar.bz2
|
||||
- tar -cvjSf nightly-linux-optimized.tar.bz2 nightly-build
|
||||
- cp nightly-linux-optimized.zip $CI_PROJECT_DIR
|
||||
- tar -cvjSf bin/nightly-linux-optimized.tar.bz2 nightly-build
|
||||
- cp bin/nightly-linux-optimized.tar.bz2 $CI_PROJECT_DIR
|
||||
artifacts:
|
||||
paths:
|
||||
- nightly-linux-optimized.tar.bz2
|
||||
@ -199,7 +198,7 @@ nightly-windows-optimized:
|
||||
stage: executable
|
||||
image: registry.gitlab.com/veloren/veloren-docker-ci
|
||||
tags:
|
||||
- docker
|
||||
- veloren-docker
|
||||
script:
|
||||
- (cd voxygen && VELOREN_ASSETS=assets cargo build --release --target=x86_64-pc-windows-gnu)
|
||||
- (cd server-cli && VELOREN_ASSETS=assets cargo build --release --target=x86_64-pc-windows-gnu)
|
||||
@ -209,9 +208,8 @@ nightly-windows-optimized:
|
||||
- cp target/x86_64-pc-windows-gnu/release/veloren-voxygen.exe nightly-build
|
||||
- cp -r assets nightly-build/
|
||||
- cp -r voxygen/shaders nightly-build/
|
||||
- rm -f nightly-windows-optimized.zip
|
||||
- zip -r nightly-windows-optimized.zip nightly-build
|
||||
- cp nightly-windows-optimized.zip $CI_PROJECT_DIR
|
||||
- zip -r bin/nightly-windows-optimized.zip nightly-build
|
||||
- cp bin/nightly-windows-optimized.zip $CI_PROJECT_DIR
|
||||
artifacts:
|
||||
paths:
|
||||
- nightly-windows-optimized.zip
|
||||
|
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,4 +1,4 @@
|
||||
[submodule "assets/voxygen"]
|
||||
path = assets/voxygen
|
||||
url = https://gitlab.com/veloren/fresh-assets/voxygen.git
|
||||
url = ../../veloren/fresh-assets/voxygen.git
|
||||
shallow = true
|
||||
|
@ -2,6 +2,11 @@
|
||||
<img alt="Veloren logo on a screenshot" src="https://cdn.discordapp.com/attachments/449602562165833760/521121348886593547/veloren_image.png">
|
||||
</p>
|
||||
|
||||
[![pipeline status](https://gitlab.com/veloren/veloren/badges/master/pipeline.svg)](https://gitlab.com/veloren/veloren/commits/master)
|
||||
[![coverage report](https://gitlab.com/veloren/veloren/badges/master/coverage.svg)](https://gitlab.com/veloren/veloren/commits/master)
|
||||
[![license](https://img.shields.io/github/license/veloren/veloren.svg)](https://gitlab.com/veloren/veloren/blob/master/LICENSE)
|
||||
[![discord](https://img.shields.io/discord/449602562165833758.svg)](https://discord.gg/WEXSY9h)
|
||||
|
||||
## Welcome To Veloren!
|
||||
|
||||
Veloren is a multiplayer voxel RPG written in Rust. Veloren takes inspiration from games such as Cube World, Minecraft and Dwarf Fortress. The game is currently under heavy development, but is playable.
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 25346c1ead7d03b11f7f4403332f2288824c6ca9
|
||||
Subproject commit cff10b010db25ce9af5edbdfb5ef0af889dd741a
|
4
chat-cli/.gitignore
vendored
4
chat-cli/.gitignore
vendored
@ -1,4 +0,0 @@
|
||||
/target
|
||||
/assets
|
||||
**/*.rs.bk.rar
|
||||
Cargo.lock
|
@ -1,10 +1,7 @@
|
||||
use std::time::Duration;
|
||||
use client::{Client, Event, Input};
|
||||
use common::{clock::Clock, comp};
|
||||
use log::info;
|
||||
use client::{Input, Client, Event};
|
||||
use common::{
|
||||
comp,
|
||||
clock::Clock,
|
||||
};
|
||||
use std::time::Duration;
|
||||
|
||||
const FPS: u64 = 60;
|
||||
|
||||
@ -18,8 +15,8 @@ fn main() {
|
||||
let mut clock = Clock::new();
|
||||
|
||||
// Create client
|
||||
let mut client = Client::new(([127, 0, 0, 1], 59003), 300)
|
||||
.expect("Failed to create client instance");
|
||||
let mut client =
|
||||
Client::new(([127, 0, 0, 1], 59003), 300).expect("Failed to create client instance");
|
||||
|
||||
client.register(comp::Player::new("test".to_string()));
|
||||
|
||||
@ -31,7 +28,7 @@ fn main() {
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
break;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
for event in events {
|
||||
|
3
client/.gitignore
vendored
3
client/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
@ -249,9 +249,18 @@ impl Client {
|
||||
ServerMsg::Ping => self.postbox.send_message(ClientMsg::Pong),
|
||||
ServerMsg::Pong => {}
|
||||
ServerMsg::Chat(msg) => frontend_events.push(Event::Chat(msg)),
|
||||
ServerMsg::SetPlayerEntity(uid) => self.entity = self.state.ecs().entity_from_uid(uid).unwrap(), // TODO: Don't unwrap here!
|
||||
ServerMsg::EcsSync(sync_package) => self.state.ecs_mut().sync_with_package(sync_package),
|
||||
ServerMsg::EntityPhysics { entity, pos, vel, dir } => match self.state.ecs().entity_from_uid(entity) {
|
||||
ServerMsg::SetPlayerEntity(uid) => {
|
||||
self.entity = self.state.ecs().entity_from_uid(uid).unwrap()
|
||||
} // TODO: Don't unwrap here!
|
||||
ServerMsg::EcsSync(sync_package) => {
|
||||
self.state.ecs_mut().sync_with_package(sync_package)
|
||||
}
|
||||
ServerMsg::EntityPhysics {
|
||||
entity,
|
||||
pos,
|
||||
vel,
|
||||
dir,
|
||||
} => match self.state.ecs().entity_from_uid(entity) {
|
||||
Some(entity) => {
|
||||
self.state.write_component(entity, pos);
|
||||
self.state.write_component(entity, vel);
|
||||
@ -259,7 +268,10 @@ impl Client {
|
||||
}
|
||||
None => {}
|
||||
},
|
||||
ServerMsg::EntityAnimation { entity, animation_history } => match self.state.ecs().entity_from_uid(entity) {
|
||||
ServerMsg::EntityAnimation {
|
||||
entity,
|
||||
animation_history,
|
||||
} => match self.state.ecs().entity_from_uid(entity) {
|
||||
Some(entity) => {
|
||||
self.state.write_component(entity, animation_history);
|
||||
}
|
||||
|
3
common/.gitignore
vendored
3
common/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
@ -1,8 +1,8 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::fs::File;
|
||||
|
||||
fn try_load(name: &str) -> Option<File> {
|
||||
let basepaths = [
|
||||
@ -22,26 +22,29 @@ fn try_load(name: &str) -> Option<File> {
|
||||
Ok(f) => {
|
||||
debug!("loading {} succedeed", filename);
|
||||
return Some(f);
|
||||
},
|
||||
}
|
||||
Err(e) => {
|
||||
debug!("loading {} did not work with error: {}", filename, e);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
pub fn load(name: &str) -> Result<Vec<u8>,()> {
|
||||
pub fn load(name: &str) -> Result<Vec<u8>, ()> {
|
||||
return match try_load(name) {
|
||||
Some(mut f) => {
|
||||
let mut content: Vec<u8> = vec!();
|
||||
let mut content: Vec<u8> = vec![];
|
||||
f.read_to_end(&mut content);
|
||||
info!("loaded asset successful: {}", name);
|
||||
Ok(content)
|
||||
},
|
||||
}
|
||||
None => {
|
||||
warn!("Loading asset failed, wanted to load {} but could not load it, check debug log!", name);
|
||||
warn!(
|
||||
"Loading asset failed, wanted to load {} but could not load it, check debug log!",
|
||||
name
|
||||
);
|
||||
Err(())
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -23,13 +23,19 @@ impl Clock {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_tps(&self) -> f64 { 1.0 / self.running_tps_average }
|
||||
pub fn get_tps(&self) -> f64 {
|
||||
1.0 / self.running_tps_average
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_last_delta(&self) -> Duration { self.last_delta.unwrap_or(Duration::new(0, 0)) }
|
||||
pub fn get_last_delta(&self) -> Duration {
|
||||
self.last_delta.unwrap_or(Duration::new(0, 0))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_avg_delta(&self) -> Duration { Duration::from_secs_f64(self.running_tps_average) }
|
||||
pub fn get_avg_delta(&self) -> Duration {
|
||||
Duration::from_secs_f64(self.running_tps_average)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn tick(&mut self, tgt: Duration) {
|
||||
@ -44,7 +50,9 @@ impl Clock {
|
||||
} else {
|
||||
tgt.as_secs_f64() / self.running_tps_average
|
||||
};
|
||||
thread::sleep(Duration::from_secs_f64(sleep_dur.as_secs_f64() * adjustment));
|
||||
thread::sleep(Duration::from_secs_f64(
|
||||
sleep_dur.as_secs_f64() * adjustment,
|
||||
));
|
||||
}
|
||||
|
||||
let delta = SystemTime::now()
|
||||
@ -56,8 +64,8 @@ impl Clock {
|
||||
self.running_tps_average = if self.running_tps_average == 0.0 {
|
||||
delta.as_secs_f64()
|
||||
} else {
|
||||
CLOCK_SMOOTHING * self.running_tps_average +
|
||||
(1.0 - CLOCK_SMOOTHING) * delta.as_secs_f64()
|
||||
CLOCK_SMOOTHING * self.running_tps_average
|
||||
+ (1.0 - CLOCK_SMOOTHING) * delta.as_secs_f64()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use specs::{Component, VecStorage, FlaggedStorage};
|
||||
use vek::*;
|
||||
use rand::prelude::*;
|
||||
use specs::{Component, FlaggedStorage, VecStorage};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Race {
|
||||
@ -60,14 +60,14 @@ pub enum Weapon {
|
||||
Staff,
|
||||
}
|
||||
|
||||
use Race::*;
|
||||
use Gender::*;
|
||||
use Head::*;
|
||||
use Chest::*;
|
||||
use Belt::*;
|
||||
use Pants::*;
|
||||
use Hand::*;
|
||||
use Chest::*;
|
||||
use Foot::*;
|
||||
use Gender::*;
|
||||
use Hand::*;
|
||||
use Head::*;
|
||||
use Pants::*;
|
||||
use Race::*;
|
||||
use Weapon::*;
|
||||
|
||||
const ALL_RACES: [Race; 6] = [Danari, Dwarf, Elf, Human, Orc, Undead];
|
||||
|
@ -1,11 +1,11 @@
|
||||
pub mod agent;
|
||||
pub mod character;
|
||||
pub mod player;
|
||||
pub mod phys;
|
||||
pub mod player;
|
||||
|
||||
// Reexports
|
||||
pub use agent::{Agent, Control};
|
||||
pub use character::Animation;
|
||||
pub use character::AnimationHistory;
|
||||
pub use character::Character;
|
||||
pub use player::Player;
|
||||
pub use character::AnimationHistory;
|
||||
pub use character::Animation;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use specs::{Component, VecStorage, FlaggedStorage, NullStorage};
|
||||
use specs::{Component, FlaggedStorage, NullStorage, VecStorage};
|
||||
use vek::*;
|
||||
|
||||
// Pos
|
||||
|
@ -1,4 +1,4 @@
|
||||
use specs::{Component, VecStorage, FlaggedStorage};
|
||||
use specs::{Component, FlaggedStorage, VecStorage};
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Player {
|
||||
@ -7,9 +7,7 @@ pub struct Player {
|
||||
|
||||
impl Player {
|
||||
pub fn new(alias: String) -> Self {
|
||||
Self {
|
||||
alias,
|
||||
}
|
||||
Self { alias }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
pub mod cell;
|
||||
|
||||
// Library
|
||||
use vek::*;
|
||||
use dot_vox::DotVoxData;
|
||||
use vek::*;
|
||||
|
||||
// Crate
|
||||
use crate::{
|
||||
@ -28,11 +28,7 @@ impl From<DotVoxData> for Segment {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut segment = Segment::filled(
|
||||
Vec3::new(
|
||||
model.size.x,
|
||||
model.size.y,
|
||||
model.size.z,
|
||||
),
|
||||
Vec3::new(model.size.x, model.size.y, model.size.z),
|
||||
Cell::empty(),
|
||||
(),
|
||||
);
|
||||
|
@ -1,4 +1,9 @@
|
||||
#![feature(euclidean_division, duration_float, trait_alias, bind_by_move_pattern_guards)]
|
||||
#![feature(
|
||||
euclidean_division,
|
||||
duration_float,
|
||||
trait_alias,
|
||||
bind_by_move_pattern_guards
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
@ -10,13 +15,13 @@ pub mod clock;
|
||||
pub mod comp;
|
||||
pub mod figure;
|
||||
pub mod msg;
|
||||
pub mod ray;
|
||||
pub mod state;
|
||||
pub mod sys;
|
||||
pub mod terrain;
|
||||
pub mod util;
|
||||
pub mod volumes;
|
||||
pub mod vol;
|
||||
pub mod ray;
|
||||
pub mod volumes;
|
||||
|
||||
// TODO: unignore the code here, for some reason it refuses to compile here while has no problems copy-pasted elsewhere
|
||||
/// The networking module containing high-level wrappers of `TcpListener` and `TcpStream` (`PostOffice` and `PostBox` respectively) and data types used by both the server and client
|
||||
|
@ -1,10 +1,12 @@
|
||||
use vek::*;
|
||||
use super::ClientState;
|
||||
use crate::comp;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum ClientMsg {
|
||||
Register { player: comp::Player },
|
||||
Register {
|
||||
player: comp::Player,
|
||||
},
|
||||
Character(comp::Character),
|
||||
RequestState(ClientState),
|
||||
Ping,
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::marker::PhantomData;
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
use crate::comp;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// Automatically derive From<T> for Packet for each variant Packet::T(T)
|
||||
sphynx::sum_type! {
|
||||
|
@ -1,11 +1,11 @@
|
||||
pub mod client;
|
||||
pub mod ecs_packet;
|
||||
pub mod server;
|
||||
pub mod client;
|
||||
|
||||
// Reexports
|
||||
pub use self::server::{ServerMsg, RequestStateError};
|
||||
pub use self::client::ClientMsg;
|
||||
pub use self::ecs_packet::EcsPacket;
|
||||
pub use self::server::{RequestStateError, ServerMsg};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
pub enum ClientState {
|
||||
|
@ -1,9 +1,6 @@
|
||||
use super::{ClientState, EcsPacket};
|
||||
use crate::{comp, terrain::TerrainChunk};
|
||||
use vek::*;
|
||||
use crate::{
|
||||
comp,
|
||||
terrain::TerrainChunk,
|
||||
};
|
||||
use super::{EcsPacket, ClientState};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum RequestStateError {
|
||||
|
@ -7,11 +7,7 @@ pub use post2 as post;
|
||||
// Reexports
|
||||
pub use self::{
|
||||
data::{ClientMsg, ServerMsg},
|
||||
post::{
|
||||
Error as PostError,
|
||||
PostBox,
|
||||
PostOffice,
|
||||
},
|
||||
post::{Error as PostError, PostBox, PostOffice},
|
||||
};
|
||||
|
||||
pub trait PostSend = 'static + serde::Serialize + std::marker::Send + std::fmt::Debug;
|
||||
|
@ -1,14 +1,17 @@
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use std::{
|
||||
io::{self, Read, Write},
|
||||
net::{TcpListener, TcpStream, SocketAddr, Shutdown},
|
||||
time::{Instant, Duration},
|
||||
marker::PhantomData,
|
||||
sync::{mpsc, Arc, atomic::{AtomicBool, Ordering}},
|
||||
thread,
|
||||
collections::VecDeque,
|
||||
convert::TryFrom,
|
||||
io::{self, Read, Write},
|
||||
marker::PhantomData,
|
||||
net::{Shutdown, SocketAddr, TcpListener, TcpStream},
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
mpsc, Arc,
|
||||
},
|
||||
thread,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Error {
|
||||
@ -62,7 +65,7 @@ impl<S: PostMsg, R: PostMsg> PostOffice<S, R> {
|
||||
self.error.clone()
|
||||
}
|
||||
|
||||
pub fn new_postboxes(&mut self) -> impl ExactSizeIterator<Item=PostBox<S, R>> {
|
||||
pub fn new_postboxes(&mut self) -> impl ExactSizeIterator<Item = PostBox<S, R>> {
|
||||
let mut new = Vec::new();
|
||||
|
||||
if self.error.is_some() {
|
||||
@ -73,11 +76,11 @@ impl<S: PostMsg, R: PostMsg> PostOffice<S, R> {
|
||||
match self.listener.accept() {
|
||||
Ok((stream, sock)) => new.push(PostBox::from_stream(stream).unwrap()),
|
||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
|
||||
Err(e) if e.kind() == io::ErrorKind::Interrupted => {},
|
||||
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||
Err(e) => {
|
||||
self.error = Some(e.into());
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,11 +139,11 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
Err(e) => {
|
||||
self.error = Some(e);
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_messages(&mut self) -> impl ExactSizeIterator<Item=R> {
|
||||
pub fn new_messages(&mut self) -> impl ExactSizeIterator<Item = R> {
|
||||
let mut new = Vec::new();
|
||||
|
||||
if self.error.is_some() {
|
||||
@ -154,18 +157,23 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
Err(e) => {
|
||||
self.error = Some(e.into());
|
||||
break;
|
||||
},
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
self.error = Some(e);
|
||||
break;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new.into_iter()
|
||||
}
|
||||
|
||||
fn worker(mut stream: TcpStream, send_rx: mpsc::Receiver<S>, recv_tx: mpsc::Sender<Result<R, Error>>, running: Arc<AtomicBool>) {
|
||||
fn worker(
|
||||
mut stream: TcpStream,
|
||||
send_rx: mpsc::Receiver<S>,
|
||||
recv_tx: mpsc::Sender<Result<R, Error>>,
|
||||
running: Arc<AtomicBool>,
|
||||
) {
|
||||
let mut outgoing_chunks = VecDeque::new();
|
||||
let mut incoming_buf = Vec::new();
|
||||
|
||||
@ -176,8 +184,8 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
Ok(Some(e)) | Err(e) => {
|
||||
recv_tx.send(Err(e.into())).unwrap();
|
||||
break 'work;
|
||||
},
|
||||
Ok(None) => {},
|
||||
}
|
||||
Ok(None) => {}
|
||||
}
|
||||
|
||||
// Try getting messages from the send channel
|
||||
@ -188,11 +196,7 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
let mut msg_bytes = bincode::serialize(&send_msg).unwrap();
|
||||
|
||||
// Assemble into packet
|
||||
let mut packet_bytes = msg_bytes
|
||||
.len()
|
||||
.to_le_bytes()
|
||||
.as_ref()
|
||||
.to_vec();
|
||||
let mut packet_bytes = msg_bytes.len().to_le_bytes().as_ref().to_vec();
|
||||
packet_bytes.append(&mut msg_bytes);
|
||||
|
||||
// Split packet into chunks
|
||||
@ -200,13 +204,13 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
.chunks(4096)
|
||||
.map(|chunk| chunk.to_vec())
|
||||
.for_each(|chunk| outgoing_chunks.push_back(chunk))
|
||||
},
|
||||
}
|
||||
Err(mpsc::TryRecvError::Empty) => break,
|
||||
// Worker error
|
||||
Err(e) => {
|
||||
let _ = recv_tx.send(Err(e.into()));
|
||||
break 'work;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,17 +222,17 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
Ok(n) => {
|
||||
outgoing_chunks.push_front(chunk.split_off(n));
|
||||
break;
|
||||
},
|
||||
}
|
||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
|
||||
// Return chunk to the queue to try again later
|
||||
outgoing_chunks.push_front(chunk);
|
||||
break;
|
||||
},
|
||||
}
|
||||
// Worker error
|
||||
Err(e) => {
|
||||
recv_tx.send(Err(e.into())).unwrap();
|
||||
break 'work;
|
||||
},
|
||||
}
|
||||
},
|
||||
None => break,
|
||||
}
|
||||
@ -241,12 +245,12 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
match stream.read(&mut buf) {
|
||||
Ok(n) => incoming_buf.extend_from_slice(&buf[0..n]),
|
||||
Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
|
||||
Err(e) if e.kind() == io::ErrorKind::Interrupted => {},
|
||||
Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||
// Worker error
|
||||
Err(e) => {
|
||||
recv_tx.send(Err(e.into())).unwrap();
|
||||
break 'work;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,16 +266,14 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
|
||||
} else if incoming_buf.len() >= len + 8 {
|
||||
match bincode::deserialize(&incoming_buf[8..len + 8]) {
|
||||
Ok(msg) => recv_tx.send(Ok(msg)).unwrap(),
|
||||
Err(err) => {
|
||||
recv_tx.send(Err(err.into())).unwrap()
|
||||
},
|
||||
Err(err) => recv_tx.send(Err(err.into())).unwrap(),
|
||||
}
|
||||
|
||||
incoming_buf = incoming_buf.split_off(len + 8);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
}
|
||||
@ -295,7 +297,9 @@ impl<S: PostMsg, R: PostMsg> Drop for PostBox<S, R> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn create_postoffice<S: PostMsg, R: PostMsg>(id: u16) -> Result<(PostOffice<S, R>, SocketAddr), Error> {
|
||||
fn create_postoffice<S: PostMsg, R: PostMsg>(
|
||||
id: u16,
|
||||
) -> Result<(PostOffice<S, R>, SocketAddr), Error> {
|
||||
let sock = ([0; 4], 12345 + id).into();
|
||||
Ok((PostOffice::bind(sock)?, sock))
|
||||
}
|
||||
@ -353,9 +357,9 @@ mod tests {
|
||||
}
|
||||
|
||||
let mut recv_msgs = Vec::new();
|
||||
loop_for(Duration::from_millis(250), || server
|
||||
.new_messages()
|
||||
.for_each(|msg| recv_msgs.push(msg)));
|
||||
loop_for(Duration::from_millis(250), || {
|
||||
server.new_messages().for_each(|msg| recv_msgs.push(msg))
|
||||
});
|
||||
|
||||
assert_eq!(test_msgs, recv_msgs);
|
||||
}
|
||||
@ -363,7 +367,9 @@ mod tests {
|
||||
#[test]
|
||||
fn send_recv_huge() {
|
||||
let (mut postoffice, sock) = create_postoffice::<(), Vec<i32>>(3).unwrap();
|
||||
let test_msgs: Vec<Vec<i32>> = (0..5).map(|i| (0..100000).map(|j| i * 2 + j).collect()).collect();
|
||||
let test_msgs: Vec<Vec<i32>> = (0..5)
|
||||
.map(|i| (0..100000).map(|j| i * 2 + j).collect())
|
||||
.collect();
|
||||
|
||||
let mut client = PostBox::<Vec<i32>, ()>::to(sock).unwrap();
|
||||
loop_for(Duration::from_millis(250), || ());
|
||||
@ -374,9 +380,9 @@ mod tests {
|
||||
}
|
||||
|
||||
let mut recv_msgs = Vec::new();
|
||||
loop_for(Duration::from_millis(3000), || server
|
||||
.new_messages()
|
||||
.for_each(|msg| recv_msgs.push(msg)));
|
||||
loop_for(Duration::from_millis(3000), || {
|
||||
server.new_messages().for_each(|msg| recv_msgs.push(msg))
|
||||
});
|
||||
|
||||
assert_eq!(test_msgs.len(), recv_msgs.len());
|
||||
assert!(test_msgs == recv_msgs);
|
||||
|
@ -1,8 +1,5 @@
|
||||
use crate::vol::{ReadVol, Vox};
|
||||
use vek::*;
|
||||
use crate::vol::{
|
||||
Vox,
|
||||
ReadVol,
|
||||
};
|
||||
|
||||
pub trait RayUntil<V: Vox> = FnMut(&V) -> bool;
|
||||
|
||||
@ -26,10 +23,7 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
|
||||
}
|
||||
|
||||
pub fn until(self, f: F) -> Ray<'a, V, F> {
|
||||
Ray {
|
||||
until: f,
|
||||
..self
|
||||
}
|
||||
Ray { until: f, ..self }
|
||||
}
|
||||
|
||||
pub fn max_iter(mut self, max_iter: usize) -> Self {
|
||||
@ -52,19 +46,14 @@ impl<'a, V: ReadVol, F: RayUntil<V::Vox>> Ray<'a, V, F> {
|
||||
pos = self.from + dir * dist;
|
||||
ipos = pos.map(|e| e as i32);
|
||||
|
||||
match self.vol
|
||||
.get(ipos)
|
||||
.map(|vox| (vox, (self.until)(vox)))
|
||||
{
|
||||
match self.vol.get(ipos).map(|vox| (vox, (self.until)(vox))) {
|
||||
Ok((vox, true)) => return (dist, Ok(Some(vox))),
|
||||
Ok((_, false)) => {},
|
||||
Ok((_, false)) => {}
|
||||
Err(err) => return (dist, Err(err)),
|
||||
}
|
||||
|
||||
let deltas = (
|
||||
dir.map(|e| if e < 0.0 { 0.0 } else { 1.0 }) -
|
||||
pos.map(|e| e.fract())
|
||||
) / dir;
|
||||
let deltas =
|
||||
(dir.map(|e| if e < 0.0 { 0.0 } else { 1.0 }) - pos.map(|e| e.fract())) / dir;
|
||||
|
||||
dist += deltas.reduce(f32::min).max(PLANCK);
|
||||
}
|
||||
|
@ -1,34 +1,21 @@
|
||||
// Reexports
|
||||
pub use sphynx::Uid;
|
||||
|
||||
use std::{
|
||||
time::Duration,
|
||||
collections::HashSet,
|
||||
use crate::{
|
||||
comp,
|
||||
msg::EcsPacket,
|
||||
sys,
|
||||
terrain::{TerrainChunk, TerrainMap},
|
||||
};
|
||||
use shred::{Fetch, FetchMut};
|
||||
use specs::{
|
||||
Builder,
|
||||
Component,
|
||||
DispatcherBuilder,
|
||||
EntityBuilder as EcsEntityBuilder,
|
||||
Entity as EcsEntity,
|
||||
storage::{
|
||||
Storage as EcsStorage,
|
||||
MaskedStorage as EcsMaskedStorage,
|
||||
},
|
||||
saveload::{MarkedBuilder, MarkerAllocator},
|
||||
storage::{MaskedStorage as EcsMaskedStorage, Storage as EcsStorage},
|
||||
Builder, Component, DispatcherBuilder, Entity as EcsEntity, EntityBuilder as EcsEntityBuilder,
|
||||
};
|
||||
use sphynx;
|
||||
use std::{collections::HashSet, time::Duration};
|
||||
use vek::*;
|
||||
use crate::{
|
||||
comp,
|
||||
sys,
|
||||
terrain::{
|
||||
TerrainMap,
|
||||
TerrainChunk,
|
||||
},
|
||||
msg::EcsPacket,
|
||||
};
|
||||
|
||||
/// How much faster should an in-game day be compared to a real day?
|
||||
// TODO: Don't hard-code this
|
||||
@ -85,7 +72,11 @@ impl State {
|
||||
/// Create a new `State` from an ECS state package
|
||||
pub fn from_state_package(state_package: sphynx::StatePackage<EcsPacket>) -> Self {
|
||||
Self {
|
||||
ecs: sphynx::World::from_state_package(specs::World::new(), Self::setup_sphynx_world, state_package),
|
||||
ecs: sphynx::World::from_state_package(
|
||||
specs::World::new(),
|
||||
Self::setup_sphynx_world,
|
||||
state_package,
|
||||
),
|
||||
changes: Changes::default(),
|
||||
}
|
||||
}
|
||||
@ -113,7 +104,8 @@ impl State {
|
||||
|
||||
/// Register a component with the state's ECS
|
||||
pub fn with_component<T: Component>(mut self) -> Self
|
||||
where <T as Component>::Storage: Default
|
||||
where
|
||||
<T as Component>::Storage: Default,
|
||||
{
|
||||
self.ecs.register::<T>();
|
||||
self
|
||||
@ -166,13 +158,13 @@ impl State {
|
||||
|
||||
/// Get a reference to this state's terrain.
|
||||
pub fn terrain(&self) -> Fetch<TerrainMap> {
|
||||
self.ecs
|
||||
.read_resource::<TerrainMap>()
|
||||
self.ecs.read_resource::<TerrainMap>()
|
||||
}
|
||||
|
||||
/// Insert the provided chunk into this state's terrain.
|
||||
pub fn insert_chunk(&mut self, key: Vec3<i32>, chunk: TerrainChunk) {
|
||||
if self.ecs
|
||||
if self
|
||||
.ecs
|
||||
.write_resource::<TerrainMap>()
|
||||
.insert(key, chunk)
|
||||
.is_some()
|
||||
@ -185,7 +177,8 @@ impl State {
|
||||
|
||||
/// Remove the chunk with the given key from this state's terrain, if it exists
|
||||
pub fn remove_chunk(&mut self, key: Vec3<i32>) {
|
||||
if self.ecs
|
||||
if self
|
||||
.ecs
|
||||
.write_resource::<TerrainMap>()
|
||||
.remove(key)
|
||||
.is_some()
|
||||
|
@ -3,7 +3,7 @@ use specs::{Join, Read, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
// Crate
|
||||
use crate::comp::{Agent, Control, phys::Pos};
|
||||
use crate::comp::{phys::Pos, Agent, Control};
|
||||
|
||||
// Basic ECS AI agent system
|
||||
pub struct Sys;
|
||||
@ -22,12 +22,14 @@ impl<'a> System<'a> for Sys {
|
||||
*bearing += Vec2::new(
|
||||
rand::random::<f32>().fract() - 0.5,
|
||||
rand::random::<f32>().fract() - 0.5,
|
||||
) * 0.1 - *bearing * 0.01 - pos.0 * 0.0002;
|
||||
) * 0.1
|
||||
- *bearing * 0.01
|
||||
- pos.0 * 0.0002;
|
||||
|
||||
if bearing.magnitude_squared() != 0.0 {
|
||||
control.move_dir = bearing.normalized();
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,12 @@
|
||||
// Library
|
||||
use specs::{Join, Read, ReadStorage, System, WriteStorage, Entities};
|
||||
use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
// Crate
|
||||
use crate::comp::{Control, Animation, AnimationHistory, phys::{Pos, Vel, Dir}};
|
||||
use crate::comp::{
|
||||
phys::{Dir, Pos, Vel},
|
||||
Animation, AnimationHistory, Control,
|
||||
};
|
||||
|
||||
// Basic ECS AI agent system
|
||||
pub struct Sys;
|
||||
@ -18,25 +21,29 @@ impl<'a> System<'a> for Sys {
|
||||
);
|
||||
|
||||
fn run(&mut self, (entities, mut vels, mut dirs, mut anims, controls): Self::SystemData) {
|
||||
for (entity, mut vel, mut dir, control) in (&entities, &mut vels, &mut dirs, &controls).join() {
|
||||
for (entity, mut vel, mut dir, control) in
|
||||
(&entities, &mut vels, &mut dirs, &controls).join()
|
||||
{
|
||||
// TODO: Don't hard-code this
|
||||
// Apply physics to the player: acceleration and non-linear decceleration
|
||||
vel.0 += control.move_dir * 2.0 - vel.0.map(|e| e * e.abs() + e) * 0.03;
|
||||
|
||||
let animation =
|
||||
if control.move_dir.magnitude() > 0.01 {
|
||||
dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
|
||||
Animation::Run
|
||||
} else {
|
||||
Animation::Idle
|
||||
};
|
||||
let animation = if control.move_dir.magnitude() > 0.01 {
|
||||
dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
|
||||
Animation::Run
|
||||
} else {
|
||||
Animation::Idle
|
||||
};
|
||||
|
||||
let last_animation = anims.get_mut(entity).map(|h| h.current);
|
||||
|
||||
anims.insert(entity, AnimationHistory {
|
||||
last: last_animation,
|
||||
current: animation,
|
||||
});
|
||||
anims.insert(
|
||||
entity,
|
||||
AnimationHistory {
|
||||
last: last_animation,
|
||||
current: animation,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
use vek::*;
|
||||
use specs::{Join, Read, ReadStorage, System, WriteStorage, ReadExpect};
|
||||
use crate::{
|
||||
comp::phys::{Pos, Vel},
|
||||
state::DeltaTime,
|
||||
terrain::TerrainMap,
|
||||
vol::{Vox, ReadVol},
|
||||
vol::{ReadVol, Vox},
|
||||
};
|
||||
use specs::{Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
|
||||
use vek::*;
|
||||
|
||||
// Basic ECS physics system
|
||||
pub struct Sys;
|
||||
@ -33,8 +33,8 @@ impl<'a> System<'a> for Sys {
|
||||
while terrain
|
||||
.get(pos.0.map(|e| e.floor() as i32))
|
||||
.map(|vox| !vox.is_empty())
|
||||
.unwrap_or(false) &&
|
||||
i < 80
|
||||
.unwrap_or(false)
|
||||
&& i < 80
|
||||
{
|
||||
pos.0.z += 0.005;
|
||||
vel.0.z = 0.0;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum BiomeKind {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
|
||||
// Crate
|
||||
use crate::vol::Vox;
|
||||
|
@ -1,21 +1,15 @@
|
||||
pub mod block;
|
||||
pub mod biome;
|
||||
pub mod block;
|
||||
|
||||
// Reexports
|
||||
pub use self::{
|
||||
block::Block,
|
||||
biome::BiomeKind,
|
||||
};
|
||||
pub use self::{biome::BiomeKind, block::Block};
|
||||
|
||||
use vek::*;
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
use crate::{
|
||||
vol::VolSize,
|
||||
volumes::{
|
||||
vol_map::VolMap,
|
||||
chunk::Chunk,
|
||||
},
|
||||
volumes::{chunk::Chunk, vol_map::VolMap},
|
||||
};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
|
||||
// TerrainChunkSize
|
||||
|
||||
@ -23,7 +17,11 @@ use crate::{
|
||||
pub struct TerrainChunkSize;
|
||||
|
||||
impl VolSize for TerrainChunkSize {
|
||||
const SIZE: Vec3<u32> = Vec3 { x: 32, y: 32, z: 32 };
|
||||
const SIZE: Vec3<u32> = Vec3 {
|
||||
x: 32,
|
||||
y: 32,
|
||||
z: 32,
|
||||
};
|
||||
}
|
||||
|
||||
// TerrainChunkMeta
|
||||
|
@ -1,5 +1,5 @@
|
||||
use vek::*;
|
||||
use crate::ray::{Ray, RayUntil};
|
||||
use vek::*;
|
||||
|
||||
/// A voxel
|
||||
pub trait Vox {
|
||||
@ -66,14 +66,18 @@ pub trait ReadVol: BaseVol {
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Err>;
|
||||
|
||||
fn ray(&self, from: Vec3<f32>, to: Vec3<f32>) -> Ray<Self, fn(&Self::Vox) -> bool>
|
||||
where Self: Sized
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Ray::new(self, from, to, |vox| !vox.is_empty())
|
||||
}
|
||||
}
|
||||
|
||||
/// A volume that provides the ability to sample (i.e: clone a section of) its voxel data.
|
||||
pub trait SampleVol: BaseVol where Self::Vox: Clone {
|
||||
pub trait SampleVol: BaseVol
|
||||
where
|
||||
Self::Vox: Clone,
|
||||
{
|
||||
type Sample: BaseVol + ReadVol;
|
||||
/// Take a sample of the volume by cloning voxels within the provided range.
|
||||
///
|
||||
|
@ -2,18 +2,11 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// Library
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use vek::*;
|
||||
use serde_derive::{Serialize, Deserialize};
|
||||
|
||||
// Local
|
||||
use crate::vol::{
|
||||
Vox,
|
||||
BaseVol,
|
||||
SizedVol,
|
||||
ReadVol,
|
||||
WriteVol,
|
||||
VolSize,
|
||||
};
|
||||
use crate::vol::{BaseVol, ReadVol, SizedVol, VolSize, Vox, WriteVol};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ChunkErr {
|
||||
@ -36,15 +29,13 @@ impl<V: Vox, S: VolSize, M> Chunk<V, S, M> {
|
||||
// array.
|
||||
#[inline(always)]
|
||||
fn idx_for(pos: Vec3<i32>) -> Option<usize> {
|
||||
if
|
||||
pos.map(|e| e >= 0).reduce_and() &&
|
||||
pos.map2(S::SIZE, |e, lim| e < lim as i32).reduce_and()
|
||||
if pos.map(|e| e >= 0).reduce_and()
|
||||
&& pos.map2(S::SIZE, |e, lim| e < lim as i32).reduce_and()
|
||||
{
|
||||
Some((
|
||||
pos.x * S::SIZE.y as i32 * S::SIZE.z as i32 +
|
||||
pos.y * S::SIZE.z as i32 +
|
||||
pos.z
|
||||
) as usize)
|
||||
Some(
|
||||
(pos.x * S::SIZE.y as i32 * S::SIZE.z as i32 + pos.y * S::SIZE.z as i32 + pos.z)
|
||||
as usize,
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -58,7 +49,9 @@ impl<V: Vox, S: VolSize, M> BaseVol for Chunk<V, S, M> {
|
||||
|
||||
impl<V: Vox, S: VolSize, M> SizedVol for Chunk<V, S, M> {
|
||||
#[inline(always)]
|
||||
fn get_size(&self) -> Vec3<u32> { S::SIZE }
|
||||
fn get_size(&self) -> Vec3<u32> {
|
||||
S::SIZE
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Vox, S: VolSize, M> ReadVol for Chunk<V, S, M> {
|
||||
|
@ -2,13 +2,7 @@
|
||||
use vek::*;
|
||||
|
||||
// Local
|
||||
use crate::vol::{
|
||||
Vox,
|
||||
BaseVol,
|
||||
SizedVol,
|
||||
ReadVol,
|
||||
WriteVol,
|
||||
};
|
||||
use crate::vol::{BaseVol, ReadVol, SizedVol, Vox, WriteVol};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DynaErr {
|
||||
@ -30,15 +24,8 @@ impl<V: Vox, M> Dyna<V, M> {
|
||||
// array.
|
||||
#[inline(always)]
|
||||
fn idx_for(sz: Vec3<u32>, pos: Vec3<i32>) -> Option<usize> {
|
||||
if
|
||||
pos.map(|e| e >= 0).reduce_and() &&
|
||||
pos.map2(sz, |e, lim| e < lim as i32).reduce_and()
|
||||
{
|
||||
Some((
|
||||
pos.x * sz.y as i32 * sz.z as i32 +
|
||||
pos.y * sz.z as i32 +
|
||||
pos.z
|
||||
) as usize)
|
||||
if pos.map(|e| e >= 0).reduce_and() && pos.map2(sz, |e, lim| e < lim as i32).reduce_and() {
|
||||
Some((pos.x * sz.y as i32 * sz.z as i32 + pos.y * sz.z as i32 + pos.z) as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -52,7 +39,9 @@ impl<V: Vox, M> BaseVol for Dyna<V, M> {
|
||||
|
||||
impl<V: Vox, M> SizedVol for Dyna<V, M> {
|
||||
#[inline(always)]
|
||||
fn get_size(&self) -> Vec3<u32> { self.sz }
|
||||
fn get_size(&self) -> Vec3<u32> {
|
||||
self.sz
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: Vox, M> ReadVol for Dyna<V, M> {
|
||||
|
@ -1,3 +1,3 @@
|
||||
pub mod dyna;
|
||||
pub mod chunk;
|
||||
pub mod dyna;
|
||||
pub mod vol_map;
|
||||
|
@ -6,15 +6,7 @@ use vek::*;
|
||||
|
||||
// Crate
|
||||
use crate::{
|
||||
vol::{
|
||||
Vox,
|
||||
BaseVol,
|
||||
SizedVol,
|
||||
ReadVol,
|
||||
SampleVol,
|
||||
WriteVol,
|
||||
VolSize,
|
||||
},
|
||||
vol::{BaseVol, ReadVol, SampleVol, SizedVol, VolSize, Vox, WriteVol},
|
||||
volumes::{
|
||||
chunk::{Chunk, ChunkErr},
|
||||
dyna::{Dyna, DynaErr},
|
||||
@ -56,7 +48,8 @@ impl<V: Vox, S: VolSize, M> ReadVol for VolMap<V, S, M> {
|
||||
#[inline(always)]
|
||||
fn get(&self, pos: Vec3<i32>) -> Result<&V, VolMapErr> {
|
||||
let ck = Self::chunk_key(pos);
|
||||
self.chunks.get(&ck)
|
||||
self.chunks
|
||||
.get(&ck)
|
||||
.ok_or(VolMapErr::NoSuchChunk)
|
||||
.and_then(|chunk| {
|
||||
let co = Self::chunk_offs(pos);
|
||||
@ -87,14 +80,16 @@ impl<V: Vox + Clone, S: VolSize, M> SampleVol for VolMap<V, S, M> {
|
||||
}
|
||||
*/
|
||||
|
||||
let mut sample = Dyna::filled(
|
||||
range.size().map(|e| e as u32).into(),
|
||||
V::empty(),
|
||||
(),
|
||||
);
|
||||
let mut sample = Dyna::filled(range.size().map(|e| e as u32).into(), V::empty(), ());
|
||||
|
||||
for pos in sample.iter_positions() {
|
||||
sample.set(pos, self.get(range.min + pos).map(|v| v.clone()).unwrap_or(V::empty()))
|
||||
sample
|
||||
.set(
|
||||
pos,
|
||||
self.get(range.min + pos)
|
||||
.map(|v| v.clone())
|
||||
.unwrap_or(V::empty()),
|
||||
)
|
||||
.map_err(|err| VolMapErr::DynaErr(err))?;
|
||||
}
|
||||
|
||||
@ -106,7 +101,8 @@ impl<V: Vox, S: VolSize, M> WriteVol for VolMap<V, S, M> {
|
||||
#[inline(always)]
|
||||
fn set(&mut self, pos: Vec3<i32>, vox: V) -> Result<(), VolMapErr> {
|
||||
let ck = Self::chunk_key(pos);
|
||||
self.chunks.get_mut(&ck)
|
||||
self.chunks
|
||||
.get_mut(&ck)
|
||||
.ok_or(VolMapErr::NoSuchChunk)
|
||||
.and_then(|chunk| {
|
||||
let co = Self::chunk_offs(pos);
|
||||
@ -122,7 +118,9 @@ impl<V: Vox, S: VolSize, M> VolMap<V, S, M> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chunk_size() -> Vec3<u32> { S::SIZE }
|
||||
pub fn chunk_size() -> Vec3<u32> {
|
||||
S::SIZE
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: Vec3<i32>, chunk: Chunk<V, S, M>) -> Option<Chunk<V, S, M>> {
|
||||
self.chunks.insert(key, chunk)
|
||||
|
3
server-cli/.gitignore
vendored
3
server-cli/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
@ -1,7 +1,7 @@
|
||||
use std::time::Duration;
|
||||
use log::info;
|
||||
use server::{Input, Event, Server};
|
||||
use common::clock::Clock;
|
||||
use log::info;
|
||||
use server::{Event, Input, Server};
|
||||
use std::time::Duration;
|
||||
|
||||
const TPS: u64 = 30;
|
||||
|
||||
@ -15,11 +15,11 @@ fn main() {
|
||||
let mut clock = Clock::new();
|
||||
|
||||
// Create server
|
||||
let mut server = Server::new()
|
||||
.expect("Failed to create server instance");
|
||||
let mut server = Server::new().expect("Failed to create server instance");
|
||||
|
||||
loop {
|
||||
let events = server.tick(Input::default(), clock.get_last_delta())
|
||||
let events = server
|
||||
.tick(Input::default(), clock.get_last_delta())
|
||||
.expect("Failed to tick server");
|
||||
|
||||
for event in events {
|
||||
|
3
server/.gitignore
vendored
3
server/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
@ -88,9 +88,14 @@ fn handle_jump(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
|
||||
.read_component_cloned::<comp::phys::Pos>(entity)
|
||||
{
|
||||
Some(current_pos) => {
|
||||
server.state.write_component(entity, comp::phys::Pos(current_pos.0 + Vec3::new(x, y, z)));
|
||||
server.state.write_component(entity, comp::phys::ForceUpdate);
|
||||
},
|
||||
server.state.write_component(
|
||||
entity,
|
||||
comp::phys::Pos(current_pos.0 + Vec3::new(x, y, z)),
|
||||
);
|
||||
server
|
||||
.state
|
||||
.write_component(entity, comp::phys::ForceUpdate);
|
||||
}
|
||||
None => server.clients.notify(
|
||||
entity,
|
||||
ServerMsg::Chat(String::from("Command 'jump' invalid in current state")),
|
||||
@ -107,9 +112,13 @@ fn handle_goto(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
|
||||
let (opt_x, opt_y, opt_z) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32);
|
||||
match (opt_x, opt_y, opt_z) {
|
||||
(Some(x), Some(y), Some(z)) => {
|
||||
server.state.write_component(entity, comp::phys::Pos(Vec3::new(x, y, z)));
|
||||
server.state.write_component(entity, comp::phys::ForceUpdate);
|
||||
},
|
||||
server
|
||||
.state
|
||||
.write_component(entity, comp::phys::Pos(Vec3::new(x, y, z)));
|
||||
server
|
||||
.state
|
||||
.write_component(entity, comp::phys::ForceUpdate);
|
||||
}
|
||||
_ => server
|
||||
.clients
|
||||
.notify(entity, ServerMsg::Chat(String::from(action.help_string))),
|
||||
@ -144,8 +153,10 @@ fn handle_tp(server: &mut Server, entity: EcsEntity, args: String, action: &Chat
|
||||
{
|
||||
Some(pos) => {
|
||||
server.state.write_component(entity, pos);
|
||||
server.state.write_component(entity, comp::phys::ForceUpdate);
|
||||
},
|
||||
server
|
||||
.state
|
||||
.write_component(entity, comp::phys::ForceUpdate);
|
||||
}
|
||||
None => server.clients.notify(
|
||||
entity,
|
||||
ServerMsg::Chat(format!("Unable to teleport to player '{}'", alias)),
|
||||
|
@ -8,20 +8,10 @@ pub mod input;
|
||||
// Reexports
|
||||
pub use crate::{error::Error, input::Input};
|
||||
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
net::SocketAddr,
|
||||
sync::mpsc,
|
||||
time::Duration,
|
||||
i32,
|
||||
use crate::{
|
||||
client::{Client, Clients},
|
||||
cmd::CHAT_COMMANDS,
|
||||
};
|
||||
use specs::{
|
||||
join::Join, saveload::MarkedBuilder, world::EntityBuilder as EcsEntityBuilder, Builder,
|
||||
Entity as EcsEntity,
|
||||
};
|
||||
use threadpool::ThreadPool;
|
||||
use vek::*;
|
||||
use world::World;
|
||||
use common::{
|
||||
comp,
|
||||
comp::character::Animation,
|
||||
@ -30,10 +20,14 @@ use common::{
|
||||
state::{State, Uid},
|
||||
terrain::TerrainChunk,
|
||||
};
|
||||
use crate::{
|
||||
client::{Client, Clients},
|
||||
cmd::CHAT_COMMANDS,
|
||||
use specs::{
|
||||
join::Join, saveload::MarkedBuilder, world::EntityBuilder as EcsEntityBuilder, Builder,
|
||||
Entity as EcsEntity,
|
||||
};
|
||||
use std::{collections::HashSet, i32, net::SocketAddr, sync::mpsc, time::Duration};
|
||||
use threadpool::ThreadPool;
|
||||
use vek::*;
|
||||
use world::World;
|
||||
|
||||
const CLIENT_TIMEOUT: f64 = 20.0; // Seconds
|
||||
|
||||
@ -193,15 +187,20 @@ impl Server {
|
||||
&self.state.ecs().entities(),
|
||||
&self.state.ecs().read_storage::<comp::Player>(),
|
||||
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
||||
).join() {
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
|
||||
let dist = (chunk_pos - key).map(|e| e.abs()).reduce_max();
|
||||
|
||||
if dist < 4 {
|
||||
self.clients.notify(entity, ServerMsg::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Box::new(chunk.clone()),
|
||||
});
|
||||
self.clients.notify(
|
||||
entity,
|
||||
ServerMsg::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Box::new(chunk.clone()),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,7 +217,9 @@ impl Server {
|
||||
for (_, pos) in (
|
||||
&self.state.ecs().read_storage::<comp::Player>(),
|
||||
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
||||
).join() {
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
|
||||
let dist = (chunk_pos - key).map(|e| e.abs()).reduce_max();
|
||||
min_dist = min_dist.min(dist);
|
||||
@ -297,43 +298,68 @@ impl Server {
|
||||
ClientState::Connected => disconnect = true, // Default state
|
||||
ClientState::Registered => match client.client_state {
|
||||
// Use ClientMsg::Register instead
|
||||
ClientState::Connected => client.error_state(RequestStateError::WrongMessage),
|
||||
ClientState::Registered => client.error_state(RequestStateError::Already),
|
||||
ClientState::Spectator | ClientState::Character
|
||||
=> client.allow_state(ClientState::Registered),
|
||||
ClientState::Connected => {
|
||||
client.error_state(RequestStateError::WrongMessage)
|
||||
}
|
||||
ClientState::Registered => {
|
||||
client.error_state(RequestStateError::Already)
|
||||
}
|
||||
ClientState::Spectator | ClientState::Character => {
|
||||
client.allow_state(ClientState::Registered)
|
||||
}
|
||||
},
|
||||
ClientState::Spectator => match requested_state {
|
||||
// Become Registered first
|
||||
ClientState::Connected => client.error_state(RequestStateError::Impossible),
|
||||
ClientState::Spectator => client.error_state(RequestStateError::Already),
|
||||
ClientState::Registered | ClientState::Character
|
||||
=> client.allow_state(ClientState::Spectator),
|
||||
ClientState::Connected => {
|
||||
client.error_state(RequestStateError::Impossible)
|
||||
}
|
||||
ClientState::Spectator => {
|
||||
client.error_state(RequestStateError::Already)
|
||||
}
|
||||
ClientState::Registered | ClientState::Character => {
|
||||
client.allow_state(ClientState::Spectator)
|
||||
}
|
||||
},
|
||||
// Use ClientMsg::Character instead
|
||||
ClientState::Character => client.error_state(RequestStateError::WrongMessage),
|
||||
ClientState::Character => {
|
||||
client.error_state(RequestStateError::WrongMessage)
|
||||
}
|
||||
},
|
||||
ClientMsg::Register { player } => match client.client_state {
|
||||
ClientState::Connected => Self::initialize_player(state, entity, client, player),
|
||||
ClientState::Connected => {
|
||||
Self::initialize_player(state, entity, client, player)
|
||||
}
|
||||
// Use RequestState instead (No need to send `player` again)
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
},
|
||||
ClientMsg::Character(character) => match client.client_state {
|
||||
// Become Registered first
|
||||
ClientState::Connected => client.error_state(RequestStateError::Impossible),
|
||||
ClientState::Registered | ClientState::Spectator =>
|
||||
Self::create_player_character(state, entity, client, character),
|
||||
ClientState::Character => client.error_state(RequestStateError::Already),
|
||||
ClientState::Connected => {
|
||||
client.error_state(RequestStateError::Impossible)
|
||||
}
|
||||
ClientState::Registered | ClientState::Spectator => {
|
||||
Self::create_player_character(state, entity, client, character)
|
||||
}
|
||||
ClientState::Character => {
|
||||
client.error_state(RequestStateError::Already)
|
||||
}
|
||||
},
|
||||
ClientMsg::Chat(msg) => match client.client_state {
|
||||
ClientState::Connected => client.error_state(RequestStateError::Impossible),
|
||||
ClientState::Connected => {
|
||||
client.error_state(RequestStateError::Impossible)
|
||||
}
|
||||
ClientState::Registered
|
||||
| ClientState::Spectator
|
||||
| ClientState::Character => new_chat_msgs.push((entity, msg)),
|
||||
},
|
||||
ClientMsg::PlayerAnimation(animation_history) => match client.client_state {
|
||||
ClientState::Character => state.write_component(entity, animation_history),
|
||||
// Only characters can send animations
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
ClientMsg::PlayerAnimation(animation_history) => {
|
||||
match client.client_state {
|
||||
ClientState::Character => {
|
||||
state.write_component(entity, animation_history)
|
||||
}
|
||||
// Only characters can send animations
|
||||
_ => client.error_state(RequestStateError::Impossible),
|
||||
}
|
||||
}
|
||||
ClientMsg::PlayerPhysics { pos, vel, dir } => match client.client_state {
|
||||
ClientState::Character => {
|
||||
@ -350,10 +376,12 @@ impl Server {
|
||||
}
|
||||
ClientState::Spectator | ClientState::Character => {
|
||||
match state.terrain().get_key(key) {
|
||||
Some(chunk) => client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Box::new(chunk.clone()),
|
||||
}),
|
||||
Some(chunk) => {
|
||||
client.postbox.send_message(ServerMsg::TerrainChunkUpdate {
|
||||
key,
|
||||
chunk: Box::new(chunk.clone()),
|
||||
})
|
||||
}
|
||||
None => requested_chunks.push(key),
|
||||
}
|
||||
}
|
||||
@ -458,7 +486,10 @@ impl Server {
|
||||
&self.state.ecs().read_storage::<comp::phys::Pos>(),
|
||||
&self.state.ecs().read_storage::<comp::phys::Vel>(),
|
||||
&self.state.ecs().read_storage::<comp::phys::Dir>(),
|
||||
self.state.ecs().read_storage::<comp::phys::ForceUpdate>().maybe(),
|
||||
self.state
|
||||
.ecs()
|
||||
.read_storage::<comp::phys::ForceUpdate>()
|
||||
.maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
@ -508,7 +539,10 @@ impl Server {
|
||||
}
|
||||
|
||||
// Remove all force flags
|
||||
self.state.ecs_mut().write_storage::<comp::phys::ForceUpdate>().clear();
|
||||
self.state
|
||||
.ecs_mut()
|
||||
.write_storage::<comp::phys::ForceUpdate>()
|
||||
.clear();
|
||||
}
|
||||
|
||||
pub fn generate_chunk(&mut self, key: Vec3<i32>) {
|
||||
|
5
voxygen/.gitignore
vendored
5
voxygen/.gitignore
vendored
@ -1,5 +0,0 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
||||
settings.toml
|
||||
voxygen.log
|
@ -5,11 +5,7 @@ use std::f32::consts::PI;
|
||||
use vek::*;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
CharacterSkeleton,
|
||||
super::Animation,
|
||||
SCALE,
|
||||
};
|
||||
use super::{super::Animation, CharacterSkeleton, SCALE};
|
||||
|
||||
pub struct IdleAnimation;
|
||||
|
||||
@ -17,10 +13,7 @@ impl Animation for IdleAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = f64;
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
time: f64,
|
||||
) -> Self::Skeleton {
|
||||
fn update_skeleton(skeleton: &Self::Skeleton, time: f64) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let wave = (time as f32 * 12.0).sin();
|
||||
@ -47,11 +40,19 @@ impl Animation for IdleAnimation {
|
||||
next.shorts.ori = Quaternion::rotation_y(0.0);
|
||||
next.shorts.scale = Vec3::one();
|
||||
|
||||
next.l_hand.offset = Vec3::new(2.0 + waveultracos_slow * 0.3, 7.5, 12.5 + waveultra_slow * 1.1);
|
||||
next.l_hand.offset = Vec3::new(
|
||||
2.0 + waveultracos_slow * 0.3,
|
||||
7.5,
|
||||
12.5 + waveultra_slow * 1.1,
|
||||
);
|
||||
next.l_hand.ori = Quaternion::rotation_y(0.0 + waveultra_slow * 0.06);
|
||||
next.l_hand.scale = Vec3::one();
|
||||
|
||||
next.r_hand.offset = Vec3::new(2.0 + waveultracos_slow * 0.3 , - 7.5, 12.5 + waveultra_slow * 1.1);
|
||||
next.r_hand.offset = Vec3::new(
|
||||
2.0 + waveultracos_slow * 0.3,
|
||||
-7.5,
|
||||
12.5 + waveultra_slow * 1.1,
|
||||
);
|
||||
next.r_hand.ori = Quaternion::rotation_y(0.0 + waveultra_slow * 0.06);
|
||||
next.r_hand.scale = Vec3::one();
|
||||
|
||||
|
@ -1,18 +1,15 @@
|
||||
pub mod run;
|
||||
pub mod idle;
|
||||
pub mod run;
|
||||
|
||||
// Reexports
|
||||
pub use self::run::RunAnimation;
|
||||
pub use self::idle::IdleAnimation;
|
||||
pub use self::run::RunAnimation;
|
||||
|
||||
// Crate
|
||||
use crate::render::FigureBoneData;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
Skeleton,
|
||||
Bone,
|
||||
};
|
||||
use super::{Bone, Skeleton};
|
||||
|
||||
const SCALE: f32 = 11.0;
|
||||
|
||||
@ -47,7 +44,6 @@ impl CharacterSkeleton {
|
||||
torso: Bone::default(),
|
||||
l_shoulder: Bone::default(),
|
||||
r_shoulder: Bone::default(),
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,7 +71,6 @@ impl Skeleton for CharacterSkeleton {
|
||||
FigureBoneData::default(),
|
||||
FigureBoneData::default(),
|
||||
FigureBoneData::default(),
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
@ -92,6 +87,5 @@ impl Skeleton for CharacterSkeleton {
|
||||
self.torso.interpolate(&target.torso);
|
||||
self.l_shoulder.interpolate(&target.l_shoulder);
|
||||
self.r_shoulder.interpolate(&target.r_shoulder);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,7 @@ use std::f32::consts::PI;
|
||||
use vek::*;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
CharacterSkeleton,
|
||||
super::Animation,
|
||||
SCALE
|
||||
};
|
||||
use super::{super::Animation, CharacterSkeleton, SCALE};
|
||||
|
||||
pub struct RunAnimation;
|
||||
|
||||
@ -17,10 +13,7 @@ impl Animation for RunAnimation {
|
||||
type Skeleton = CharacterSkeleton;
|
||||
type Dependency = f64;
|
||||
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
time: f64,
|
||||
) -> Self::Skeleton {
|
||||
fn update_skeleton(skeleton: &Self::Skeleton, time: f64) -> Self::Skeleton {
|
||||
let mut next = (*skeleton).clone();
|
||||
|
||||
let wave = (time as f32 * 14.0).sin();
|
||||
@ -79,8 +72,6 @@ impl Animation for RunAnimation {
|
||||
next.r_shoulder.ori = Quaternion::rotation_y(0.0);
|
||||
next.r_shoulder.scale = Vec3::one();
|
||||
|
||||
|
||||
next
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,9 @@ impl Bone {
|
||||
}
|
||||
|
||||
pub fn compute_base_matrix(&self) -> Mat4<f32> {
|
||||
Mat4::<f32>::translation_3d(self.offset) * Mat4::scaling_3d(self.scale) * Mat4::from(self.ori)
|
||||
Mat4::<f32>::translation_3d(self.offset)
|
||||
* Mat4::scaling_3d(self.scale)
|
||||
* Mat4::from(self.ori)
|
||||
}
|
||||
|
||||
/// Change the current bone to be more like `target`
|
||||
@ -48,8 +50,5 @@ pub trait Animation {
|
||||
type Dependency;
|
||||
|
||||
/// Returns a new skeleton that is generated by the animation
|
||||
fn update_skeleton(
|
||||
skeleton: &Self::Skeleton,
|
||||
dependency: Self::Dependency,
|
||||
) -> Self::Skeleton;
|
||||
fn update_skeleton(skeleton: &Self::Skeleton, dependency: Self::Dependency) -> Self::Skeleton;
|
||||
}
|
||||
|
@ -85,7 +85,11 @@ impl Chat {
|
||||
|
||||
// Only show if it has the keyboard captured
|
||||
// Chat input with rectangle as background
|
||||
let keyboard_captured = ui_widgets.global_input().current.widget_capturing_keyboard.map_or(false, |id| id == self.ids.input);
|
||||
let keyboard_captured = ui_widgets
|
||||
.global_input()
|
||||
.current
|
||||
.widget_capturing_keyboard
|
||||
.map_or(false, |id| id == self.ids.input);
|
||||
if keyboard_captured {
|
||||
let text_edit = TextEdit::new(&self.input)
|
||||
.w(460.0)
|
||||
@ -114,10 +118,12 @@ impl Chat {
|
||||
// Message box
|
||||
Rectangle::fill([470.0, 174.0])
|
||||
.rgba(0.0, 0.0, 0.0, 0.4)
|
||||
.and(|r| if keyboard_captured {
|
||||
r.up_from(self.ids.input_bg, 0.0)
|
||||
} else {
|
||||
r.bottom_left_with_margins_on(ui_widgets.window, 10.0, 10.0)
|
||||
.and(|r| {
|
||||
if keyboard_captured {
|
||||
r.up_from(self.ids.input_bg, 0.0)
|
||||
} else {
|
||||
r.bottom_left_with_margins_on(ui_widgets.window, 10.0, 10.0)
|
||||
}
|
||||
})
|
||||
.set(self.ids.message_box_bg, ui_widgets);
|
||||
let (mut items, _) = List::flow_down(self.messages.len() + 1)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
#![feature(drain_filter)]
|
||||
#![recursion_limit="2048"]
|
||||
#![recursion_limit = "2048"]
|
||||
|
||||
pub mod anim;
|
||||
pub mod error;
|
||||
@ -10,22 +10,18 @@ pub mod mesh;
|
||||
pub mod render;
|
||||
pub mod scene;
|
||||
pub mod session;
|
||||
pub mod ui;
|
||||
pub mod window;
|
||||
pub mod settings;
|
||||
pub mod singleplayer;
|
||||
pub mod ui;
|
||||
pub mod window;
|
||||
|
||||
// Reexports
|
||||
pub use crate::error::Error;
|
||||
|
||||
use std::{mem, thread, panic, fs::File};
|
||||
use crate::{menu::main::MainMenuState, settings::Settings, window::Window};
|
||||
use log;
|
||||
use simplelog::{CombinedLogger, TermLogger, WriteLogger, Config};
|
||||
use crate::{
|
||||
menu::main::MainMenuState,
|
||||
window::Window,
|
||||
settings::Settings,
|
||||
};
|
||||
use simplelog::{CombinedLogger, Config, TermLogger, WriteLogger};
|
||||
use std::{fs::File, mem, panic, str::FromStr, thread};
|
||||
|
||||
/// The URL of the default public server that Voxygen will connect to
|
||||
const DEFAULT_PUBLIC_SERVER: &'static str = "server.veloren.net";
|
||||
@ -82,15 +78,24 @@ fn main() {
|
||||
let settings = Settings::default();
|
||||
settings.save_to_file();
|
||||
settings
|
||||
},
|
||||
}
|
||||
};
|
||||
let window = Window::new(&settings).expect("Failed to create window");
|
||||
|
||||
// Init logging
|
||||
let term_log_level = std::env::var_os("VOXYGEN_LOG")
|
||||
.and_then(|env| env.to_str().map(|s| s.to_owned()))
|
||||
.and_then(|s| log::LevelFilter::from_str(&s).ok())
|
||||
.unwrap_or(log::LevelFilter::Warn);
|
||||
CombinedLogger::init(vec![
|
||||
TermLogger::new(log::LevelFilter::Warn, Config::default()).unwrap(),
|
||||
WriteLogger::new(log::LevelFilter::Info, Config::default(), File::create(&settings.log.file).unwrap()),
|
||||
]).unwrap();
|
||||
TermLogger::new(term_log_level, Config::default()).unwrap(),
|
||||
WriteLogger::new(
|
||||
log::LevelFilter::Info,
|
||||
Config::default(),
|
||||
File::create(&settings.log.file).unwrap(),
|
||||
),
|
||||
])
|
||||
.unwrap();
|
||||
|
||||
// Set up panic handler to relay swish panic messages to the user
|
||||
let settings_clone = settings.clone();
|
||||
@ -123,18 +128,13 @@ The information below is intended for developers and testers.
|
||||
msgbox::create("Voxygen has panicked", &msg, msgbox::IconType::ERROR);
|
||||
}));
|
||||
|
||||
let mut global_state = GlobalState {
|
||||
settings,
|
||||
window,
|
||||
};
|
||||
let mut global_state = GlobalState { settings, window };
|
||||
|
||||
// Set up the initial play state
|
||||
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(
|
||||
&mut global_state,
|
||||
))];
|
||||
states.last().map(|current_state| {
|
||||
log::info!("Started game with state '{}'", current_state.name())
|
||||
});
|
||||
let mut states: Vec<Box<dyn PlayState>> = vec![Box::new(MainMenuState::new(&mut global_state))];
|
||||
states
|
||||
.last()
|
||||
.map(|current_state| log::info!("Started game with state '{}'", current_state.name()));
|
||||
|
||||
// What's going on here?
|
||||
// ---------------------
|
||||
@ -144,7 +144,10 @@ The information below is intended for developers and testers.
|
||||
// The code below manages the state transfer logic automatically so that we don't have to
|
||||
// re-engineer it for each menu we decide to add to the game.
|
||||
let mut direction = Direction::Forwards;
|
||||
while let Some(state_result) = states.last_mut().map(|last| last.play(direction, &mut global_state)){
|
||||
while let Some(state_result) = states
|
||||
.last_mut()
|
||||
.map(|last| last.play(direction, &mut global_state))
|
||||
{
|
||||
// Implement state transfer logic
|
||||
match state_result {
|
||||
PlayStateResult::Shutdown => {
|
||||
@ -156,28 +159,32 @@ The information below is intended for developers and testers.
|
||||
global_state.on_play_state_changed();
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
PlayStateResult::Pop => {
|
||||
direction = Direction::Backwards;
|
||||
states.pop().map(|old_state| {
|
||||
log::info!("Popped state '{}'", old_state.name());
|
||||
global_state.on_play_state_changed();
|
||||
});
|
||||
},
|
||||
}
|
||||
PlayStateResult::Push(new_state) => {
|
||||
direction = Direction::Forwards;
|
||||
log::info!("Pushed state '{}'", new_state.name());
|
||||
states.push(new_state);
|
||||
global_state.on_play_state_changed();
|
||||
},
|
||||
}
|
||||
PlayStateResult::Switch(mut new_state) => {
|
||||
direction = Direction::Forwards;
|
||||
states.last_mut().map(|old_state| {
|
||||
log::info!("Switching to state '{}' from state '{}'", new_state.name(), old_state.name());
|
||||
log::info!(
|
||||
"Switching to state '{}' from state '{}'",
|
||||
new_state.name(),
|
||||
old_state.name()
|
||||
);
|
||||
mem::swap(old_state, &mut new_state);
|
||||
global_state.on_play_state_changed();
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,12 @@
|
||||
mod ui;
|
||||
|
||||
use crate::{
|
||||
window::{Event, Window},
|
||||
session::SessionState,
|
||||
window::{Event, Window},
|
||||
Direction, GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::{
|
||||
clock::Clock,
|
||||
msg::ClientMsg,
|
||||
};
|
||||
use common::{clock::Clock, msg::ClientMsg};
|
||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
use ui::CharSelectionUi;
|
||||
use vek::*;
|
||||
@ -50,7 +47,7 @@ impl PlayState for CharSelectionState {
|
||||
match event {
|
||||
Event::Close => {
|
||||
return PlayStateResult::Shutdown;
|
||||
},
|
||||
}
|
||||
// Pass events to ui
|
||||
Event::Ui(event) => {
|
||||
self.char_selection_ui.handle_event(event);
|
||||
@ -63,23 +60,36 @@ impl PlayState for CharSelectionState {
|
||||
global_state.window.renderer_mut().clear(BG_COLOR);
|
||||
|
||||
// Maintain the UI
|
||||
for event in self.char_selection_ui.maintain(global_state.window.renderer_mut()) {
|
||||
for event in self
|
||||
.char_selection_ui
|
||||
.maintain(global_state.window.renderer_mut())
|
||||
{
|
||||
match event {
|
||||
ui::Event::Logout => {
|
||||
return PlayStateResult::Pop;
|
||||
},
|
||||
}
|
||||
ui::Event::Play => {
|
||||
self.client.borrow_mut().postbox.send_message(ClientMsg::Character(self.char_selection_ui.character));
|
||||
return PlayStateResult::Switch( Box::new(SessionState::new(&mut global_state.window, self.client.clone(), global_state.settings.clone())));
|
||||
self.client
|
||||
.borrow_mut()
|
||||
.postbox
|
||||
.send_message(ClientMsg::Character(self.char_selection_ui.character));
|
||||
return PlayStateResult::Switch(Box::new(SessionState::new(
|
||||
&mut global_state.window,
|
||||
self.client.clone(),
|
||||
global_state.settings.clone()
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the UI to the screen
|
||||
self.char_selection_ui.render(global_state.window.renderer_mut());
|
||||
self.char_selection_ui
|
||||
.render(global_state.window.renderer_mut());
|
||||
|
||||
// Tick the client (currently only to keep the connection alive)
|
||||
self.client.borrow_mut().tick(client::Input::default(), clock.get_last_delta())
|
||||
self.client
|
||||
.borrow_mut()
|
||||
.tick(client::Input::default(), clock.get_last_delta())
|
||||
.expect("Failed to tick the client");
|
||||
self.client.borrow_mut().cleanup();
|
||||
|
||||
|
@ -5,19 +5,8 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
assets,
|
||||
comp::character::{Belt, Character, Chest, Foot, Gender, Hand, Head, Pants, Race, Weapon},
|
||||
figure::Segment,
|
||||
comp::character::{
|
||||
Character,
|
||||
Race,
|
||||
Gender,
|
||||
Head,
|
||||
Chest,
|
||||
Belt,
|
||||
Pants,
|
||||
Hand,
|
||||
Foot,
|
||||
Weapon,
|
||||
}
|
||||
};
|
||||
use conrod_core::{
|
||||
color,
|
||||
@ -381,10 +370,12 @@ impl CharSelectionUi {
|
||||
// Load fonts
|
||||
let load_font = |filename, ui: &mut Ui| {
|
||||
let fullpath: String = ["/voxygen/font", filename].concat();
|
||||
ui.new_font(conrod_core::text::Font::from_bytes(
|
||||
assets::load(fullpath.as_str())
|
||||
.expect("Error loading file")
|
||||
).unwrap())
|
||||
ui.new_font(
|
||||
conrod_core::text::Font::from_bytes(
|
||||
assets::load(fullpath.as_str()).expect("Error loading file"),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
};
|
||||
let font_opensans = load_font("/OpenSans-Regular.ttf", &mut ui);
|
||||
let font_metamorph = load_font("/Metamorphous-Regular.ttf", &mut ui);
|
||||
@ -471,7 +462,7 @@ impl CharSelectionUi {
|
||||
|
||||
// Veloren Logo and Alpha Version
|
||||
Image::new(self.imgs.v_logo)
|
||||
.w_h(123.0*3.0, 35.0*3.0)
|
||||
.w_h(123.0 * 3.0, 35.0 * 3.0)
|
||||
.top_left_with_margins(30.0, 30.0)
|
||||
.set(self.ids.v_logo, ui_widgets);
|
||||
Text::new(version)
|
||||
|
@ -20,10 +20,7 @@ pub struct ClientInit {
|
||||
rx: Receiver<Result<Client, Error>>,
|
||||
}
|
||||
impl ClientInit {
|
||||
pub fn new(
|
||||
connection_args: (String, u16, bool),
|
||||
client_args: (comp::Player, u64),
|
||||
) -> Self {
|
||||
pub fn new(connection_args: (String, u16, bool), client_args: (comp::Player, u64)) -> Self {
|
||||
let (server_address, default_port, prefer_ipv6) = connection_args;
|
||||
let (player, view_distance) = client_args;
|
||||
|
||||
|
@ -2,7 +2,6 @@ mod client_init;
|
||||
mod start_singleplayer;
|
||||
mod ui;
|
||||
|
||||
use start_singleplayer::StartSingleplayerState;
|
||||
use super::char_selection::CharSelectionState;
|
||||
use crate::{
|
||||
window::{Event, Window},
|
||||
@ -10,6 +9,7 @@ use crate::{
|
||||
};
|
||||
use client_init::{ClientInit, Error as InitError};
|
||||
use common::{clock::Clock, comp};
|
||||
use start_singleplayer::StartSingleplayerState;
|
||||
use std::time::Duration;
|
||||
use ui::{Event as MainMenuEvent, MainMenuUi};
|
||||
use vek::*;
|
||||
@ -86,10 +86,7 @@ impl PlayState for MainMenuState {
|
||||
}
|
||||
|
||||
// Maintain the UI
|
||||
for event in self
|
||||
.main_menu_ui
|
||||
.maintain(global_state)
|
||||
{
|
||||
for event in self.main_menu_ui.maintain(global_state) {
|
||||
match event {
|
||||
MainMenuEvent::LoginAttempt {
|
||||
username,
|
||||
@ -104,15 +101,12 @@ impl PlayState for MainMenuState {
|
||||
// Don't try to connect if there is already a connection in progress
|
||||
client_init = client_init.or(Some(ClientInit::new(
|
||||
(server_address, DEFAULT_PORT, false),
|
||||
(
|
||||
comp::Player::new(username.clone()),
|
||||
300,
|
||||
),
|
||||
(comp::Player::new(username.clone()), 300),
|
||||
)));
|
||||
},
|
||||
}
|
||||
MainMenuEvent::StartSingleplayer => {
|
||||
return PlayStateResult::Push(Box::new(StartSingleplayerState::new()));
|
||||
},
|
||||
}
|
||||
MainMenuEvent::Quit => return PlayStateResult::Shutdown,
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
use common::comp;
|
||||
use super::{DEFAULT_PORT, client_init::ClientInit};
|
||||
use super::{client_init::ClientInit, DEFAULT_PORT};
|
||||
use crate::{
|
||||
menu::char_selection::CharSelectionState,
|
||||
singleplayer::Singleplayer,
|
||||
Direction, GlobalState, PlayState, PlayStateResult,
|
||||
menu::char_selection::CharSelectionState, singleplayer::Singleplayer, Direction, GlobalState,
|
||||
PlayState, PlayStateResult,
|
||||
};
|
||||
use common::comp;
|
||||
|
||||
pub struct StartSingleplayerState {
|
||||
singleplayer: Singleplayer,
|
||||
@ -28,10 +27,7 @@ impl PlayState for StartSingleplayerState {
|
||||
|
||||
let client_init = ClientInit::new(
|
||||
(server_address.clone(), DEFAULT_PORT, false),
|
||||
(
|
||||
comp::Player::new(username.clone()),
|
||||
300,
|
||||
),
|
||||
(comp::Player::new(username.clone()), 300),
|
||||
);
|
||||
|
||||
// Client creation
|
||||
@ -39,8 +35,8 @@ impl PlayState for StartSingleplayerState {
|
||||
match client_init.poll() {
|
||||
Some(Ok(client)) => break client,
|
||||
// Should always work
|
||||
Some(Err(err)) => unreachable!(),
|
||||
_ => {},
|
||||
Some(Err(err)) => unreachable!(),
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
|
||||
@ -55,7 +51,7 @@ impl PlayState for StartSingleplayerState {
|
||||
&mut global_state.window,
|
||||
std::rc::Rc::new(std::cell::RefCell::new(client)),
|
||||
)))
|
||||
},
|
||||
}
|
||||
Direction::Backwards => PlayStateResult::Pop,
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ impl MainMenuUi {
|
||||
.middle_of(ui_widgets.window)
|
||||
.set(self.ids.bg, ui_widgets);
|
||||
Image::new(self.imgs.v_logo)
|
||||
.w_h(123.0*3.0, 35.0*3.0)
|
||||
.w_h(123.0 * 3.0, 35.0 * 3.0)
|
||||
.top_left_with_margins(30.0, 30.0)
|
||||
.set(self.ids.v_logo, ui_widgets);
|
||||
Text::new(version)
|
||||
@ -373,7 +373,7 @@ impl MainMenuUi {
|
||||
.label_y(Relative::Scalar(5.0))
|
||||
.set(self.ids.login_button, ui_widgets);
|
||||
} else {
|
||||
if Button::image(self.imgs.button)
|
||||
if Button::image(self.imgs.button)
|
||||
.hover_image(self.imgs.button_hover)
|
||||
.press_image(self.imgs.button_press)
|
||||
.w_h(258.0, 68.0)
|
||||
|
@ -1,11 +1,9 @@
|
||||
pub mod segment;
|
||||
pub mod terrain;
|
||||
mod vol;
|
||||
|
||||
// Crate
|
||||
use crate::render::{
|
||||
self,
|
||||
Mesh,
|
||||
};
|
||||
use crate::render::{self, Mesh};
|
||||
|
||||
pub trait Meshable {
|
||||
type Pipeline: render::Pipeline;
|
||||
|
@ -3,43 +3,20 @@ use vek::*;
|
||||
|
||||
// Project
|
||||
use common::{
|
||||
vol::{
|
||||
Vox,
|
||||
SizedVol,
|
||||
ReadVol,
|
||||
},
|
||||
figure::Segment,
|
||||
vol::{ReadVol, SizedVol, Vox},
|
||||
};
|
||||
|
||||
// Crate
|
||||
use crate::{
|
||||
mesh::Meshable,
|
||||
render::{
|
||||
self,
|
||||
Mesh,
|
||||
Quad,
|
||||
FigurePipeline,
|
||||
},
|
||||
mesh::{vol, Meshable},
|
||||
render::{self, FigurePipeline, Mesh, Quad},
|
||||
};
|
||||
|
||||
type FigureVertex = <FigurePipeline as render::Pipeline>::Vertex;
|
||||
|
||||
// Utility function
|
||||
// TODO: Evaluate how useful this is
|
||||
fn create_quad(
|
||||
origin: Vec3<f32>,
|
||||
unit_x: Vec3<f32>,
|
||||
unit_y: Vec3<f32>,
|
||||
norm: Vec3<f32>,
|
||||
col: Rgb<f32>,
|
||||
bone: u8,
|
||||
) -> Quad<FigurePipeline> {
|
||||
Quad::new(
|
||||
FigureVertex::new(origin, norm, col, bone),
|
||||
FigureVertex::new(origin + unit_x, norm, col, bone),
|
||||
FigureVertex::new(origin + unit_x + unit_y, norm, col, bone),
|
||||
FigureVertex::new(origin + unit_y, norm, col, bone),
|
||||
)
|
||||
fn create_vertex(origin: Vec3<f32>, norm: Vec3<f32>, col: Rgb<f32>) -> FigureVertex {
|
||||
FigureVertex::new(origin, norm, col, 0)
|
||||
}
|
||||
|
||||
impl Meshable for Segment {
|
||||
@ -50,97 +27,17 @@ impl Meshable for Segment {
|
||||
let mut mesh = Mesh::new();
|
||||
|
||||
for pos in self.iter_positions() {
|
||||
if let Some(col) = self
|
||||
.get(pos)
|
||||
.ok()
|
||||
.and_then(|vox| vox.get_color())
|
||||
{
|
||||
if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) {
|
||||
let col = col.map(|e| e as f32 / 255.0);
|
||||
|
||||
// -x
|
||||
if self.get(pos - Vec3::unit_x())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs + pos.map(|e| e as f32) + Vec3::unit_y(),
|
||||
-Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
-Vec3::unit_x(),
|
||||
col,
|
||||
0,
|
||||
));
|
||||
}
|
||||
// +x
|
||||
if self.get(pos + Vec3::unit_x())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs + pos.map(|e| e as f32) + Vec3::unit_x(),
|
||||
Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
Vec3::unit_x(),
|
||||
col,
|
||||
0,
|
||||
));
|
||||
}
|
||||
// -y
|
||||
if self.get(pos - Vec3::unit_y())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs + pos.map(|e| e as f32),
|
||||
Vec3::unit_x(),
|
||||
Vec3::unit_z(),
|
||||
-Vec3::unit_y(),
|
||||
col,
|
||||
0,
|
||||
));
|
||||
}
|
||||
// +y
|
||||
if self.get(pos + Vec3::unit_y())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs + pos.map(|e| e as f32) + Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
Vec3::unit_x(),
|
||||
Vec3::unit_y(),
|
||||
col,
|
||||
0,
|
||||
));
|
||||
}
|
||||
// -z
|
||||
if self.get(pos - Vec3::unit_z())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs + pos.map(|e| e as f32),
|
||||
Vec3::unit_y(),
|
||||
Vec3::unit_x(),
|
||||
-Vec3::unit_z(),
|
||||
col,
|
||||
0,
|
||||
));
|
||||
}
|
||||
// +z
|
||||
if self.get(pos + Vec3::unit_z())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs + pos.map(|e| e as f32) + Vec3::unit_z(),
|
||||
Vec3::unit_x(),
|
||||
Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
col,
|
||||
0,
|
||||
));
|
||||
}
|
||||
vol::push_vox_verts(
|
||||
&mut mesh,
|
||||
self,
|
||||
pos,
|
||||
offs + pos.map(|e| e as f32),
|
||||
col,
|
||||
create_vertex,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,45 +3,19 @@ use vek::*;
|
||||
|
||||
// Project
|
||||
use common::{
|
||||
vol::{
|
||||
Vox,
|
||||
SizedVol,
|
||||
ReadVol,
|
||||
},
|
||||
volumes::dyna::Dyna,
|
||||
terrain::Block,
|
||||
vol::{ReadVol, SizedVol, Vox},
|
||||
volumes::dyna::Dyna,
|
||||
};
|
||||
|
||||
// Crate
|
||||
use crate::{
|
||||
mesh::Meshable,
|
||||
render::{
|
||||
self,
|
||||
Mesh,
|
||||
Quad,
|
||||
TerrainPipeline,
|
||||
},
|
||||
mesh::{vol, Meshable},
|
||||
render::{self, Mesh, Quad, TerrainPipeline},
|
||||
};
|
||||
|
||||
type TerrainVertex = <TerrainPipeline as render::Pipeline>::Vertex;
|
||||
|
||||
// Utility function
|
||||
// TODO: Evaluate how useful this is
|
||||
fn create_quad(
|
||||
origin: Vec3<f32>,
|
||||
unit_x: Vec3<f32>,
|
||||
unit_y: Vec3<f32>,
|
||||
norm: Vec3<f32>,
|
||||
col: Rgb<f32>,
|
||||
) -> Quad<TerrainPipeline> {
|
||||
Quad::new(
|
||||
TerrainVertex::new(origin, norm, col),
|
||||
TerrainVertex::new(origin + unit_x, norm, col),
|
||||
TerrainVertex::new(origin + unit_x + unit_y, norm, col),
|
||||
TerrainVertex::new(origin + unit_y, norm, col),
|
||||
)
|
||||
}
|
||||
|
||||
impl<M> Meshable for Dyna<Block, M> {
|
||||
type Pipeline = TerrainPipeline;
|
||||
type Supplement = ();
|
||||
@ -52,95 +26,17 @@ impl<M> Meshable for Dyna<Block, M> {
|
||||
for pos in self
|
||||
.iter_positions()
|
||||
.filter(|pos| pos.map(|e| e >= 1).reduce_and())
|
||||
.filter(|pos| pos.map2(self.get_size(), |e, sz| e < sz as i32 - 1).reduce_and())
|
||||
.filter(|pos| {
|
||||
pos.map2(self.get_size(), |e, sz| e < sz as i32 - 1)
|
||||
.reduce_and()
|
||||
})
|
||||
{
|
||||
let offs = pos.map(|e| e as f32 - 1.0);
|
||||
|
||||
if let Some(col) = self
|
||||
.get(pos)
|
||||
.ok()
|
||||
.and_then(|vox| vox.get_color())
|
||||
{
|
||||
if let Some(col) = self.get(pos).ok().and_then(|vox| vox.get_color()) {
|
||||
let col = col.map(|e| e as f32 / 255.0);
|
||||
|
||||
// -x
|
||||
if self.get(pos - Vec3::unit_x())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs,
|
||||
Vec3::unit_z(),
|
||||
Vec3::unit_y(),
|
||||
-Vec3::unit_x(),
|
||||
col,
|
||||
));
|
||||
}
|
||||
// +x
|
||||
if self.get(pos + Vec3::unit_x())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs + Vec3::unit_x(),
|
||||
Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
Vec3::unit_x(),
|
||||
col,
|
||||
));
|
||||
}
|
||||
// -y
|
||||
if self.get(pos - Vec3::unit_y())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs,
|
||||
Vec3::unit_x(),
|
||||
Vec3::unit_z(),
|
||||
-Vec3::unit_y(),
|
||||
col,
|
||||
));
|
||||
}
|
||||
// +y
|
||||
if self.get(pos + Vec3::unit_y())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs + Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
Vec3::unit_x(),
|
||||
Vec3::unit_y(),
|
||||
col,
|
||||
));
|
||||
}
|
||||
// -z
|
||||
if self.get(pos - Vec3::unit_z())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs,
|
||||
Vec3::unit_y(),
|
||||
Vec3::unit_x(),
|
||||
-Vec3::unit_z(),
|
||||
col,
|
||||
));
|
||||
}
|
||||
// +z
|
||||
if self.get(pos + Vec3::unit_z())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs + Vec3::unit_z(),
|
||||
Vec3::unit_x(),
|
||||
Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
col,
|
||||
));
|
||||
}
|
||||
vol::push_vox_verts(&mut mesh, self, pos, offs, col, TerrainVertex::new);
|
||||
}
|
||||
}
|
||||
|
||||
|
183
voxygen/src/mesh/vol.rs
Normal file
183
voxygen/src/mesh/vol.rs
Normal file
@ -0,0 +1,183 @@
|
||||
use vek::*;
|
||||
|
||||
use common::vol::{ReadVol, Vox};
|
||||
|
||||
use crate::render::{
|
||||
mesh::{Mesh, Quad},
|
||||
Pipeline,
|
||||
};
|
||||
|
||||
/// Given a volume, a position and the cardinal directions, compute each vertex' AO value
|
||||
/// `dirs` should be a slice of length 5 so that the sliding window of size 2 over the slice
|
||||
/// yields each vertex' adjacent positions.
|
||||
fn get_ao_quad<V: ReadVol>(vol: &V, pos: Vec3<i32>, dirs: &[Vec3<i32>]) -> Vec4<f32> {
|
||||
dirs.windows(2)
|
||||
.map(|offs| {
|
||||
let (s1, s2) = (
|
||||
vol.get(pos + offs[0])
|
||||
.map(|v| !v.is_empty())
|
||||
.unwrap_or(false),
|
||||
vol.get(pos + offs[1])
|
||||
.map(|v| !v.is_empty())
|
||||
.unwrap_or(false),
|
||||
);
|
||||
|
||||
if s1 && s2 {
|
||||
0.0
|
||||
} else {
|
||||
let corner = vol
|
||||
.get(pos + offs[0] + offs[1])
|
||||
.map(|v| !v.is_empty())
|
||||
.unwrap_or(false);
|
||||
// Map both 1 and 2 neighbors to 0.5 occlusion
|
||||
if s1 || s2 || corner {
|
||||
0.5
|
||||
} else {
|
||||
1.0
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec4<f32>>()
|
||||
}
|
||||
|
||||
// Utility function
|
||||
fn create_quad<P: Pipeline, F: Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>) -> P::Vertex>(
|
||||
origin: Vec3<f32>,
|
||||
unit_x: Vec3<f32>,
|
||||
unit_y: Vec3<f32>,
|
||||
norm: Vec3<f32>,
|
||||
col: Rgb<f32>,
|
||||
ao: Vec4<f32>,
|
||||
vcons: &F,
|
||||
) -> Quad<P> {
|
||||
let ao_scale = 1.0;
|
||||
let dark = col * (1.0 - ao_scale);
|
||||
|
||||
if ao[0] + ao[2] < ao[1] + ao[3] {
|
||||
Quad::new(
|
||||
vcons(origin + unit_y, norm, Rgb::lerp(dark, col, ao[3])),
|
||||
vcons(origin, norm, Rgb::lerp(dark, col, ao[0])),
|
||||
vcons(origin + unit_x, norm, Rgb::lerp(dark, col, ao[1])),
|
||||
vcons(origin + unit_x + unit_y, norm, Rgb::lerp(dark, col, ao[2])),
|
||||
)
|
||||
} else {
|
||||
Quad::new(
|
||||
vcons(origin, norm, Rgb::lerp(dark, col, ao[0])),
|
||||
vcons(origin + unit_x, norm, Rgb::lerp(dark, col, ao[1])),
|
||||
vcons(origin + unit_x + unit_y, norm, Rgb::lerp(dark, col, ao[2])),
|
||||
vcons(origin + unit_y, norm, Rgb::lerp(dark, col, ao[3])),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_vox_verts<
|
||||
V: ReadVol,
|
||||
P: Pipeline,
|
||||
F: Fn(Vec3<f32>, Vec3<f32>, Rgb<f32>) -> P::Vertex,
|
||||
>(
|
||||
mesh: &mut Mesh<P>,
|
||||
vol: &V,
|
||||
pos: Vec3<i32>,
|
||||
offs: Vec3<f32>,
|
||||
col: Rgb<f32>,
|
||||
vcons: F,
|
||||
) {
|
||||
let (x, y, z) = (Vec3::unit_x(), Vec3::unit_y(), Vec3::unit_z());
|
||||
|
||||
// -x
|
||||
if vol
|
||||
.get(pos - Vec3::unit_x())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs,
|
||||
Vec3::unit_z(),
|
||||
Vec3::unit_y(),
|
||||
-Vec3::unit_x(),
|
||||
col,
|
||||
get_ao_quad(vol, pos - Vec3::unit_x(), &[-z, -y, z, y, -z]),
|
||||
&vcons,
|
||||
));
|
||||
}
|
||||
// +x
|
||||
if vol
|
||||
.get(pos + Vec3::unit_x())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs + Vec3::unit_x(),
|
||||
Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
Vec3::unit_x(),
|
||||
col,
|
||||
get_ao_quad(vol, pos + Vec3::unit_x(), &[-y, -z, y, z, -y]),
|
||||
&vcons,
|
||||
));
|
||||
}
|
||||
// -y
|
||||
if vol
|
||||
.get(pos - Vec3::unit_y())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs,
|
||||
Vec3::unit_x(),
|
||||
Vec3::unit_z(),
|
||||
-Vec3::unit_y(),
|
||||
col,
|
||||
get_ao_quad(vol, pos - Vec3::unit_y(), &[-x, -z, x, z, -x]),
|
||||
&vcons,
|
||||
));
|
||||
}
|
||||
// +y
|
||||
if vol
|
||||
.get(pos + Vec3::unit_y())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs + Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
Vec3::unit_x(),
|
||||
Vec3::unit_y(),
|
||||
col,
|
||||
get_ao_quad(vol, pos + Vec3::unit_y(), &[-z, -x, z, x, -z]),
|
||||
&vcons,
|
||||
));
|
||||
}
|
||||
// -z
|
||||
if vol
|
||||
.get(pos - Vec3::unit_z())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs,
|
||||
Vec3::unit_y(),
|
||||
Vec3::unit_x(),
|
||||
-Vec3::unit_z(),
|
||||
col,
|
||||
get_ao_quad(vol, pos - Vec3::unit_z(), &[-y, -x, y, x, -y]),
|
||||
&vcons,
|
||||
));
|
||||
}
|
||||
// +z
|
||||
if vol
|
||||
.get(pos + Vec3::unit_z())
|
||||
.map(|v| v.is_empty())
|
||||
.unwrap_or(true)
|
||||
{
|
||||
mesh.push_quad(create_quad(
|
||||
offs + Vec3::unit_z(),
|
||||
Vec3::unit_x(),
|
||||
Vec3::unit_y(),
|
||||
Vec3::unit_z(),
|
||||
col,
|
||||
get_ao_quad(vol, pos + Vec3::unit_z(), &[-x, -y, x, y, -x]),
|
||||
&vcons,
|
||||
));
|
||||
}
|
||||
}
|
@ -1,14 +1,8 @@
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
traits::FactoryExt,
|
||||
};
|
||||
use gfx::{self, traits::FactoryExt};
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
RenderError,
|
||||
gfx_backend,
|
||||
};
|
||||
use super::{gfx_backend, RenderError};
|
||||
|
||||
/// A handle to a series of constants sitting on the GPU. This is used to hold information used in
|
||||
/// the rendering process that does not change throughout a single render pass.
|
||||
@ -31,7 +25,8 @@ impl<T: Copy + gfx::traits::Pod> Consts<T> {
|
||||
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
||||
vals: &[T],
|
||||
) -> Result<(), RenderError> {
|
||||
encoder.update_buffer(&self.buf, vals, 0)
|
||||
encoder
|
||||
.update_buffer(&self.buf, vals, 0)
|
||||
.map_err(|err| RenderError::UpdateError(err))
|
||||
}
|
||||
}
|
||||
|
@ -75,11 +75,7 @@ pub struct Tri<P: Pipeline> {
|
||||
}
|
||||
|
||||
impl<P: Pipeline> Tri<P> {
|
||||
pub fn new(
|
||||
a: P::Vertex,
|
||||
b: P::Vertex,
|
||||
c: P::Vertex,
|
||||
) -> Self {
|
||||
pub fn new(a: P::Vertex, b: P::Vertex, c: P::Vertex) -> Self {
|
||||
Self { a, b, c }
|
||||
}
|
||||
}
|
||||
@ -93,12 +89,7 @@ pub struct Quad<P: Pipeline> {
|
||||
}
|
||||
|
||||
impl<P: Pipeline> Quad<P> {
|
||||
pub fn new(
|
||||
a: P::Vertex,
|
||||
b: P::Vertex,
|
||||
c: P::Vertex,
|
||||
d: P::Vertex,
|
||||
) -> Self {
|
||||
pub fn new(a: P::Vertex, b: P::Vertex, c: P::Vertex, d: P::Vertex) -> Self {
|
||||
Self { a, b, c, d }
|
||||
}
|
||||
}
|
||||
|
@ -9,33 +9,19 @@ mod util;
|
||||
// Reexports
|
||||
pub use self::{
|
||||
consts::Consts,
|
||||
mesh::{Mesh, Tri, Quad},
|
||||
mesh::{Mesh, Quad, Tri},
|
||||
model::Model,
|
||||
texture::Texture,
|
||||
renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
|
||||
pipelines::{
|
||||
Globals,
|
||||
figure::{
|
||||
FigurePipeline,
|
||||
Locals as FigureLocals,
|
||||
BoneData as FigureBoneData,
|
||||
},
|
||||
skybox::{
|
||||
create_mesh as create_skybox_mesh,
|
||||
SkyboxPipeline,
|
||||
Locals as SkyboxLocals,
|
||||
},
|
||||
terrain::{
|
||||
TerrainPipeline,
|
||||
Locals as TerrainLocals,
|
||||
},
|
||||
figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals},
|
||||
skybox::{create_mesh as create_skybox_mesh, Locals as SkyboxLocals, SkyboxPipeline},
|
||||
terrain::{Locals as TerrainLocals, TerrainPipeline},
|
||||
ui::{
|
||||
create_quad as create_ui_quad,
|
||||
create_tri as create_ui_tri,
|
||||
Mode as UiMode,
|
||||
UiPipeline,
|
||||
create_quad as create_ui_quad, create_tri as create_ui_tri, Mode as UiMode, UiPipeline,
|
||||
},
|
||||
Globals,
|
||||
},
|
||||
renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
|
||||
texture::Texture,
|
||||
};
|
||||
|
||||
#[cfg(feature = "gl")]
|
||||
@ -64,8 +50,5 @@ pub enum RenderError {
|
||||
/// - `SkyboxPipeline`
|
||||
/// - `FigurePipeline`
|
||||
pub trait Pipeline {
|
||||
type Vertex:
|
||||
Clone +
|
||||
gfx::traits::Pod +
|
||||
gfx::pso::buffer::Structure<gfx::format::Format>;
|
||||
type Vertex: Clone + gfx::traits::Pod + gfx::pso::buffer::Structure<gfx::format::Format>;
|
||||
}
|
||||
|
@ -1,15 +1,8 @@
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
traits::FactoryExt,
|
||||
};
|
||||
use gfx::{self, traits::FactoryExt};
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
mesh::Mesh,
|
||||
Pipeline,
|
||||
gfx_backend,
|
||||
};
|
||||
use super::{gfx_backend, mesh::Mesh, Pipeline};
|
||||
|
||||
/// Represents a mesh that has been sent to the GPU.
|
||||
pub struct Model<P: Pipeline> {
|
||||
@ -18,10 +11,7 @@ pub struct Model<P: Pipeline> {
|
||||
}
|
||||
|
||||
impl<P: Pipeline> Model<P> {
|
||||
pub fn new(
|
||||
factory: &mut gfx_backend::Factory,
|
||||
mesh: &Mesh<P>,
|
||||
) -> Self {
|
||||
pub fn new(factory: &mut gfx_backend::Factory, mesh: &Mesh<P>) -> Self {
|
||||
Self {
|
||||
vbuf: factory.create_vertex_buffer(mesh.vertices()),
|
||||
slice: gfx::Slice {
|
||||
|
@ -1,25 +1,20 @@
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
gfx_constant_struct_meta,
|
||||
// Macros
|
||||
gfx_defines,
|
||||
gfx_vertex_struct_meta,
|
||||
gfx_constant_struct_meta,
|
||||
gfx_impl_struct_meta,
|
||||
gfx_pipeline,
|
||||
gfx_pipeline_inner,
|
||||
gfx_vertex_struct_meta,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
super::{util::arr_to_mat, Pipeline, TgtColorFmt, TgtDepthFmt},
|
||||
Globals,
|
||||
super::{
|
||||
Pipeline,
|
||||
TgtColorFmt,
|
||||
TgtDepthFmt,
|
||||
util::arr_to_mat,
|
||||
},
|
||||
};
|
||||
|
||||
gfx_defines! {
|
||||
|
@ -6,9 +6,9 @@ pub mod ui;
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
gfx_constant_struct_meta,
|
||||
// Macros
|
||||
gfx_defines,
|
||||
gfx_constant_struct_meta,
|
||||
gfx_impl_struct_meta,
|
||||
};
|
||||
use vek::*;
|
||||
|
@ -1,25 +1,19 @@
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
gfx_constant_struct_meta,
|
||||
// Macros
|
||||
gfx_defines,
|
||||
gfx_vertex_struct_meta,
|
||||
gfx_constant_struct_meta,
|
||||
gfx_impl_struct_meta,
|
||||
gfx_pipeline,
|
||||
gfx_pipeline_inner,
|
||||
gfx_vertex_struct_meta,
|
||||
};
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
super::{Mesh, Pipeline, Quad, TgtColorFmt, TgtDepthFmt},
|
||||
Globals,
|
||||
super::{
|
||||
Pipeline,
|
||||
TgtColorFmt,
|
||||
TgtDepthFmt,
|
||||
Mesh,
|
||||
Quad,
|
||||
},
|
||||
};
|
||||
|
||||
gfx_defines! {
|
||||
|
@ -1,24 +1,20 @@
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
gfx_constant_struct_meta,
|
||||
// Macros
|
||||
gfx_defines,
|
||||
gfx_vertex_struct_meta,
|
||||
gfx_constant_struct_meta,
|
||||
gfx_impl_struct_meta,
|
||||
gfx_pipeline,
|
||||
gfx_pipeline_inner,
|
||||
gfx_vertex_struct_meta,
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
super::{Pipeline, TgtColorFmt, TgtDepthFmt},
|
||||
Globals,
|
||||
super::{
|
||||
Pipeline,
|
||||
TgtColorFmt,
|
||||
TgtDepthFmt,
|
||||
},
|
||||
};
|
||||
|
||||
gfx_defines! {
|
||||
|
@ -1,20 +1,14 @@
|
||||
use super::super::{Pipeline, Quad, TgtColorFmt, TgtDepthFmt, Tri};
|
||||
use gfx::{
|
||||
self,
|
||||
// Macros
|
||||
gfx_defines,
|
||||
gfx_vertex_struct_meta,
|
||||
gfx_impl_struct_meta,
|
||||
gfx_pipeline,
|
||||
gfx_pipeline_inner,
|
||||
gfx_vertex_struct_meta,
|
||||
};
|
||||
use vek::*;
|
||||
use super::super::{
|
||||
Pipeline,
|
||||
TgtColorFmt,
|
||||
TgtDepthFmt,
|
||||
Quad,
|
||||
Tri,
|
||||
};
|
||||
|
||||
gfx_defines! {
|
||||
vertex Vertex {
|
||||
@ -65,20 +59,20 @@ impl Mode {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_quad(rect: Aabr<f32>, uv_rect: Aabr<f32>, color: Rgba<f32>, mode: Mode) -> Quad<UiPipeline> {
|
||||
pub fn create_quad(
|
||||
rect: Aabr<f32>,
|
||||
uv_rect: Aabr<f32>,
|
||||
color: Rgba<f32>,
|
||||
mode: Mode,
|
||||
) -> Quad<UiPipeline> {
|
||||
let mode_val = mode.value();
|
||||
let v = |pos, uv| {
|
||||
Vertex {
|
||||
pos,
|
||||
uv,
|
||||
color: color.into_array(),
|
||||
mode: mode_val,
|
||||
}
|
||||
let v = |pos, uv| Vertex {
|
||||
pos,
|
||||
uv,
|
||||
color: color.into_array(),
|
||||
mode: mode_val,
|
||||
};
|
||||
let aabr_to_lbrt = |aabr: Aabr<f32>| (
|
||||
aabr.min.x, aabr.min.y,
|
||||
aabr.max.x, aabr.max.y,
|
||||
);
|
||||
let aabr_to_lbrt = |aabr: Aabr<f32>| (aabr.min.x, aabr.min.y, aabr.max.x, aabr.max.y);
|
||||
|
||||
let (l, b, r, t) = aabr_to_lbrt(rect);
|
||||
let (uv_l, uv_b, uv_r, uv_t) = aabr_to_lbrt(uv_rect);
|
||||
@ -90,15 +84,18 @@ pub fn create_quad(rect: Aabr<f32>, uv_rect: Aabr<f32>, color: Rgba<f32>, mode:
|
||||
)
|
||||
}
|
||||
|
||||
pub fn create_tri(tri: [[f32; 2]; 3], uv_tri: [[f32; 2]; 3], color: Rgba<f32>, mode: Mode) -> Tri<UiPipeline> {
|
||||
pub fn create_tri(
|
||||
tri: [[f32; 2]; 3],
|
||||
uv_tri: [[f32; 2]; 3],
|
||||
color: Rgba<f32>,
|
||||
mode: Mode,
|
||||
) -> Tri<UiPipeline> {
|
||||
let mode_val = mode.value();
|
||||
let v = |pos, uv| {
|
||||
Vertex {
|
||||
pos,
|
||||
uv,
|
||||
color: color.into_array(),
|
||||
mode: mode_val,
|
||||
}
|
||||
let v = |pos, uv| Vertex {
|
||||
pos,
|
||||
uv,
|
||||
color: color.into_array(),
|
||||
mode: mode_val,
|
||||
};
|
||||
Tri::new(
|
||||
v([tri[0][0], tri[0][1]], [uv_tri[0][0], uv_tri[0][1]]),
|
||||
|
@ -1,25 +1,18 @@
|
||||
use vek::*;
|
||||
use super::{
|
||||
consts::Consts,
|
||||
gfx_backend,
|
||||
mesh::Mesh,
|
||||
model::Model,
|
||||
pipelines::{figure, skybox, terrain, ui, Globals},
|
||||
texture::Texture,
|
||||
Pipeline, RenderError,
|
||||
};
|
||||
use gfx::{
|
||||
self,
|
||||
traits::{Device, FactoryExt},
|
||||
};
|
||||
use image;
|
||||
use super::{
|
||||
consts::Consts,
|
||||
mesh::Mesh,
|
||||
model::Model,
|
||||
texture::Texture,
|
||||
Pipeline,
|
||||
RenderError,
|
||||
gfx_backend,
|
||||
pipelines::{
|
||||
Globals,
|
||||
figure,
|
||||
skybox,
|
||||
terrain,
|
||||
ui,
|
||||
},
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
/// Represents the format of the window's color target.
|
||||
pub type TgtColorFmt = gfx::format::Rgba8;
|
||||
@ -149,37 +142,30 @@ impl Renderer {
|
||||
pub fn update_consts<T: Copy + gfx::traits::Pod>(
|
||||
&mut self,
|
||||
consts: &mut Consts<T>,
|
||||
vals: &[T]
|
||||
vals: &[T],
|
||||
) -> Result<(), RenderError> {
|
||||
consts.update(&mut self.encoder, vals)
|
||||
}
|
||||
|
||||
/// Create a new model from the provided mesh.
|
||||
pub fn create_model<P: Pipeline>(&mut self, mesh: &Mesh<P>) -> Result<Model<P>, RenderError> {
|
||||
Ok(Model::new(
|
||||
&mut self.factory,
|
||||
mesh,
|
||||
))
|
||||
Ok(Model::new(&mut self.factory, mesh))
|
||||
}
|
||||
|
||||
/// Create a new texture from the provided image.
|
||||
pub fn create_texture<P: Pipeline>(&mut self, image: &image::DynamicImage) -> Result<Texture<P>, RenderError> {
|
||||
Texture::new(
|
||||
&mut self.factory,
|
||||
image,
|
||||
)
|
||||
pub fn create_texture<P: Pipeline>(
|
||||
&mut self,
|
||||
image: &image::DynamicImage,
|
||||
) -> Result<Texture<P>, RenderError> {
|
||||
Texture::new(&mut self.factory, image)
|
||||
}
|
||||
|
||||
/// Create a new dynamic texture (gfx::memory::Usage::Dynamic) with the specified dimensions
|
||||
pub fn create_dynamic_texture<P: Pipeline>(
|
||||
&mut self,
|
||||
dims: Vec2<u16>
|
||||
dims: Vec2<u16>,
|
||||
) -> Result<Texture<P>, RenderError> {
|
||||
Texture::new_dynamic(
|
||||
&mut self.factory,
|
||||
dims.x,
|
||||
dims.y,
|
||||
)
|
||||
Texture::new_dynamic(&mut self.factory, dims.x, dims.y)
|
||||
}
|
||||
|
||||
/// Update a texture with the provided offset, size, and data
|
||||
@ -188,14 +174,9 @@ impl Renderer {
|
||||
texture: &Texture<P>,
|
||||
offset: [u16; 2],
|
||||
size: [u16; 2],
|
||||
data: &[[u8; 4]]
|
||||
data: &[[u8; 4]],
|
||||
) -> Result<(), RenderError> {
|
||||
texture.update(
|
||||
&mut self.encoder,
|
||||
offset,
|
||||
size,
|
||||
data,
|
||||
)
|
||||
texture.update(&mut self.encoder, offset, size, data)
|
||||
}
|
||||
|
||||
/// Queue the rendering of the provided skybox model in the upcoming frame.
|
||||
@ -273,7 +254,12 @@ impl Renderer {
|
||||
&self.ui_pipeline.pso,
|
||||
&ui::pipe::Data {
|
||||
vbuf: model.vbuf.clone(),
|
||||
scissor: gfx::Rect { x: min.x, y: min.y, w: max.x - min.x, h: max.y - min.y },
|
||||
scissor: gfx::Rect {
|
||||
x: min.x,
|
||||
y: min.y,
|
||||
w: max.x - min.x,
|
||||
h: max.y - min.y,
|
||||
},
|
||||
tex: (tex.srv.clone(), tex.sampler.clone()),
|
||||
tgt_color: self.tgt_color_view.clone(),
|
||||
tgt_depth: self.tgt_depth_view.clone(),
|
||||
@ -298,7 +284,8 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>(
|
||||
.map_err(|err| RenderError::PipelineError(gfx::PipelineStateError::Program(err)))?;
|
||||
|
||||
Ok(GfxPipeline {
|
||||
pso: factory.create_pipeline_from_program(
|
||||
pso: factory
|
||||
.create_pipeline_from_program(
|
||||
&program,
|
||||
gfx::Primitive::TriangleList,
|
||||
gfx::state::Rasterizer {
|
||||
@ -310,14 +297,17 @@ fn create_pipeline<'a, P: gfx::pso::PipelineInit>(
|
||||
},
|
||||
pipe,
|
||||
)
|
||||
// Do some funky things to work around an oddity in gfx's error ownership rules
|
||||
.map_err(|err| RenderError::PipelineError(match err {
|
||||
gfx::PipelineStateError::Program(err) =>
|
||||
gfx::PipelineStateError::Program(err),
|
||||
gfx::PipelineStateError::DescriptorInit(err) =>
|
||||
gfx::PipelineStateError::DescriptorInit(err.into()),
|
||||
gfx::PipelineStateError::DeviceCreate(err) =>
|
||||
gfx::PipelineStateError::DeviceCreate(err),
|
||||
}))?,
|
||||
// Do some funky things to work around an oddity in gfx's error ownership rules
|
||||
.map_err(|err| {
|
||||
RenderError::PipelineError(match err {
|
||||
gfx::PipelineStateError::Program(err) => gfx::PipelineStateError::Program(err),
|
||||
gfx::PipelineStateError::DescriptorInit(err) => {
|
||||
gfx::PipelineStateError::DescriptorInit(err.into())
|
||||
}
|
||||
gfx::PipelineStateError::DeviceCreate(err) => {
|
||||
gfx::PipelineStateError::DeviceCreate(err)
|
||||
}
|
||||
})
|
||||
})?,
|
||||
})
|
||||
}
|
||||
|
@ -2,29 +2,25 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// Library
|
||||
use gfx::{
|
||||
self,
|
||||
traits::Factory,
|
||||
};
|
||||
use image::{
|
||||
DynamicImage,
|
||||
GenericImageView,
|
||||
};
|
||||
use gfx::{self, traits::Factory};
|
||||
use image::{DynamicImage, GenericImageView};
|
||||
use vek::Vec2;
|
||||
|
||||
// Local
|
||||
use super::{
|
||||
RenderError,
|
||||
Pipeline,
|
||||
gfx_backend,
|
||||
};
|
||||
use super::{gfx_backend, Pipeline, RenderError};
|
||||
|
||||
type ShaderFormat = (gfx::format::R8_G8_B8_A8, gfx::format::Srgb);
|
||||
|
||||
/// Represents an image that has been uploaded to the GPU.
|
||||
pub struct Texture<P: Pipeline> {
|
||||
pub tex: gfx::handle::Texture<gfx_backend::Resources, <ShaderFormat as gfx::format::Formatted>::Surface>,
|
||||
pub srv: gfx::handle::ShaderResourceView<gfx_backend::Resources, <ShaderFormat as gfx::format::Formatted>::View>,
|
||||
pub tex: gfx::handle::Texture<
|
||||
gfx_backend::Resources,
|
||||
<ShaderFormat as gfx::format::Formatted>::Surface,
|
||||
>,
|
||||
pub srv: gfx::handle::ShaderResourceView<
|
||||
gfx_backend::Resources,
|
||||
<ShaderFormat as gfx::format::Formatted>::View,
|
||||
>,
|
||||
pub sampler: gfx::handle::Sampler<gfx_backend::Resources>,
|
||||
_phantom: PhantomData<P>,
|
||||
}
|
||||
@ -34,15 +30,16 @@ impl<P: Pipeline> Texture<P> {
|
||||
factory: &mut gfx_backend::Factory,
|
||||
image: &DynamicImage,
|
||||
) -> Result<Self, RenderError> {
|
||||
let (tex, srv) = factory.create_texture_immutable_u8::<ShaderFormat>(
|
||||
gfx::texture::Kind::D2(
|
||||
image.width() as u16,
|
||||
image.height() as u16,
|
||||
gfx::texture::AaMode::Single,
|
||||
),
|
||||
gfx::texture::Mipmap::Provided,
|
||||
&[&image.to_rgba().into_raw()],
|
||||
)
|
||||
let (tex, srv) = factory
|
||||
.create_texture_immutable_u8::<ShaderFormat>(
|
||||
gfx::texture::Kind::D2(
|
||||
image.width() as u16,
|
||||
image.height() as u16,
|
||||
gfx::texture::AaMode::Single,
|
||||
),
|
||||
gfx::texture::Mipmap::Provided,
|
||||
&[&image.to_rgba().into_raw()],
|
||||
)
|
||||
.map_err(|err| RenderError::CombinedError(err))?;
|
||||
|
||||
Ok(Self {
|
||||
@ -73,8 +70,12 @@ impl<P: Pipeline> Texture<P> {
|
||||
)
|
||||
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Texture(err)))?;
|
||||
|
||||
let srv =
|
||||
factory.view_texture_as_shader_resource::<ShaderFormat>(&tex, (0, 0), gfx::format::Swizzle::new())
|
||||
let srv = factory
|
||||
.view_texture_as_shader_resource::<ShaderFormat>(
|
||||
&tex,
|
||||
(0, 0),
|
||||
gfx::format::Swizzle::new(),
|
||||
)
|
||||
.map_err(|err| RenderError::CombinedError(gfx::CombinedError::Resource(err)))?;
|
||||
|
||||
Ok(Self {
|
||||
@ -107,8 +108,10 @@ impl<P: Pipeline> Texture<P> {
|
||||
mipmap: 0,
|
||||
};
|
||||
encoder
|
||||
.update_texture::<<ShaderFormat as gfx::format::Formatted>::Surface, ShaderFormat>(&self.tex, None, info, data)
|
||||
.map_err(|err| RenderError::TexUpdateError(err))
|
||||
.update_texture::<<ShaderFormat as gfx::format::Formatted>::Surface, ShaderFormat>(
|
||||
&self.tex, None, info, data,
|
||||
)
|
||||
.map_err(|err| RenderError::TexUpdateError(err))
|
||||
}
|
||||
/// Get dimensions of the represented image
|
||||
pub fn get_dimensions(&self) -> Vec2<u16> {
|
||||
|
@ -38,12 +38,7 @@ impl Camera {
|
||||
* Mat4::rotation_3d(PI / 2.0, -Vec4::unit_x())
|
||||
* Mat4::translation_3d(-self.focus);
|
||||
|
||||
let proj_mat = Mat4::perspective_rh_no(
|
||||
self.fov,
|
||||
self.aspect,
|
||||
NEAR_PLANE,
|
||||
FAR_PLANE,
|
||||
);
|
||||
let proj_mat = Mat4::perspective_rh_no(self.fov, self.aspect, NEAR_PLANE, FAR_PLANE);
|
||||
|
||||
// TODO: Make this more efficient
|
||||
let cam_pos = Vec3::from(view_mat.inverted() * Vec4::unit_w());
|
||||
@ -56,9 +51,7 @@ impl Camera {
|
||||
// Wrap camera yaw
|
||||
self.ori.x = (self.ori.x + delta.x) % (2.0 * PI);
|
||||
// Clamp camera pitch to the vertical limits
|
||||
self.ori.y = (self.ori.y + delta.y)
|
||||
.min(PI / 2.0)
|
||||
.max(-PI / 2.0);
|
||||
self.ori.y = (self.ori.y + delta.y).min(PI / 2.0).max(-PI / 2.0);
|
||||
// Wrap camera roll
|
||||
self.ori.z = (self.ori.z + delta.z) % (2.0 * PI);
|
||||
}
|
||||
@ -70,15 +63,25 @@ impl Camera {
|
||||
}
|
||||
|
||||
/// Get the focus position of the camera.
|
||||
pub fn get_focus_pos(&self) -> Vec3<f32> { self.focus }
|
||||
pub fn get_focus_pos(&self) -> Vec3<f32> {
|
||||
self.focus
|
||||
}
|
||||
/// Set the focus position of the camera.
|
||||
pub fn set_focus_pos(&mut self, focus: Vec3<f32>) { self.focus = focus; }
|
||||
pub fn set_focus_pos(&mut self, focus: Vec3<f32>) {
|
||||
self.focus = focus;
|
||||
}
|
||||
|
||||
/// Get the aspect ratio of the camera.
|
||||
pub fn get_aspect_ratio(&self) -> f32 { self.aspect }
|
||||
pub fn get_aspect_ratio(&self) -> f32 {
|
||||
self.aspect
|
||||
}
|
||||
/// Set the aspect ratio of the camera.
|
||||
pub fn set_aspect_ratio(&mut self, aspect: f32) { self.aspect = aspect; }
|
||||
pub fn set_aspect_ratio(&mut self, aspect: f32) {
|
||||
self.aspect = aspect;
|
||||
}
|
||||
|
||||
/// Get the orientation of the camera
|
||||
pub fn get_orientation(&self) -> Vec3<f32> { self.ori }
|
||||
pub fn get_orientation(&self) -> Vec3<f32> {
|
||||
self.ori
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +1,27 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
f32,
|
||||
use crate::{
|
||||
anim::{
|
||||
character::{CharacterSkeleton, IdleAnimation, RunAnimation},
|
||||
Animation, Skeleton,
|
||||
},
|
||||
mesh::Meshable,
|
||||
render::{
|
||||
Consts, FigureBoneData, FigureLocals, FigurePipeline, Globals, Mesh, Model, Renderer,
|
||||
},
|
||||
Error,
|
||||
};
|
||||
use specs::{Entity as EcsEntity, Component, VecStorage, Join};
|
||||
use vek::*;
|
||||
use client::Client;
|
||||
use common::{
|
||||
assets,
|
||||
comp::{
|
||||
self,
|
||||
character::{
|
||||
Character,
|
||||
Head,
|
||||
Chest,
|
||||
Belt,
|
||||
Pants,
|
||||
Hand,
|
||||
Foot,
|
||||
Weapon,
|
||||
}
|
||||
character::{Belt, Character, Chest, Foot, Hand, Head, Pants, Weapon},
|
||||
},
|
||||
figure::Segment,
|
||||
msg,
|
||||
assets,
|
||||
};
|
||||
use crate::{
|
||||
Error,
|
||||
render::{
|
||||
Consts,
|
||||
Globals,
|
||||
Mesh,
|
||||
Model,
|
||||
Renderer,
|
||||
FigurePipeline,
|
||||
FigureBoneData,
|
||||
FigureLocals,
|
||||
},
|
||||
anim::{
|
||||
Animation,
|
||||
Skeleton,
|
||||
character::{
|
||||
CharacterSkeleton,
|
||||
RunAnimation,
|
||||
IdleAnimation,
|
||||
},
|
||||
},
|
||||
mesh::Meshable,
|
||||
};
|
||||
use specs::{Component, Entity as EcsEntity, Join, VecStorage};
|
||||
use std::{collections::HashMap, f32};
|
||||
use vek::*;
|
||||
|
||||
pub struct FigureCache {
|
||||
models: HashMap<Character, (Model<FigurePipeline>, u64)>,
|
||||
@ -64,45 +40,52 @@ impl FigureCache {
|
||||
models: &'a mut HashMap<Character, (Model<FigurePipeline>, u64)>,
|
||||
renderer: &mut Renderer,
|
||||
tick: u64,
|
||||
character: Character)
|
||||
-> &'a (Model<FigurePipeline>, u64) {
|
||||
character: Character,
|
||||
) -> &'a (Model<FigurePipeline>, u64) {
|
||||
match models.get_mut(&character) {
|
||||
Some((model, last_used)) => {
|
||||
*last_used = tick;
|
||||
}
|
||||
None => {
|
||||
models.insert(character, ({
|
||||
let bone_meshes = [
|
||||
Some(Self::load_head(character.head)),
|
||||
Some(Self::load_chest(character.chest)),
|
||||
Some(Self::load_belt(character.belt)),
|
||||
Some(Self::load_pants(character.pants)),
|
||||
Some(Self::load_left_hand(character.hand)),
|
||||
Some(Self::load_right_hand(character.hand)),
|
||||
Some(Self::load_left_foot(character.foot)),
|
||||
Some(Self::load_right_foot(character.foot)),
|
||||
Some(Self::load_weapon(character.weapon)),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
];
|
||||
models.insert(
|
||||
character,
|
||||
(
|
||||
{
|
||||
let bone_meshes = [
|
||||
Some(Self::load_head(character.head)),
|
||||
Some(Self::load_chest(character.chest)),
|
||||
Some(Self::load_belt(character.belt)),
|
||||
Some(Self::load_pants(character.pants)),
|
||||
Some(Self::load_left_hand(character.hand)),
|
||||
Some(Self::load_right_hand(character.hand)),
|
||||
Some(Self::load_left_foot(character.foot)),
|
||||
Some(Self::load_right_foot(character.foot)),
|
||||
Some(Self::load_weapon(character.weapon)),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
];
|
||||
|
||||
let mut mesh = Mesh::new();
|
||||
bone_meshes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm)))
|
||||
.for_each(|(i, bone_mesh)| {
|
||||
mesh.push_mesh_map(bone_mesh, |vert| {
|
||||
vert.with_bone_idx(i as u8)
|
||||
})
|
||||
});
|
||||
|
||||
let mut mesh = Mesh::new();
|
||||
bone_meshes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, bm)| bm.as_ref().map(|bm| (i, bm)))
|
||||
.for_each(|(i, bone_mesh)| {
|
||||
mesh.push_mesh_map(bone_mesh, |vert| vert.with_bone_idx(i as u8))
|
||||
});
|
||||
|
||||
renderer.create_model(&mesh).unwrap()
|
||||
}, tick));
|
||||
renderer.create_model(&mesh).unwrap()
|
||||
},
|
||||
tick,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,76 +94,106 @@ impl FigureCache {
|
||||
|
||||
pub fn clean(&mut self, tick: u64) {
|
||||
// TODO: Don't hard-code this
|
||||
self.models.retain(|_, (_, last_used)| *last_used + 60 > tick);
|
||||
self.models
|
||||
.retain(|_, (_, last_used)| *last_used + 60 > tick);
|
||||
}
|
||||
|
||||
fn load_mesh(filename: &'static str, position: Vec3<f32>) -> Mesh<FigurePipeline> {
|
||||
let fullpath: String = ["/voxygen/voxel/", filename].concat();
|
||||
Segment::from(dot_vox::load_bytes(
|
||||
assets::load(fullpath.as_str())
|
||||
.expect("Error loading file")
|
||||
.as_slice(),
|
||||
).unwrap())
|
||||
.generate_mesh(position)
|
||||
Segment::from(
|
||||
dot_vox::load_bytes(
|
||||
assets::load(fullpath.as_str())
|
||||
.expect("Error loading file")
|
||||
.as_slice(),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.generate_mesh(position)
|
||||
}
|
||||
|
||||
fn load_head(head: Head) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(match head {
|
||||
Head::DefaultHead => "head.vox",
|
||||
}, Vec3::new(-5.5, -7.0, -6.0))
|
||||
Self::load_mesh(
|
||||
match head {
|
||||
Head::DefaultHead => "head.vox",
|
||||
},
|
||||
Vec3::new(-5.5, -7.0, -6.0),
|
||||
)
|
||||
}
|
||||
|
||||
fn load_chest(chest: Chest) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(match chest {
|
||||
Chest::DefaultChest => "chest.vox",
|
||||
}, Vec3::new(-2.5, -6.0, 0.0))
|
||||
Self::load_mesh(
|
||||
match chest {
|
||||
Chest::DefaultChest => "chest.vox",
|
||||
},
|
||||
Vec3::new(-2.5, -6.0, 0.0),
|
||||
)
|
||||
}
|
||||
|
||||
fn load_belt(belt: Belt) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(match belt {
|
||||
Belt::DefaultBelt => "belt.vox",
|
||||
}, Vec3::new(-2.5, -5.0, 0.0))
|
||||
Self::load_mesh(
|
||||
match belt {
|
||||
Belt::DefaultBelt => "belt.vox",
|
||||
},
|
||||
Vec3::new(-2.5, -5.0, 0.0),
|
||||
)
|
||||
}
|
||||
|
||||
fn load_pants(pants: Pants) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(match pants {
|
||||
Pants::DefaultPants => "pants.vox",
|
||||
}, Vec3::new(-2.5, -5.0, 0.0))
|
||||
Self::load_mesh(
|
||||
match pants {
|
||||
Pants::DefaultPants => "pants.vox",
|
||||
},
|
||||
Vec3::new(-2.5, -5.0, 0.0),
|
||||
)
|
||||
}
|
||||
|
||||
fn load_left_hand(hand: Hand) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(match hand {
|
||||
Hand::DefaultHand => "hand.vox",
|
||||
}, Vec3::new(0.0, -2.0, -7.0))
|
||||
Self::load_mesh(
|
||||
match hand {
|
||||
Hand::DefaultHand => "hand.vox",
|
||||
},
|
||||
Vec3::new(0.0, -2.0, -7.0),
|
||||
)
|
||||
}
|
||||
|
||||
fn load_right_hand(hand: Hand) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(match hand {
|
||||
Hand::DefaultHand => "hand.vox",
|
||||
}, Vec3::new(0.0, -2.0, -7.0))
|
||||
Self::load_mesh(
|
||||
match hand {
|
||||
Hand::DefaultHand => "hand.vox",
|
||||
},
|
||||
Vec3::new(0.0, -2.0, -7.0),
|
||||
)
|
||||
}
|
||||
|
||||
fn load_left_foot(foot: Foot) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(match foot {
|
||||
Foot::DefaultFoot => "foot.vox",
|
||||
}, Vec3::new(-3.5, -2.5, -8.0))
|
||||
Self::load_mesh(
|
||||
match foot {
|
||||
Foot::DefaultFoot => "foot.vox",
|
||||
},
|
||||
Vec3::new(-3.5, -2.5, -8.0),
|
||||
)
|
||||
}
|
||||
|
||||
fn load_right_foot(foot: Foot) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(match foot {
|
||||
Foot::DefaultFoot => "foot.vox",
|
||||
}, Vec3::new(-3.5, -2.5, -8.0))
|
||||
Self::load_mesh(
|
||||
match foot {
|
||||
Foot::DefaultFoot => "foot.vox",
|
||||
},
|
||||
Vec3::new(-3.5, -2.5, -8.0),
|
||||
)
|
||||
}
|
||||
|
||||
fn load_weapon(weapon: Weapon) -> Mesh<FigurePipeline> {
|
||||
Self::load_mesh(match weapon {
|
||||
Weapon::Sword => "sword.vox",
|
||||
// TODO actually match against other weapons and set the right model
|
||||
_ => "sword.vox",
|
||||
}, Vec3::new(0.0, 0.0, -4.0))
|
||||
Self::load_mesh(
|
||||
match weapon {
|
||||
Weapon::Sword => "sword.vox",
|
||||
// TODO actually match against other weapons and set the right model
|
||||
_ => "sword.vox",
|
||||
},
|
||||
Vec3::new(0.0, 0.0, -4.0),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) {
|
||||
let time = client.state().get_time();
|
||||
let ecs = client.state_mut().ecs_mut();
|
||||
@ -190,14 +203,21 @@ impl FigureCache {
|
||||
&ecs.read_storage::<comp::phys::Dir>(),
|
||||
&ecs.read_storage::<comp::Character>(),
|
||||
&ecs.read_storage::<comp::AnimationHistory>(),
|
||||
).join() {
|
||||
let state = self.states
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let state = self
|
||||
.states
|
||||
.entry(entity)
|
||||
.or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
|
||||
|
||||
let target_skeleton = match animation_history.current {
|
||||
comp::character::Animation::Idle => IdleAnimation::update_skeleton(&mut state.skeleton, time),
|
||||
comp::character::Animation::Run => RunAnimation::update_skeleton(&mut state.skeleton, time),
|
||||
comp::character::Animation::Idle => {
|
||||
IdleAnimation::update_skeleton(&mut state.skeleton, time)
|
||||
}
|
||||
comp::character::Animation::Run => {
|
||||
RunAnimation::update_skeleton(&mut state.skeleton, time)
|
||||
}
|
||||
};
|
||||
|
||||
state.skeleton.interpolate(&target_skeleton);
|
||||
@ -205,26 +225,25 @@ impl FigureCache {
|
||||
state.update(renderer, pos.0, dir.0);
|
||||
}
|
||||
|
||||
self.states.retain(|entity, _| ecs.entities().is_alive(*entity));
|
||||
self.states
|
||||
.retain(|entity, _| ecs.entities().is_alive(*entity));
|
||||
}
|
||||
|
||||
pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client, globals: &Consts<Globals>) {
|
||||
pub fn render(
|
||||
&mut self,
|
||||
renderer: &mut Renderer,
|
||||
client: &mut Client,
|
||||
globals: &Consts<Globals>,
|
||||
) {
|
||||
let tick = client.get_tick();
|
||||
let ecs = client.state().ecs();
|
||||
let models = &mut self.models;
|
||||
|
||||
for (entity, &character) in (
|
||||
&ecs.entities(),
|
||||
&ecs.read_storage::<comp::Character>(),
|
||||
).join() {
|
||||
for (entity, &character) in (&ecs.entities(), &ecs.read_storage::<comp::Character>()).join()
|
||||
{
|
||||
let model = Self::get_or_create_model(models, renderer, tick, character);
|
||||
let state = self.states.get(&entity).unwrap();
|
||||
renderer.render_figure(
|
||||
&model.0,
|
||||
globals,
|
||||
&state.locals,
|
||||
&state.bone_consts,
|
||||
);
|
||||
renderer.render_figure(&model.0, globals, &state.locals, &state.bone_consts);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -238,21 +257,24 @@ pub struct FigureState<S: Skeleton> {
|
||||
impl<S: Skeleton> FigureState<S> {
|
||||
pub fn new(renderer: &mut Renderer, skeleton: S) -> Self {
|
||||
Self {
|
||||
bone_consts: renderer.create_consts(&skeleton.compute_matrices()).unwrap(),
|
||||
bone_consts: renderer
|
||||
.create_consts(&skeleton.compute_matrices())
|
||||
.unwrap(),
|
||||
locals: renderer.create_consts(&[FigureLocals::default()]).unwrap(),
|
||||
skeleton,
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, renderer: &mut Renderer, pos: Vec3<f32>, dir: Vec3<f32>) {
|
||||
let mat =
|
||||
Mat4::<f32>::identity() *
|
||||
Mat4::translation_3d(pos) *
|
||||
Mat4::rotation_z(-dir.x.atan2(dir.y) + f32::consts::PI / 2.0);
|
||||
let mat = Mat4::<f32>::identity()
|
||||
* Mat4::translation_3d(pos)
|
||||
* Mat4::rotation_z(-dir.x.atan2(dir.y) + f32::consts::PI / 2.0);
|
||||
|
||||
let locals = FigureLocals::new(mat);
|
||||
renderer.update_consts(&mut self.locals, &[locals]).unwrap();
|
||||
|
||||
renderer.update_consts(&mut self.bone_consts, &self.skeleton.compute_matrices()).unwrap();
|
||||
renderer
|
||||
.update_consts(&mut self.bone_consts, &self.skeleton.compute_matrices())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -2,35 +2,23 @@ pub mod camera;
|
||||
pub mod figure;
|
||||
pub mod terrain;
|
||||
|
||||
use vek::*;
|
||||
use dot_vox;
|
||||
use common::{
|
||||
comp,
|
||||
figure::Segment,
|
||||
};
|
||||
use client::Client;
|
||||
use self::{camera::Camera, figure::FigureCache, terrain::Terrain};
|
||||
use crate::{
|
||||
anim::{
|
||||
character::{CharacterSkeleton, RunAnimation},
|
||||
Animation,
|
||||
},
|
||||
mesh::Meshable,
|
||||
render::{
|
||||
Consts,
|
||||
Globals,
|
||||
Model,
|
||||
Renderer,
|
||||
create_skybox_mesh, Consts, FigureLocals, Globals, Model, Renderer, SkyboxLocals,
|
||||
SkyboxPipeline,
|
||||
SkyboxLocals,
|
||||
FigureLocals,
|
||||
create_skybox_mesh,
|
||||
},
|
||||
window::Event,
|
||||
mesh::Meshable, anim::{
|
||||
Animation,
|
||||
character::{CharacterSkeleton, RunAnimation},
|
||||
},
|
||||
};
|
||||
use self::{
|
||||
camera::Camera,
|
||||
figure::FigureCache,
|
||||
terrain::Terrain,
|
||||
};
|
||||
use client::Client;
|
||||
use common::{comp, figure::Segment};
|
||||
use dot_vox;
|
||||
use vek::*;
|
||||
|
||||
// TODO: Don't hard-code this
|
||||
const CURSOR_PAN_SCALE: f32 = 0.005;
|
||||
@ -56,18 +44,12 @@ impl Scene {
|
||||
let resolution = renderer.get_resolution().map(|e| e as f32);
|
||||
|
||||
Self {
|
||||
globals: renderer
|
||||
.create_consts(&[Globals::default()])
|
||||
.unwrap(),
|
||||
globals: renderer.create_consts(&[Globals::default()]).unwrap(),
|
||||
camera: Camera::new(resolution.x / resolution.y),
|
||||
|
||||
skybox: Skybox {
|
||||
model: renderer
|
||||
.create_model(&create_skybox_mesh())
|
||||
.unwrap(),
|
||||
locals: renderer
|
||||
.create_consts(&[SkyboxLocals::default()])
|
||||
.unwrap(),
|
||||
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
|
||||
locals: renderer.create_consts(&[SkyboxLocals::default()]).unwrap(),
|
||||
},
|
||||
terrain: Terrain::new(),
|
||||
figure_cache: FigureCache::new(),
|
||||
@ -75,10 +57,14 @@ impl Scene {
|
||||
}
|
||||
|
||||
/// Get a reference to the scene's camera.
|
||||
pub fn camera(&self) -> &Camera { &self.camera }
|
||||
pub fn camera(&self) -> &Camera {
|
||||
&self.camera
|
||||
}
|
||||
|
||||
/// Get a mutable reference to the scene's camera.
|
||||
pub fn camera_mut(&mut self) -> &mut Camera { &mut self.camera }
|
||||
pub fn camera_mut(&mut self) -> &mut Camera {
|
||||
&mut self.camera
|
||||
}
|
||||
|
||||
/// Handle an incoming user input event (i.e: cursor moved, key pressed, window closed, etc.).
|
||||
///
|
||||
@ -89,17 +75,17 @@ impl Scene {
|
||||
Event::Resize(dims) => {
|
||||
self.camera.set_aspect_ratio(dims.x as f32 / dims.y as f32);
|
||||
true
|
||||
},
|
||||
}
|
||||
// Panning the cursor makes the camera rotate
|
||||
Event::CursorPan(delta) => {
|
||||
self.camera.rotate_by(Vec3::from(delta) * CURSOR_PAN_SCALE);
|
||||
true
|
||||
},
|
||||
}
|
||||
// Zoom the camera when a zoom event occurs
|
||||
Event::Zoom(delta) => {
|
||||
self.camera.zoom_by(delta * 0.3);
|
||||
true
|
||||
},
|
||||
}
|
||||
// All other events are unhandled
|
||||
_ => false,
|
||||
}
|
||||
@ -123,15 +109,19 @@ impl Scene {
|
||||
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents();
|
||||
|
||||
// Update global constants
|
||||
renderer.update_consts(&mut self.globals, &[Globals::new(
|
||||
view_mat,
|
||||
proj_mat,
|
||||
cam_pos,
|
||||
self.camera.get_focus_pos(),
|
||||
10.0,
|
||||
client.state().get_time_of_day(),
|
||||
client.state().get_time(),
|
||||
)])
|
||||
renderer
|
||||
.update_consts(
|
||||
&mut self.globals,
|
||||
&[Globals::new(
|
||||
view_mat,
|
||||
proj_mat,
|
||||
cam_pos,
|
||||
self.camera.get_focus_pos(),
|
||||
10.0,
|
||||
client.state().get_time_of_day(),
|
||||
client.state().get_time(),
|
||||
)],
|
||||
)
|
||||
.expect("Failed to update global constants");
|
||||
|
||||
// Maintain the terrain
|
||||
@ -147,11 +137,7 @@ impl Scene {
|
||||
/// Render the scene using the provided `Renderer`
|
||||
pub fn render(&mut self, renderer: &mut Renderer, client: &mut Client) {
|
||||
// Render the skybox first (it appears over everything else so must be rendered first)
|
||||
renderer.render_skybox(
|
||||
&self.skybox.model,
|
||||
&self.globals,
|
||||
&self.skybox.locals,
|
||||
);
|
||||
renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
|
||||
|
||||
// Render terrain and figures
|
||||
self.terrain.render(renderer, &self.globals);
|
||||
|
@ -10,24 +10,12 @@ use vek::*;
|
||||
|
||||
// Project
|
||||
use client::Client;
|
||||
use common::{
|
||||
terrain::TerrainMap,
|
||||
volumes::vol_map::VolMapErr,
|
||||
vol::SampleVol,
|
||||
};
|
||||
use common::{terrain::TerrainMap, vol::SampleVol, volumes::vol_map::VolMapErr};
|
||||
|
||||
// Crate
|
||||
use crate::{
|
||||
render::{
|
||||
Consts,
|
||||
Globals,
|
||||
Mesh,
|
||||
Model,
|
||||
Renderer,
|
||||
TerrainPipeline,
|
||||
TerrainLocals,
|
||||
},
|
||||
mesh::Meshable,
|
||||
render::{Consts, Globals, Mesh, Model, Renderer, TerrainLocals, TerrainPipeline},
|
||||
};
|
||||
|
||||
struct TerrainChunk {
|
||||
@ -92,7 +80,11 @@ impl Terrain {
|
||||
let current_tick = client.get_tick();
|
||||
|
||||
// Add any recently created or changed chunks to the list of chunks to be meshed
|
||||
for pos in client.state().changes().new_chunks.iter()
|
||||
for pos in client
|
||||
.state()
|
||||
.changes()
|
||||
.new_chunks
|
||||
.iter()
|
||||
.chain(client.state().changes().changed_chunks.iter())
|
||||
{
|
||||
// TODO: ANOTHER PROBLEM HERE!
|
||||
@ -139,8 +131,12 @@ impl Terrain {
|
||||
// ambient occlusion and edge elision, we also need to borders of the chunk's
|
||||
// neighbours too (hence the `- 1` and `+ 1`).
|
||||
let aabb = Aabb {
|
||||
min: todo.pos.map2(TerrainMap::chunk_size(), |e, sz| e * sz as i32 - 1),
|
||||
max: todo.pos.map2(TerrainMap::chunk_size(), |e, sz| (e + 1) * sz as i32 + 1),
|
||||
min: todo
|
||||
.pos
|
||||
.map2(TerrainMap::chunk_size(), |e, sz| e * sz as i32 - 1),
|
||||
max: todo
|
||||
.pos
|
||||
.map2(TerrainMap::chunk_size(), |e, sz| (e + 1) * sz as i32 + 1),
|
||||
};
|
||||
|
||||
// Copy out the chunk data we need to perform the meshing. We do this by taking a
|
||||
@ -173,27 +169,35 @@ impl Terrain {
|
||||
// It's the mesh we want, insert the newly finished model into the terrain model
|
||||
// data structure (convert the mesh to a model first of course)
|
||||
Some(todo) if response.started_tick == todo.started_tick => {
|
||||
self.chunks.insert(response.pos, TerrainChunk {
|
||||
model: renderer.create_model(&response.mesh).expect("Failed to upload chunk mesh to the GPU"),
|
||||
locals: renderer.create_consts(&[TerrainLocals {
|
||||
model_offs: response.pos.map2(TerrainMap::chunk_size(), |e, sz| e as f32 * sz as f32).into_array(),
|
||||
}]).expect("Failed to upload chunk locals to the GPU"),
|
||||
});
|
||||
},
|
||||
self.chunks.insert(
|
||||
response.pos,
|
||||
TerrainChunk {
|
||||
model: renderer
|
||||
.create_model(&response.mesh)
|
||||
.expect("Failed to upload chunk mesh to the GPU"),
|
||||
locals: renderer
|
||||
.create_consts(&[TerrainLocals {
|
||||
model_offs: response
|
||||
.pos
|
||||
.map2(TerrainMap::chunk_size(), |e, sz| {
|
||||
e as f32 * sz as f32
|
||||
})
|
||||
.into_array(),
|
||||
}])
|
||||
.expect("Failed to upload chunk locals to the GPU"),
|
||||
},
|
||||
);
|
||||
}
|
||||
// Chunk must have been removed, or it was spawned on an old tick. Drop the mesh
|
||||
// since it's either out of date or no longer needed
|
||||
_ => {},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) {
|
||||
for (_, chunk) in &self.chunks {
|
||||
renderer.render_terrain_chunk(
|
||||
&chunk.model,
|
||||
globals,
|
||||
&chunk.locals,
|
||||
);
|
||||
renderer.render_terrain_chunk(&chunk.model, globals, &chunk.locals);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,23 +1,16 @@
|
||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
use vek::*;
|
||||
use common::clock::Clock;
|
||||
use client::{
|
||||
self,
|
||||
Client,
|
||||
};
|
||||
use crate::{
|
||||
Direction,
|
||||
Error,
|
||||
PlayState,
|
||||
PlayStateResult,
|
||||
GlobalState,
|
||||
hud::{Event as HudEvent, Hud},
|
||||
key_state::KeyState,
|
||||
window::{Event, Key, Window},
|
||||
render::Renderer,
|
||||
scene::Scene,
|
||||
settings::Settings,
|
||||
hud::{Hud, Event as HudEvent},
|
||||
window::{Event, Key, Window},
|
||||
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use client::{self, Client};
|
||||
use common::clock::Clock;
|
||||
use std::{cell::RefCell, rc::Rc, time::Duration};
|
||||
use vek::*;
|
||||
|
||||
const FPS: u64 = 60;
|
||||
|
||||
@ -28,7 +21,6 @@ pub struct SessionState {
|
||||
hud: Hud,
|
||||
}
|
||||
|
||||
|
||||
/// Represents an active game session (i.e: one that is being played)
|
||||
impl SessionState {
|
||||
/// Create a new `SessionState`
|
||||
@ -44,7 +36,6 @@ impl SessionState {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The background colour
|
||||
const BG_COLOR: Rgba<f32> = Rgba {
|
||||
r: 0.0,
|
||||
@ -65,7 +56,11 @@ impl SessionState {
|
||||
let dir_vec = self.key_state.dir_vec();
|
||||
let move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1];
|
||||
|
||||
for event in self.client.borrow_mut().tick(client::Input { move_dir }, dt)? {
|
||||
for event in self
|
||||
.client
|
||||
.borrow_mut()
|
||||
.tick(client::Input { move_dir }, dt)?
|
||||
{
|
||||
match event {
|
||||
client::Event::Chat(msg) => {
|
||||
self.hud.new_message(msg);
|
||||
@ -124,7 +119,6 @@ impl PlayState for SessionState {
|
||||
loop {
|
||||
// Handle window events
|
||||
for event in global_state.window.fetch_events() {
|
||||
|
||||
// Pass all events to the ui first
|
||||
if self.hud.handle_event(event.clone(), global_state) {
|
||||
continue;
|
||||
@ -132,7 +126,7 @@ impl PlayState for SessionState {
|
||||
let _handled = match event {
|
||||
Event::Close => {
|
||||
return PlayStateResult::Shutdown;
|
||||
},
|
||||
}
|
||||
// Toggle cursor grabbing
|
||||
Event::KeyDown(Key::ToggleCursor) => {
|
||||
global_state
|
||||
@ -162,18 +156,24 @@ impl PlayState for SessionState {
|
||||
.expect("Failed to tick the scene");
|
||||
|
||||
// Maintain the scene
|
||||
self.scene.maintain(global_state.window.renderer_mut(), &mut self.client.borrow_mut());
|
||||
self.scene.maintain(
|
||||
global_state.window.renderer_mut(),
|
||||
&mut self.client.borrow_mut(),
|
||||
);
|
||||
// Maintain the UI
|
||||
for event in self.hud.maintain(global_state.window.renderer_mut(), clock.get_tps()) {
|
||||
for event in self
|
||||
.hud
|
||||
.maintain(global_state.window.renderer_mut(), clock.get_tps())
|
||||
{
|
||||
match event {
|
||||
HudEvent::SendMessage(msg) => {
|
||||
// TODO: Handle result
|
||||
self.client.borrow_mut().send_chat(msg);
|
||||
},
|
||||
}
|
||||
HudEvent::Logout => return PlayStateResult::Pop,
|
||||
HudEvent::Quit => {
|
||||
return PlayStateResult::Shutdown;
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,9 @@
|
||||
use std::time::Duration;
|
||||
use log::info;
|
||||
use server::{Input, Event, Server};
|
||||
use common::clock::Clock;
|
||||
use std::{
|
||||
thread,
|
||||
thread::JoinHandle
|
||||
};
|
||||
use std::sync::mpsc::{
|
||||
channel, Receiver, Sender, TryRecvError,
|
||||
};
|
||||
use log::info;
|
||||
use server::{Event, Input, Server};
|
||||
use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
|
||||
use std::time::Duration;
|
||||
use std::{thread, thread::JoinHandle};
|
||||
|
||||
const TPS: u64 = 30;
|
||||
|
||||
@ -49,11 +44,11 @@ fn run_server(rec: Receiver<Msg>) {
|
||||
let mut clock = Clock::new();
|
||||
|
||||
// Create server
|
||||
let mut server = Server::new()
|
||||
.expect("Failed to create server instance");
|
||||
let mut server = Server::new().expect("Failed to create server instance");
|
||||
|
||||
loop {
|
||||
let events = server.tick(Input::default(), clock.get_last_delta())
|
||||
let events = server
|
||||
.tick(Input::default(), clock.get_last_delta())
|
||||
.expect("Failed to tick server");
|
||||
|
||||
for event in events {
|
||||
|
@ -70,7 +70,7 @@ pub fn draw_vox(segment: &Segment, output_size: Vec2<u16>) -> Vec<[u8; 4]> {
|
||||
top: 1.0,
|
||||
near: 0.0,
|
||||
far: 1.0,
|
||||
}) * Mat4::rotation_x(-std::f32::consts::PI / 2.0)
|
||||
}) * Mat4::rotation_x(-std::f32::consts::PI / 2.0)
|
||||
* Mat4::scaling_3d([2.0 / w, 2.0 / h, 2.0 / d])
|
||||
* Mat4::translation_3d([-w / 2.0, -h / 2.0, -d / 2.0]);
|
||||
Voxel { mvp }.draw::<rasterizer::Triangles<_>, _>(
|
||||
|
@ -1,46 +1,30 @@
|
||||
mod widgets;
|
||||
mod graphic;
|
||||
mod util;
|
||||
mod widgets;
|
||||
|
||||
pub use widgets::toggle_button::ToggleButton;
|
||||
pub use graphic::Graphic;
|
||||
pub(self) use util::{srgb_to_linear, linear_to_srgb};
|
||||
pub(self) use util::{linear_to_srgb, srgb_to_linear};
|
||||
pub use widgets::toggle_button::ToggleButton;
|
||||
|
||||
use graphic::{
|
||||
GraphicCache,
|
||||
Id as GraphicId,
|
||||
};
|
||||
use conrod_core::{
|
||||
Ui as CrUi,
|
||||
UiBuilder,
|
||||
UiCell,
|
||||
text::{
|
||||
Font,
|
||||
GlyphCache,
|
||||
font::Id as FontId,
|
||||
},
|
||||
image::{Map, Id as ImgId},
|
||||
widget::{Id as WidgId, id::Generator},
|
||||
render::Primitive,
|
||||
event::Input,
|
||||
input::{touch::Touch, Widget, Motion, Button},
|
||||
};
|
||||
use vek::*;
|
||||
use crate::{
|
||||
Error,
|
||||
render::{
|
||||
RenderError,
|
||||
Renderer,
|
||||
Model,
|
||||
Mesh,
|
||||
Texture,
|
||||
create_ui_quad, create_ui_tri, Mesh, Model, RenderError, Renderer, Texture, UiMode,
|
||||
UiPipeline,
|
||||
UiMode,
|
||||
create_ui_quad,
|
||||
create_ui_tri,
|
||||
},
|
||||
window::Window,
|
||||
Error,
|
||||
};
|
||||
use conrod_core::{
|
||||
event::Input,
|
||||
image::{Id as ImgId, Map},
|
||||
input::{touch::Touch, Button, Motion, Widget},
|
||||
render::Primitive,
|
||||
text::{font::Id as FontId, Font, GlyphCache},
|
||||
widget::{id::Generator, Id as WidgId},
|
||||
Ui as CrUi, UiBuilder, UiCell,
|
||||
};
|
||||
use graphic::{GraphicCache, Id as GraphicId};
|
||||
use vek::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum UiError {
|
||||
@ -66,19 +50,23 @@ impl Event {
|
||||
winit::Window::get_hidpi_factor(&self.0) as _
|
||||
}
|
||||
}
|
||||
convert_event!(event, &WindowRef(window.window())).map(|input| {
|
||||
Self(input)
|
||||
})
|
||||
convert_event!(event, &WindowRef(window.window())).map(|input| Self(input))
|
||||
}
|
||||
pub fn is_keyboard_or_mouse(&self) -> bool {
|
||||
match self.0 {
|
||||
Input::Press(_) | Input::Release(_) | Input::Motion(_) | Input::Touch(_) | Input::Text(_) => true,
|
||||
Input::Press(_)
|
||||
| Input::Release(_)
|
||||
| Input::Motion(_)
|
||||
| Input::Touch(_)
|
||||
| Input::Text(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
pub fn is_keyboard(&self) -> bool {
|
||||
match self.0 {
|
||||
Input::Press(Button::Keyboard(_)) | Input::Release(Button::Keyboard(_)) | Input::Text(_) => true,
|
||||
Input::Press(Button::Keyboard(_))
|
||||
| Input::Release(Button::Keyboard(_))
|
||||
| Input::Text(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -113,11 +101,21 @@ impl Cache {
|
||||
graphic_cache_tex: renderer.create_dynamic_texture(graphic_cache_dims)?,
|
||||
})
|
||||
}
|
||||
pub fn glyph_cache_tex(&self) -> &Texture<UiPipeline> { &self.glyph_cache_tex }
|
||||
pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture<UiPipeline>) { (&mut self.glyph_cache, &self.glyph_cache_tex) }
|
||||
pub fn graphic_cache_tex(&self) -> &Texture<UiPipeline> { &self.graphic_cache_tex }
|
||||
pub fn graphic_cache_mut_and_tex(&mut self) -> (&mut GraphicCache, &Texture<UiPipeline>) { (&mut self.graphic_cache, &self.graphic_cache_tex) }
|
||||
pub fn new_graphic(&mut self, graphic: Graphic) -> GraphicId { self.graphic_cache.new_graphic(graphic) }
|
||||
pub fn glyph_cache_tex(&self) -> &Texture<UiPipeline> {
|
||||
&self.glyph_cache_tex
|
||||
}
|
||||
pub fn glyph_cache_mut_and_tex(&mut self) -> (&mut GlyphCache<'static>, &Texture<UiPipeline>) {
|
||||
(&mut self.glyph_cache, &self.glyph_cache_tex)
|
||||
}
|
||||
pub fn graphic_cache_tex(&self) -> &Texture<UiPipeline> {
|
||||
&self.graphic_cache_tex
|
||||
}
|
||||
pub fn graphic_cache_mut_and_tex(&mut self) -> (&mut GraphicCache, &Texture<UiPipeline>) {
|
||||
(&mut self.graphic_cache, &self.graphic_cache_tex)
|
||||
}
|
||||
pub fn new_graphic(&mut self, graphic: Graphic) -> GraphicId {
|
||||
self.graphic_cache.new_graphic(graphic)
|
||||
}
|
||||
pub fn clear_graphic_cache(&mut self, renderer: &mut Renderer, new_size: Vec2<u16>) {
|
||||
self.graphic_cache.clear_cache(new_size);
|
||||
self.graphic_cache_tex = renderer.create_dynamic_texture(new_size).unwrap();
|
||||
@ -190,7 +188,9 @@ impl Scale {
|
||||
match self.mode {
|
||||
ScaleMode::Absolute(scale) => scale / self.dpi_factor,
|
||||
ScaleMode::DpiFactor => 1.0,
|
||||
ScaleMode::RelativeToWindow(dims) => (self.window_dims.x / dims.x).min(self.window_dims.y / dims.y),
|
||||
ScaleMode::RelativeToWindow(dims) => {
|
||||
(self.window_dims.x / dims.x).min(self.window_dims.y / dims.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Calculate factor to transform between physical coordinates and our scaled coordinates
|
||||
@ -277,35 +277,36 @@ impl Ui {
|
||||
|
||||
// Get whether a widget besides the window is capturing the mouse
|
||||
pub fn no_widget_capturing_mouse(&self) -> bool {
|
||||
self.ui.global_input().current.widget_capturing_mouse.filter(|id| id != &self.ui.window ).is_none()
|
||||
self.ui
|
||||
.global_input()
|
||||
.current
|
||||
.widget_capturing_mouse
|
||||
.filter(|id| id != &self.ui.window)
|
||||
.is_none()
|
||||
}
|
||||
|
||||
pub fn handle_event(&mut self, event: Event) {
|
||||
match event.0 {
|
||||
Input::Resize(w, h) => self.window_resized = Some(Vec2::new(w, h)),
|
||||
Input::Touch(touch) => self.ui.handle_event(
|
||||
Input::Touch(Touch {
|
||||
xy: self.scale.scale_point(touch.xy.into()).into_array(),
|
||||
..touch
|
||||
})
|
||||
),
|
||||
Input::Motion(motion) => self.ui.handle_event(
|
||||
Input::Motion( match motion {
|
||||
Motion::MouseCursor { x, y } => {
|
||||
let (x, y) = self.scale.scale_point(Vec2::new(x, y)).into_tuple();
|
||||
Motion::MouseCursor { x, y }
|
||||
}
|
||||
Motion::MouseRelative { x, y } => {
|
||||
let (x, y) = self.scale.scale_point(Vec2::new(x, y)).into_tuple();
|
||||
Motion::MouseRelative { x, y }
|
||||
}
|
||||
Motion::Scroll { x, y } => {
|
||||
let (x, y) = self.scale.scale_point(Vec2::new(x, y)).into_tuple();
|
||||
Motion::Scroll { x, y }
|
||||
}
|
||||
_ => motion,
|
||||
})
|
||||
),
|
||||
Input::Touch(touch) => self.ui.handle_event(Input::Touch(Touch {
|
||||
xy: self.scale.scale_point(touch.xy.into()).into_array(),
|
||||
..touch
|
||||
})),
|
||||
Input::Motion(motion) => self.ui.handle_event(Input::Motion(match motion {
|
||||
Motion::MouseCursor { x, y } => {
|
||||
let (x, y) = self.scale.scale_point(Vec2::new(x, y)).into_tuple();
|
||||
Motion::MouseCursor { x, y }
|
||||
}
|
||||
Motion::MouseRelative { x, y } => {
|
||||
let (x, y) = self.scale.scale_point(Vec2::new(x, y)).into_tuple();
|
||||
Motion::MouseRelative { x, y }
|
||||
}
|
||||
Motion::Scroll { x, y } => {
|
||||
let (x, y) = self.scale.scale_point(Vec2::new(x, y)).into_tuple();
|
||||
Motion::Scroll { x, y }
|
||||
}
|
||||
_ => motion,
|
||||
})),
|
||||
_ => self.ui.handle_event(event.0),
|
||||
}
|
||||
}
|
||||
@ -338,7 +339,8 @@ impl Ui {
|
||||
macro_rules! switch_to_plain_state {
|
||||
() => {
|
||||
if let State::Image = current_state {
|
||||
self.draw_commands.push(DrawCommand::image(renderer.create_model(&mesh).unwrap()));
|
||||
self.draw_commands
|
||||
.push(DrawCommand::image(renderer.create_model(&mesh).unwrap()));
|
||||
mesh.clear();
|
||||
current_state = State::Plain;
|
||||
}
|
||||
@ -348,7 +350,12 @@ impl Ui {
|
||||
let p_scale_factor = self.scale.scale_factor_physical();
|
||||
|
||||
while let Some(prim) = primitives.next() {
|
||||
let Primitive {kind, scizzor, id: _id, rect} = prim;
|
||||
let Primitive {
|
||||
kind,
|
||||
scizzor,
|
||||
id: _id,
|
||||
rect,
|
||||
} = prim;
|
||||
|
||||
// Check for a change in the scizzor
|
||||
let new_scizzor = {
|
||||
@ -366,17 +373,15 @@ impl Ui {
|
||||
max: Vec2 {
|
||||
x: ((min_x + w) * p_scale_factor) as u16,
|
||||
y: ((min_y + h) * p_scale_factor) as u16,
|
||||
}
|
||||
},
|
||||
}
|
||||
.intersection(window_scizzor)
|
||||
};
|
||||
if new_scizzor != current_scizzor {
|
||||
// Finish the current command
|
||||
self.draw_commands.push(match current_state {
|
||||
State::Plain =>
|
||||
DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
||||
State::Image =>
|
||||
DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
||||
State::Plain => DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
||||
State::Image => DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
||||
});
|
||||
mesh.clear();
|
||||
|
||||
@ -398,8 +403,15 @@ impl Ui {
|
||||
|
||||
use conrod_core::render::PrimitiveKind;
|
||||
match kind {
|
||||
PrimitiveKind::Image { image_id, color, source_rect } => {
|
||||
let graphic_id = self.image_map.get(&image_id).expect("Image does not exist in image map");
|
||||
PrimitiveKind::Image {
|
||||
image_id,
|
||||
color,
|
||||
source_rect,
|
||||
} => {
|
||||
let graphic_id = self
|
||||
.image_map
|
||||
.get(&image_id)
|
||||
.expect("Image does not exist in image map");
|
||||
let (graphic_cache, cache_tex) = self.cache.graphic_cache_mut_and_tex();
|
||||
|
||||
match graphic_cache.get_graphic(*graphic_id) {
|
||||
@ -409,13 +421,15 @@ impl Ui {
|
||||
|
||||
// Switch to the `Image` state for this image if we're not in it already.
|
||||
if let State::Plain = current_state {
|
||||
self.draw_commands.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap()));
|
||||
self.draw_commands
|
||||
.push(DrawCommand::plain(renderer.create_model(&mesh).unwrap()));
|
||||
mesh.clear();
|
||||
current_state = State::Image;
|
||||
}
|
||||
|
||||
let color = srgb_to_linear(color.unwrap_or(conrod_core::color::WHITE).to_fsa().into());
|
||||
|
||||
let color = srgb_to_linear(
|
||||
color.unwrap_or(conrod_core::color::WHITE).to_fsa().into(),
|
||||
);
|
||||
|
||||
let resolution = Vec2::new(
|
||||
(rect.w() * p_scale_factor) as u16,
|
||||
@ -424,32 +438,44 @@ impl Ui {
|
||||
// Transform the source rectangle into uv coordinate
|
||||
// TODO: make sure this is right
|
||||
let source_aabr = {
|
||||
let (uv_l, uv_r, uv_b, uv_t) = (0.0, 1.0, 0.0, 1.0);/*match source_rect {
|
||||
Some(src_rect) => {
|
||||
let (l, r, b, t) = src_rect.l_r_b_t();
|
||||
((l / image_w) as f32,
|
||||
(r / image_w) as f32,
|
||||
(b / image_h) as f32,
|
||||
(t / image_h) as f32)
|
||||
}
|
||||
None => (0.0, 1.0, 0.0, 1.0),
|
||||
};*/
|
||||
let (uv_l, uv_r, uv_b, uv_t) = (0.0, 1.0, 0.0, 1.0); /*match source_rect {
|
||||
Some(src_rect) => {
|
||||
let (l, r, b, t) = src_rect.l_r_b_t();
|
||||
((l / image_w) as f32,
|
||||
(r / image_w) as f32,
|
||||
(b / image_h) as f32,
|
||||
(t / image_h) as f32)
|
||||
}
|
||||
None => (0.0, 1.0, 0.0, 1.0),
|
||||
};*/
|
||||
Aabr {
|
||||
min: Vec2::new(uv_l, uv_b),
|
||||
max: Vec2::new(uv_r, uv_t),
|
||||
}
|
||||
};
|
||||
let (cache_w, cache_h) = cache_tex.get_dimensions().map(|e| e as f32).into_tuple();
|
||||
let (cache_w, cache_h) =
|
||||
cache_tex.get_dimensions().map(|e| e as f32).into_tuple();
|
||||
|
||||
// Cache graphic at particular resolution
|
||||
let uv_aabr = match graphic_cache.cache_res(*graphic_id, resolution, source_aabr, |aabr, data| {
|
||||
let offset = aabr.min.into_array();
|
||||
let size = aabr.size().into_array();
|
||||
renderer.update_texture(cache_tex, offset, size, &data);
|
||||
}) {
|
||||
let uv_aabr = match graphic_cache.cache_res(
|
||||
*graphic_id,
|
||||
resolution,
|
||||
source_aabr,
|
||||
|aabr, data| {
|
||||
let offset = aabr.min.into_array();
|
||||
let size = aabr.size().into_array();
|
||||
renderer.update_texture(cache_tex, offset, size, &data);
|
||||
},
|
||||
) {
|
||||
Some(aabr) => Aabr {
|
||||
min: Vec2::new(aabr.min.x as f32 / cache_w, aabr.max.y as f32 / cache_h),
|
||||
max: Vec2::new(aabr.max.x as f32 / cache_w, aabr.min.y as f32 / cache_h),
|
||||
min: Vec2::new(
|
||||
aabr.min.x as f32 / cache_w,
|
||||
aabr.max.y as f32 / cache_h,
|
||||
),
|
||||
max: Vec2::new(
|
||||
aabr.max.x as f32 / cache_w,
|
||||
aabr.min.y as f32 / cache_h,
|
||||
),
|
||||
},
|
||||
None => continue,
|
||||
};
|
||||
@ -460,12 +486,16 @@ impl Ui {
|
||||
color,
|
||||
UiMode::Image,
|
||||
));
|
||||
|
||||
}
|
||||
PrimitiveKind::Text { color, text, font_id } => {
|
||||
PrimitiveKind::Text {
|
||||
color,
|
||||
text,
|
||||
font_id,
|
||||
} => {
|
||||
switch_to_plain_state!();
|
||||
// Get screen width and height
|
||||
let (screen_w, screen_h) = renderer.get_resolution().map(|e| e as f32).into_tuple();
|
||||
let (screen_w, screen_h) =
|
||||
renderer.get_resolution().map(|e| e as f32).into_tuple();
|
||||
// Calculate dpi factor
|
||||
let dpi_factor = screen_w / ui.win_w as f32;
|
||||
|
||||
@ -476,39 +506,41 @@ impl Ui {
|
||||
glyph_cache.queue_glyph(font_id.index(), glyph.clone());
|
||||
}
|
||||
|
||||
glyph_cache.cache_queued(|rect, data| {
|
||||
let offset = [rect.min.x as u16, rect.min.y as u16];
|
||||
let size = [rect.width() as u16, rect.height() as u16];
|
||||
glyph_cache
|
||||
.cache_queued(|rect, data| {
|
||||
let offset = [rect.min.x as u16, rect.min.y as u16];
|
||||
let size = [rect.width() as u16, rect.height() as u16];
|
||||
|
||||
let new_data = data.iter().map(|x| [255, 255, 255, *x]).collect::<Vec<[u8; 4]>>();
|
||||
let new_data = data
|
||||
.iter()
|
||||
.map(|x| [255, 255, 255, *x])
|
||||
.collect::<Vec<[u8; 4]>>();
|
||||
|
||||
renderer.update_texture(cache_tex, offset, size, &new_data);
|
||||
}).unwrap();
|
||||
renderer.update_texture(cache_tex, offset, size, &new_data);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let color = srgb_to_linear(color.to_fsa().into());
|
||||
|
||||
for g in positioned_glyphs {
|
||||
if let Ok(Some((uv_rect, screen_rect))) = glyph_cache.rect_for(font_id.index(), g) {
|
||||
if let Ok(Some((uv_rect, screen_rect))) =
|
||||
glyph_cache.rect_for(font_id.index(), g)
|
||||
{
|
||||
let uv = Aabr {
|
||||
min: Vec2::new(uv_rect.min.x, uv_rect.max.y),
|
||||
max: Vec2::new(uv_rect.max.x, uv_rect.min.y),
|
||||
};
|
||||
let rect = Aabr {
|
||||
min: Vec2::new(
|
||||
(screen_rect.min.x as f32 / screen_w - 0.5) * 2.0,
|
||||
(screen_rect.min.x as f32 / screen_w - 0.5) * 2.0,
|
||||
(screen_rect.max.y as f32 / screen_h - 0.5) * -2.0,
|
||||
),
|
||||
max: Vec2::new(
|
||||
(screen_rect.max.x as f32 / screen_w - 0.5) * 2.0,
|
||||
(screen_rect.max.x as f32 / screen_w - 0.5) * 2.0,
|
||||
(screen_rect.min.y as f32 / screen_h - 0.5) * -2.0,
|
||||
),
|
||||
};
|
||||
mesh.push_quad(create_ui_quad(
|
||||
rect,
|
||||
uv,
|
||||
color,
|
||||
UiMode::Text,
|
||||
));
|
||||
mesh.push_quad(create_ui_quad(rect, uv, color, UiMode::Text));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -545,16 +577,13 @@ impl Ui {
|
||||
let p2 = Vec2::new(vx(tri[1][0]), vy(tri[1][1]));
|
||||
let p3 = Vec2::new(vx(tri[2][0]), vy(tri[2][1]));
|
||||
// If triangle is clockwise reverse it
|
||||
let (v1, v2): (Vec3<f32>, Vec3<f32>) = ((p2 - p1).into(), (p3 - p1).into());
|
||||
let triangle = if v1.cross(v2).z > 0.0 {[
|
||||
p1.into_array(),
|
||||
p2.into_array(),
|
||||
p3.into_array(),
|
||||
]} else {[
|
||||
p2.into_array(),
|
||||
p1.into_array(),
|
||||
p3.into_array(),
|
||||
]};
|
||||
let (v1, v2): (Vec3<f32>, Vec3<f32>) =
|
||||
((p2 - p1).into(), (p3 - p1).into());
|
||||
let triangle = if v1.cross(v2).z > 0.0 {
|
||||
[p1.into_array(), p2.into_array(), p3.into_array()]
|
||||
} else {
|
||||
[p2.into_array(), p1.into_array(), p3.into_array()]
|
||||
};
|
||||
mesh.push_tri(create_ui_tri(
|
||||
triangle,
|
||||
[[0.0; 2]; 3],
|
||||
@ -562,21 +591,17 @@ impl Ui {
|
||||
UiMode::Geometry,
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
_ => {}
|
||||
// TODO: Add this
|
||||
//PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);}
|
||||
// Other uneeded for now
|
||||
//PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);}
|
||||
_ => {} // TODO: Add this
|
||||
//PrimitiveKind::TrianglesMultiColor {..} => {println!("primitive kind multicolor with id {:?}", id);}
|
||||
// Other uneeded for now
|
||||
//PrimitiveKind::Other {..} => {println!("primitive kind other with id {:?}", id);}
|
||||
}
|
||||
}
|
||||
// Enter the final command
|
||||
self.draw_commands.push(match current_state {
|
||||
State::Plain =>
|
||||
DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
||||
State::Image =>
|
||||
DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
||||
State::Plain => DrawCommand::plain(renderer.create_model(&mesh).unwrap()),
|
||||
State::Image => DrawCommand::image(renderer.create_model(&mesh).unwrap()),
|
||||
});
|
||||
|
||||
// Handle window resizing
|
||||
@ -584,7 +609,8 @@ impl Ui {
|
||||
self.scale.window_resized(new_dims, renderer);
|
||||
let (w, h) = self.scale.scaled_window_size().into_tuple();
|
||||
self.ui.handle_event(Input::Resize(w, h));
|
||||
self.cache.clear_graphic_cache(renderer, renderer.get_resolution().map(|e| e * 4));
|
||||
self.cache
|
||||
.clear_graphic_cache(renderer, renderer.get_resolution().map(|e| e * 4));
|
||||
// TODO: probably need to resize glyph cache, see conrod's gfx backend for reference
|
||||
}
|
||||
}
|
||||
@ -599,12 +625,8 @@ impl Ui {
|
||||
}
|
||||
DrawCommand::Draw { kind, model } => {
|
||||
let tex = match kind {
|
||||
DrawKind::Image => {
|
||||
self.cache.graphic_cache_tex()
|
||||
}
|
||||
DrawKind::Plain => {
|
||||
self.cache.glyph_cache_tex()
|
||||
}
|
||||
DrawKind::Image => self.cache.graphic_cache_tex(),
|
||||
DrawKind::Plain => self.cache.glyph_cache_tex(),
|
||||
};
|
||||
renderer.render_ui_element(&model, &tex, scissor);
|
||||
}
|
||||
@ -617,6 +639,9 @@ fn default_scissor(renderer: &mut Renderer) -> Aabr<u16> {
|
||||
let (screen_w, screen_h) = renderer.get_resolution().map(|e| e as u16).into_tuple();
|
||||
Aabr {
|
||||
min: Vec2 { x: 0, y: 0 },
|
||||
max: Vec2 { x: screen_w, y: screen_h }
|
||||
max: Vec2 {
|
||||
x: screen_w,
|
||||
y: screen_h,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,7 @@
|
||||
use conrod_core::{
|
||||
widget::{self, button},
|
||||
image,
|
||||
WidgetCommon,
|
||||
Widget,
|
||||
Sizeable,
|
||||
Color,
|
||||
Rect,
|
||||
Positionable,
|
||||
widget_ids,
|
||||
widget::{self, button},
|
||||
widget_ids, Color, Positionable, Rect, Sizeable, Widget, WidgetCommon,
|
||||
};
|
||||
|
||||
#[derive(Clone, WidgetCommon)]
|
||||
@ -88,7 +82,9 @@ impl Widget for ToggleButton {
|
||||
type Event = bool;
|
||||
|
||||
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
|
||||
State { ids: Ids::new(id_gen) }
|
||||
State {
|
||||
ids: Ids::new(id_gen),
|
||||
}
|
||||
}
|
||||
|
||||
fn style(&self) -> Self::Style {
|
||||
@ -96,8 +92,19 @@ impl Widget for ToggleButton {
|
||||
}
|
||||
|
||||
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
||||
let widget::UpdateArgs{ id, state, ui, rect, .. } = args;
|
||||
let ToggleButton { mut value, f_image, t_image, .. } = self;
|
||||
let widget::UpdateArgs {
|
||||
id,
|
||||
state,
|
||||
ui,
|
||||
rect,
|
||||
..
|
||||
} = args;
|
||||
let ToggleButton {
|
||||
mut value,
|
||||
f_image,
|
||||
t_image,
|
||||
..
|
||||
} = self;
|
||||
// Check if button was clicked
|
||||
// (can't use .set().was_clicked() because we are changing the image and this is after setting the widget which causes flickering as it takes a frame to change after the mouse button is lifted)
|
||||
if ui.widget_input(state.ids.button).clicks().left().count() % 2 == 1 {
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::{
|
||||
render::{Renderer, TgtColorFmt, TgtDepthFmt},
|
||||
ui, Error, settings::Settings,
|
||||
settings::Settings,
|
||||
ui, Error,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use vek::*;
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
3
world/.gitignore
vendored
3
world/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
Cargo.lock
|
@ -1,15 +1,11 @@
|
||||
// Library
|
||||
use vek::*;
|
||||
use noise::{NoiseFn, Perlin};
|
||||
use vek::*;
|
||||
|
||||
// Project
|
||||
use common::{
|
||||
vol::{Vox, SizedVol, WriteVol},
|
||||
terrain::{
|
||||
Block,
|
||||
TerrainChunk,
|
||||
TerrainChunkMeta,
|
||||
},
|
||||
terrain::{Block, TerrainChunk, TerrainChunkMeta},
|
||||
vol::{SizedVol, Vox, WriteVol},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -30,7 +26,7 @@ impl World {
|
||||
let mut chunk = TerrainChunk::filled(Block::empty(), TerrainChunkMeta::void());
|
||||
|
||||
let air = Block::empty();
|
||||
let stone = Block::new(1, Rgb::new(200, 220, 255));
|
||||
let stone = Block::new(1, Rgb::new(200, 220, 255));
|
||||
let grass = Block::new(2, Rgb::new(75, 150, 0));
|
||||
//let grass = Block::new(2, Rgb::new(50, 255, 0));
|
||||
let dirt = Block::new(3, Rgb::new(128, 90, 0));
|
||||
@ -47,20 +43,24 @@ impl World {
|
||||
let small_freq = 1.0 / 32.0;
|
||||
let small_ampl = 6.0;
|
||||
let offs = 32.0;
|
||||
let height =
|
||||
perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl
|
||||
let height = perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl
|
||||
+ perlin_nz.get(Vec2::from(wposf * small_freq).into_array()) * small_ampl
|
||||
+ offs;
|
||||
|
||||
chunk.set(lpos, if wposf.z < height - 4.0 {
|
||||
stone
|
||||
} else if wposf.z < height - 1.0 {
|
||||
dirt
|
||||
} else if wposf.z < height {
|
||||
grass
|
||||
} else {
|
||||
air
|
||||
}).unwrap();
|
||||
chunk
|
||||
.set(
|
||||
lpos,
|
||||
if wposf.z < height - 4.0 {
|
||||
stone
|
||||
} else if wposf.z < height - 1.0 {
|
||||
dirt
|
||||
} else if wposf.z < height {
|
||||
grass
|
||||
} else {
|
||||
air
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
chunk
|
||||
|
Loading…
Reference in New Issue
Block a user