Merge branch 'clean-all-code' into 'master'

Ran fmt on codebase

See merge request veloren/veloren!95

Former-commit-id: 9a847a63c0b69dd3a969c3829986032972f00325
This commit is contained in:
Forest Anderson 2019-04-29 20:37:19 +00:00
commit a0a628ee97
68 changed files with 1122 additions and 1117 deletions

View File

@ -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 {

View File

@ -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);
}

View File

@ -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(())
}
};
}
}

View File

@ -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()
};
}
}

View File

@ -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];

View File

@ -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;

View File

@ -1,4 +1,4 @@
use specs::{Component, VecStorage, FlaggedStorage, NullStorage};
use specs::{Component, FlaggedStorage, NullStorage, VecStorage};
use vek::*;
// Pos

View File

@ -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 }
}
}

View File

@ -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(),
(),
);

View File

@ -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

View File

@ -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,

View File

@ -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! {

View File

@ -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 {

View File

@ -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 {

View File

@ -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;

View File

@ -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);

View File

@ -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);
}

View File

@ -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()

View File

@ -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();
}
},
}
}
}
}

View File

@ -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,
},
);
}
}
}

View File

@ -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;

View File

@ -1,4 +1,4 @@
use serde_derive::{Serialize, Deserialize};
use serde_derive::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum BiomeKind {

View File

@ -1,5 +1,5 @@
use serde_derive::{Deserialize, Serialize};
use vek::*;
use serde_derive::{Serialize, Deserialize};
// Crate
use crate::vol::Vox;

View File

@ -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

View File

@ -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.
///

View File

@ -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> {

View File

@ -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> {

View File

@ -1,3 +1,3 @@
pub mod dyna;
pub mod chunk;
pub mod dyna;
pub mod vol_map;

View File

@ -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)

View File

@ -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 {

View File

@ -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)),

View File

@ -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>) {

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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;
}

View File

@ -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)

View File

@ -176,7 +176,6 @@ pub(self) struct Imgs {
inv_slot: ImgId,
// Buttons
mmap_closed: ImgId,
mmap_closed_hover: ImgId,
mmap_closed_press: ImgId,
@ -221,7 +220,7 @@ pub(self) struct Imgs {
button_dark_press: ImgId,
// MiniMap
mmap_frame: ImgId,
mmap_frame: ImgId,
mmap_frame_closed: ImgId,
// SkillBar Module
@ -341,7 +340,7 @@ impl Imgs {
mmap_open: load_vox("element/buttons/button_mmap_open.vox", ui),
mmap_open_hover: load_vox("element/buttons/button_mmap_open_hover.vox", ui),
mmap_open_press: load_vox("element/buttons/button_mmap_open_press.vox", ui),
settings: load_vox("element/buttons/settings.vox", ui),
settings_hover: load_vox("element/buttons/settings_hover.vox", ui),
settings_press: load_vox("element/buttons/settings_press.vox", ui),
@ -384,7 +383,7 @@ impl Imgs {
button_dark_press: load_img("element/buttons/button_dark_press.png", ui),
// MiniMap
mmap_frame: load_vox("element/frames/mmap.vox", ui),
mmap_frame: load_vox("element/frames/mmap.vox", ui),
mmap_frame_closed: load_vox("element/frames/mmap_closed.vox", ui),
// Skillbar Module
@ -659,35 +658,46 @@ impl Hud {
};
}
// Minimap
// Minimap
if self.mmap_open {
if self.mmap_open {
Image::new(self.imgs.mmap_frame)
.w_h(100.0 * 2.0, 100.0 * 2.0)
.top_right_with_margins_on(ui_widgets.window, 5.0, 5.0)
.set(self.ids.mmap_frame, ui_widgets);
.w_h(100.0 * 2.0, 100.0 * 2.0)
.top_right_with_margins_on(ui_widgets.window, 5.0, 5.0)
.set(self.ids.mmap_frame, ui_widgets);
Rectangle::fill_with([92.0 * 2.0, 82.0 * 2.0], color::TRANSPARENT)
.mid_top_with_margin_on(self.ids.mmap_frame, 13.0 * 2.0 + 2.0)
.set(self.ids.mmap_frame_bg, ui_widgets);
}
else {
Image::new(self.imgs.mmap_frame_closed)
Rectangle::fill_with([92.0 * 2.0, 82.0 * 2.0], color::TRANSPARENT)
.mid_top_with_margin_on(self.ids.mmap_frame, 13.0 * 2.0 + 2.0)
.set(self.ids.mmap_frame_bg, ui_widgets);
} else {
Image::new(self.imgs.mmap_frame_closed)
.w_h(100.0 * 2.0, 11.0 * 2.0)
.top_right_with_margins_on(ui_widgets.window, 5.0, 5.0)
.set(self.ids.mmap_frame, ui_widgets);
};
if Button::image(if self.mmap_open {self.imgs.mmap_open} else {self.imgs.mmap_closed})
.w_h(100.0 * 0.2, 100.0 * 0.2)
.hover_image(if self.mmap_open {self.imgs.mmap_open_hover} else {self.imgs.mmap_closed_hover})
.press_image(if self.mmap_open {self.imgs.mmap_open_press} else {self.imgs.mmap_closed_press})
.top_right_with_margins_on(self.ids.mmap_frame, 0.0, 0.0)
.set(self.ids.mmap_button, ui_widgets)
.was_clicked()
{
self.mmap_open = !self.mmap_open;
};
.set(self.ids.mmap_frame, ui_widgets);
};
if Button::image(if self.mmap_open {
self.imgs.mmap_open
} else {
self.imgs.mmap_closed
})
.w_h(100.0 * 0.2, 100.0 * 0.2)
.hover_image(if self.mmap_open {
self.imgs.mmap_open_hover
} else {
self.imgs.mmap_closed_hover
})
.press_image(if self.mmap_open {
self.imgs.mmap_open_press
} else {
self.imgs.mmap_closed_press
})
.top_right_with_margins_on(self.ids.mmap_frame, 0.0, 0.0)
.set(self.ids.mmap_button, ui_widgets)
.was_clicked()
{
self.mmap_open = !self.mmap_open;
};
// Title
// Make it display the actual location
@ -1049,23 +1059,23 @@ impl Hud {
// 0 Settings
if let Windows::Settings = self.open_windows {
// Frame Alignment
// Frame Alignment
Rectangle::fill_with([824.0, 488.0], color::TRANSPARENT)
.middle_of(ui_widgets.window)
.middle_of(ui_widgets.window)
.set(self.ids.settings_bg, ui_widgets);
// Frame
Image::new(self.imgs.settings_frame_l)
.top_left_with_margins_on(self.ids.settings_bg, 0.0, 0.0)
.w_h(412.0, 488.0)
.set(self.ids.settings_l, ui_widgets);
Image::new(self.imgs.settings_frame_r)
Image::new(self.imgs.settings_frame_r)
.right_from(self.ids.settings_l, 0.0)
.parent(self.ids.settings_bg)
.w_h(412.0, 488.0)
.set(self.ids.settings_r, ui_widgets);
// Content Alignment
Rectangle::fill_with([198.0*4.0, 97.0*4.0], color::TRANSPARENT)
.top_right_with_margins_on(self.ids.settings_r, 21.0*4.0, 4.0*4.0)
Rectangle::fill_with([198.0 * 4.0, 97.0 * 4.0], color::TRANSPARENT)
.top_right_with_margins_on(self.ids.settings_r, 21.0 * 4.0, 4.0 * 4.0)
.scroll_kids()
.scroll_kids_vertically()
.set(self.ids.settings_content, ui_widgets);
@ -1090,10 +1100,10 @@ impl Hud {
.set(self.ids.settings_title, ui_widgets);
// Icon
//Image::new(self.imgs.settings_icon)
//.w_h(224.0 / 3.0, 224.0 / 3.0)
//.top_left_with_margins_on(self.ids.settings_bg, -10.0, -10.0)
//.set(self.ids.settings_icon, ui_widgets);
// TODO: Find out if we can remove this
//.w_h(224.0 / 3.0, 224.0 / 3.0)
//.top_left_with_margins_on(self.ids.settings_bg, -10.0, -10.0)
//.set(self.ids.settings_icon, ui_widgets);
// TODO: Find out if we can remove this
// 1 Interface////////////////////////////
if Button::image(if let SettingsTab::Interface = self.settings_tab {
@ -1101,7 +1111,7 @@ impl Hud {
} else {
self.imgs.settings_button
})
.w_h(31.0*4.0, 12.0*4.0)
.w_h(31.0 * 4.0, 12.0 * 4.0)
.hover_image(if let SettingsTab::Interface = self.settings_tab {
self.imgs.settings_button_pressed
} else {
@ -1112,7 +1122,7 @@ impl Hud {
} else {
self.imgs.settings_button_press
})
.top_left_with_margins_on(self.ids.settings_l, 8.0*4.0, 2.0*4.0)
.top_left_with_margins_on(self.ids.settings_l, 8.0 * 4.0, 2.0 * 4.0)
.label("Interface")
.label_font_size(14)
.label_color(TEXT_COLOR)
@ -1175,12 +1185,12 @@ impl Hud {
}
// 2 Gameplay////////////////
if Button::image(if let SettingsTab::Gameplay = self.settings_tab {
if Button::image(if let SettingsTab::Gameplay = self.settings_tab {
self.imgs.settings_button_pressed
} else {
self.imgs.settings_button
})
.w_h(31.0*4.0, 12.0*4.0)
.w_h(31.0 * 4.0, 12.0 * 4.0)
.hover_image(if let SettingsTab::Gameplay = self.settings_tab {
self.imgs.settings_button_pressed
} else {
@ -1207,7 +1217,7 @@ impl Hud {
} else {
self.imgs.settings_button
})
.w_h(31.0*4.0, 12.0*4.0)
.w_h(31.0 * 4.0, 12.0 * 4.0)
.hover_image(if let SettingsTab::Controls = self.settings_tab {
self.imgs.settings_button_pressed
} else {
@ -1229,12 +1239,12 @@ impl Hud {
}
// 4 Video////////////////////////////////
if Button::image(if let SettingsTab::Video = self.settings_tab {
if Button::image(if let SettingsTab::Video = self.settings_tab {
self.imgs.settings_button_pressed
} else {
self.imgs.settings_button
})
.w_h(31.0*4.0, 12.0*4.0)
.w_h(31.0 * 4.0, 12.0 * 4.0)
.hover_image(if let SettingsTab::Video = self.settings_tab {
self.imgs.settings_button_pressed
} else {
@ -1244,7 +1254,7 @@ impl Hud {
self.imgs.settings_button_pressed
} else {
self.imgs.settings_button_press
})
})
.right_from(self.ids.controls, 0.0)
.label("Video")
.parent(self.ids.settings_r)
@ -1262,7 +1272,7 @@ impl Hud {
} else {
self.imgs.settings_button
})
.w_h(31.0*4.0, 12.0*4.0)
.w_h(31.0 * 4.0, 12.0 * 4.0)
.hover_image(if let SettingsTab::Sound = self.settings_tab {
self.imgs.settings_button_pressed
} else {
@ -1566,7 +1576,7 @@ impl Hud {
// 2 Map
if self.map_open {
// BG
// BG
Rectangle::fill_with([824.0, 976.0], color::TRANSPARENT)
.mid_top_with_margin_on(ui_widgets.window, 15.0)
.scroll_kids()
@ -1588,8 +1598,7 @@ impl Hud {
Image::new(self.imgs.map_frame_bl)
.down_from(self.ids.map_frame_l, 0.0)
.w_h(412.0, 488.0)
.set(self.ids.map_frame_bl, ui_widgets);
.set(self.ids.map_frame_bl, ui_widgets);
// Icon
Image::new(self.imgs.map_icon)
@ -1610,10 +1619,10 @@ impl Hud {
}
// Title
//Text::new("Map")
//.mid_top_with_margin_on(self.ids.map_bg, -7.0)
//.font_size(14)
//.color(TEXT_COLOR)
//.set(self.ids.map_title, ui_widgets);
//.mid_top_with_margin_on(self.ids.map_bg, -7.0)
//.font_size(14)
//.color(TEXT_COLOR)
//.set(self.ids.map_title, ui_widgets);
}
// ESC-MENU

View File

@ -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, str::FromStr};
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,7 +78,7 @@ fn main() {
let settings = Settings::default();
settings.save_to_file();
settings
},
}
};
let window = Window::new(&settings).expect("Failed to create window");
@ -93,8 +89,13 @@ fn main() {
.unwrap_or(log::LevelFilter::Warn);
CombinedLogger::init(vec![
TermLogger::new(term_log_level, Config::default()).unwrap(),
WriteLogger::new(log::LevelFilter::Info, Config::default(), File::create(&settings.log.file).unwrap()),
]).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();
@ -127,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?
// ---------------------
@ -148,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 => {
@ -160,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();
});
},
}
}
}
}

View File

@ -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,35 @@ 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())));
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(),
)));
}
}
}
// 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();

View File

@ -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)

View File

@ -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;

View File

@ -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,
}
}

View File

@ -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,
}
}

View File

@ -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)

View File

@ -1,6 +1,6 @@
mod vol;
pub mod segment;
pub mod terrain;
mod vol;
// Crate
use crate::render::{self, Mesh};

View File

@ -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))
}
}

View File

@ -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 }
}
}

View File

@ -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>;
}

View File

@ -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 {

View File

@ -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! {

View File

@ -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::*;

View File

@ -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! {

View File

@ -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! {

View File

@ -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]]),

View File

@ -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)
}
})
})?,
})
}

View File

@ -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> {

View File

@ -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
}
}

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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);
}
}
}

View File

@ -1,22 +1,15 @@
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,
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;
@ -27,7 +20,6 @@ pub struct SessionState {
hud: Hud,
}
/// Represents an active game session (i.e: one that is being played)
impl SessionState {
/// Create a new `SessionState`
@ -43,7 +35,6 @@ impl SessionState {
}
}
// The background colour
const BG_COLOR: Rgba<f32> = Rgba {
r: 0.0,
@ -64,7 +55,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);
@ -123,7 +118,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;
@ -131,7 +125,7 @@ impl PlayState for SessionState {
let _handled = match event {
Event::Close => {
return PlayStateResult::Shutdown;
},
}
// Toggle cursor grabbing
Event::KeyDown(Key::ToggleCursor) => {
global_state
@ -161,18 +155,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;
},
}
}
}

View File

@ -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 {

View File

@ -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<_>, _>(

View File

@ -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,
},
}
}
}

View File

@ -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 {

View File

@ -1,6 +1,7 @@
use crate::{
render::{Renderer, TgtColorFmt, TgtDepthFmt},
ui, Error, settings::Settings,
settings::Settings,
ui, Error,
};
use std::collections::HashMap;
use vek::*;

View File

@ -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