mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added figures, segments, test .vox files, basic animation test
This commit is contained in:
parent
b37a6b67f9
commit
8184bc6fc0
@ -7,3 +7,4 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
specs = "0.14"
|
specs = "0.14"
|
||||||
vek = "0.9"
|
vek = "0.9"
|
||||||
|
dot_vox = "1.0"
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
pub mod phys;
|
pub mod phys;
|
||||||
|
|
||||||
// External
|
// External
|
||||||
use specs::{World as EcsWorld, Builder};
|
use specs::World as EcsWorld;
|
||||||
|
|
||||||
pub fn register_local_components(ecs_world: &mut EcsWorld) {
|
pub fn register_local_components(ecs_world: &mut EcsWorld) {
|
||||||
ecs_world.register::<phys::Pos>();
|
ecs_world.register::<phys::Pos>();
|
||||||
|
33
common/src/figure/cell.rs
Normal file
33
common/src/figure/cell.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Library
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
/// A type representing a single voxel in a figure
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum Cell {
|
||||||
|
Filled([u8; 3]),
|
||||||
|
Empty,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cell {
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Cell::Empty
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(rgb: Rgb<u8>) -> Self {
|
||||||
|
Cell::Filled(rgb.into_array())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Cell::Filled(_) => false,
|
||||||
|
Cell::Empty => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_color(&self) -> Option<Rgb<u8>> {
|
||||||
|
match self {
|
||||||
|
Cell::Filled(col) => Some(Rgb::from(*col)),
|
||||||
|
Cell::Empty => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
63
common/src/figure/mod.rs
Normal file
63
common/src/figure/mod.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
pub mod cell;
|
||||||
|
|
||||||
|
// Library
|
||||||
|
use vek::*;
|
||||||
|
use dot_vox::DotVoxData;
|
||||||
|
|
||||||
|
// Crate
|
||||||
|
use crate::{
|
||||||
|
vol::WriteVol,
|
||||||
|
volumes::dyna::Dyna,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Local
|
||||||
|
use self::cell::Cell;
|
||||||
|
|
||||||
|
/// A type representing a single figure bone (e.g: the limb of a character).
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Bone {
|
||||||
|
origin: Vec3<f32>,
|
||||||
|
offset: Vec3<f32>,
|
||||||
|
ori: Vec3<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A type representing a volume that may be part of an animated figure.
|
||||||
|
///
|
||||||
|
/// Figures are used to represent things like characters, NPCs, mobs, etc.
|
||||||
|
pub type Segment = Dyna<Cell, ()>;
|
||||||
|
|
||||||
|
impl From<DotVoxData> for Segment {
|
||||||
|
fn from(dot_vox_data: DotVoxData) -> Self {
|
||||||
|
if let Some(model) = dot_vox_data.models.get(0) {
|
||||||
|
let palette = dot_vox_data
|
||||||
|
.palette
|
||||||
|
.iter()
|
||||||
|
.map(|col| Rgba::from(col.to_ne_bytes()).into())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let mut segment = Segment::filled(
|
||||||
|
Vec3::new(
|
||||||
|
model.size.x,
|
||||||
|
model.size.y,
|
||||||
|
model.size.z,
|
||||||
|
),
|
||||||
|
Cell::empty(),
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
|
||||||
|
for voxel in &model.voxels {
|
||||||
|
if let Some(&color) = palette.get(voxel.i as usize) {
|
||||||
|
// TODO: Maybe don't ignore this error?
|
||||||
|
let _ = segment.set(
|
||||||
|
Vec3::new(voxel.x, voxel.y, voxel.z).map(|e| e as i32),
|
||||||
|
Cell::new(color),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
segment
|
||||||
|
} else {
|
||||||
|
Segment::filled(Vec3::zero(), Cell::empty(), ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
pub mod clock;
|
pub mod clock;
|
||||||
pub mod comp;
|
pub mod comp;
|
||||||
|
pub mod figure;
|
||||||
pub mod state;
|
pub mod state;
|
||||||
pub mod terrain;
|
pub mod terrain;
|
||||||
pub mod volumes;
|
pub mod volumes;
|
||||||
|
@ -8,7 +8,6 @@ use specs::World as EcsWorld;
|
|||||||
use crate::{
|
use crate::{
|
||||||
comp,
|
comp,
|
||||||
terrain::TerrainMap,
|
terrain::TerrainMap,
|
||||||
vol::VolSize,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// How much faster should an in-game day be compared to a real day?
|
/// How much faster should an in-game day be compared to a real day?
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
kind: u8,
|
kind: u8,
|
||||||
color: [u8; 3],
|
color: [u8; 3],
|
||||||
|
@ -1,27 +1,76 @@
|
|||||||
// Library
|
// Library
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
|
/// A volume that contains voxel data.
|
||||||
pub trait BaseVol {
|
pub trait BaseVol {
|
||||||
type Vox;
|
type Vox;
|
||||||
type Err;
|
type Err;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SizedVol: BaseVol {
|
// Utility types
|
||||||
const SIZE: Vec3<u32>;
|
|
||||||
|
pub struct VoxPosIter {
|
||||||
|
pos: Vec3<u32>,
|
||||||
|
sz: Vec3<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Iterator for VoxPosIter {
|
||||||
|
type Item = Vec3<i32>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let mut old_pos = self.pos;
|
||||||
|
|
||||||
|
if old_pos.z == self.sz.z {
|
||||||
|
old_pos.z = 0;
|
||||||
|
old_pos.y += 1;
|
||||||
|
if old_pos.y == self.sz.y {
|
||||||
|
old_pos.y = 0;
|
||||||
|
old_pos.x += 1;
|
||||||
|
if old_pos.x == self.sz.x {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.pos = old_pos + Vec3::unit_z();
|
||||||
|
|
||||||
|
Some(old_pos.map(|e| e as i32))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A volume that has a finite size.
|
||||||
|
pub trait SizedVol: BaseVol {
|
||||||
|
/// Get the size of the volume.
|
||||||
|
#[inline(always)]
|
||||||
|
fn get_size(&self) -> Vec3<u32>;
|
||||||
|
|
||||||
|
/// Iterate through all potential voxel positions in this volume
|
||||||
|
fn iter_positions(&self) -> VoxPosIter {
|
||||||
|
VoxPosIter {
|
||||||
|
pos: Vec3::zero(),
|
||||||
|
sz: self.get_size(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A volume that provided read access to its voxel data.
|
||||||
pub trait ReadVol: BaseVol {
|
pub trait ReadVol: BaseVol {
|
||||||
|
/// Get a reference to the voxel at the provided position in the volume.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Err>;
|
fn get(&self, pos: Vec3<i32>) -> Result<&Self::Vox, Self::Err>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A volume that provides write access to its voxel data.
|
||||||
pub trait WriteVol: BaseVol {
|
pub trait WriteVol: BaseVol {
|
||||||
|
/// Set the voxel at the provided position in the volume to the provided value.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Err>;
|
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), Self::Err>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Utility traits
|
// Utility traits
|
||||||
|
|
||||||
|
/// Used to specify a volume's compile-time size. This exists as a substitute until const generics
|
||||||
|
/// are implemented.
|
||||||
pub trait VolSize {
|
pub trait VolSize {
|
||||||
const SIZE: Vec3<u32>;
|
const SIZE: Vec3<u32>;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ pub enum ChunkErr {
|
|||||||
OutOfBounds,
|
OutOfBounds,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A volume with dimensions known at compile-time.
|
||||||
// V = Voxel
|
// V = Voxel
|
||||||
// S = Size (replace when const generics are a thing)
|
// S = Size (replace when const generics are a thing)
|
||||||
// M = Metadata
|
// M = Metadata
|
||||||
@ -27,6 +28,8 @@ pub struct Chunk<V, S: VolSize, M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<V, S: VolSize, M> Chunk<V, S, M> {
|
impl<V, S: VolSize, M> Chunk<V, S, M> {
|
||||||
|
/// Used to transform a voxel position in the volume into its corresponding index in the voxel
|
||||||
|
// array.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn idx_for(pos: Vec3<i32>) -> Option<usize> {
|
fn idx_for(pos: Vec3<i32>) -> Option<usize> {
|
||||||
if
|
if
|
||||||
@ -50,7 +53,8 @@ impl<V, S: VolSize, M> BaseVol for Chunk<V, S, M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<V, S: VolSize, M> SizedVol for Chunk<V, S, M> {
|
impl<V, S: VolSize, M> SizedVol for Chunk<V, S, M> {
|
||||||
const SIZE: Vec3<u32> = Vec3 { x: 32, y: 32, z: 32 };
|
#[inline(always)]
|
||||||
|
fn get_size(&self) -> Vec3<u32> { S::SIZE }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V, S: VolSize, M> ReadVol for Chunk<V, S, M> {
|
impl<V, S: VolSize, M> ReadVol for Chunk<V, S, M> {
|
||||||
@ -73,6 +77,8 @@ impl<V, S: VolSize, M> WriteVol for Chunk<V, S, M> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<V: Clone, S: VolSize, M> Chunk<V, S, M> {
|
impl<V: Clone, S: VolSize, M> Chunk<V, S, M> {
|
||||||
|
/// Create a new `Chunk` with the provided dimensions and all voxels filled with duplicates of
|
||||||
|
/// the provided voxel.
|
||||||
pub fn filled(vox: V, meta: M) -> Self {
|
pub fn filled(vox: V, meta: M) -> Self {
|
||||||
Self {
|
Self {
|
||||||
vox: vec![vox; S::SIZE.product() as usize],
|
vox: vec![vox; S::SIZE.product() as usize],
|
||||||
@ -81,10 +87,12 @@ impl<V: Clone, S: VolSize, M> Chunk<V, S, M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the internal metadata.
|
||||||
pub fn metadata(&self) -> &M {
|
pub fn metadata(&self) -> &M {
|
||||||
&self.meta
|
&self.meta
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a mutable reference to the internal metadata.
|
||||||
pub fn metadata_mut(&mut self) -> &mut M {
|
pub fn metadata_mut(&mut self) -> &mut M {
|
||||||
&mut self.meta
|
&mut self.meta
|
||||||
}
|
}
|
||||||
|
95
common/src/volumes/dyna.rs
Normal file
95
common/src/volumes/dyna.rs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Library
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
// Local
|
||||||
|
use crate::vol::{
|
||||||
|
BaseVol,
|
||||||
|
SizedVol,
|
||||||
|
ReadVol,
|
||||||
|
WriteVol,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub enum DynaErr {
|
||||||
|
OutOfBounds,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A volume with dimensions known only at the creation of the object.
|
||||||
|
// V = Voxel
|
||||||
|
// S = Size (replace when const generics are a thing)
|
||||||
|
// M = Metadata
|
||||||
|
pub struct Dyna<V, M> {
|
||||||
|
vox: Vec<V>,
|
||||||
|
meta: M,
|
||||||
|
sz: Vec3<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V, M> Dyna<V, M> {
|
||||||
|
/// Used to transform a voxel position in the volume into its corresponding index in the voxel
|
||||||
|
// 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)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V, M> BaseVol for Dyna<V, M> {
|
||||||
|
type Vox = V;
|
||||||
|
type Err = DynaErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V, M> SizedVol for Dyna<V, M> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn get_size(&self) -> Vec3<u32> { self.sz }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V, M> ReadVol for Dyna<V, M> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn get(&self, pos: Vec3<i32>) -> Result<&V, DynaErr> {
|
||||||
|
Self::idx_for(self.sz, pos)
|
||||||
|
.and_then(|idx| self.vox.get(idx))
|
||||||
|
.ok_or(DynaErr::OutOfBounds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V, M> WriteVol for Dyna<V, M> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn set(&mut self, pos: Vec3<i32>, vox: Self::Vox) -> Result<(), DynaErr> {
|
||||||
|
Self::idx_for(self.sz, pos)
|
||||||
|
.and_then(|idx| self.vox.get_mut(idx))
|
||||||
|
.map(|old_vox| *old_vox = vox)
|
||||||
|
.ok_or(DynaErr::OutOfBounds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V: Clone, M> Dyna<V, M> {
|
||||||
|
/// Create a new `Dyna` with the provided dimensions and all voxels filled with duplicates of
|
||||||
|
/// the provided voxel.
|
||||||
|
pub fn filled(sz: Vec3<u32>, vox: V, meta: M) -> Self {
|
||||||
|
Self {
|
||||||
|
vox: vec![vox; sz.product() as usize],
|
||||||
|
meta,
|
||||||
|
sz,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a reference to the internal metadata.
|
||||||
|
pub fn metadata(&self) -> &M {
|
||||||
|
&self.meta
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a mutable reference to the internal metadata.
|
||||||
|
pub fn metadata_mut(&mut self) -> &mut M {
|
||||||
|
&mut self.meta
|
||||||
|
}
|
||||||
|
}
|
@ -1,2 +1,3 @@
|
|||||||
|
pub mod dyna;
|
||||||
pub mod chunk;
|
pub mod chunk;
|
||||||
pub mod vol_map;
|
pub mod vol_map;
|
||||||
|
@ -7,7 +7,7 @@ edition = "2018"
|
|||||||
[features]
|
[features]
|
||||||
gl = ["gfx_device_gl"]
|
gl = ["gfx_device_gl"]
|
||||||
|
|
||||||
default = []
|
default = ["gl"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
common = { package = "veloren-common", path = "../common" }
|
common = { package = "veloren-common", path = "../common" }
|
||||||
@ -28,3 +28,4 @@ failure = "0.1"
|
|||||||
lazy_static = "1.1"
|
lazy_static = "1.1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pretty_env_logger = "0.3"
|
pretty_env_logger = "0.3"
|
||||||
|
dot_vox = "1.0"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#version 330 core
|
#version 330 core
|
||||||
|
|
||||||
in vec3 f_pos;
|
in vec3 f_pos;
|
||||||
|
in vec3 f_col;
|
||||||
|
|
||||||
layout (std140)
|
layout (std140)
|
||||||
uniform u_locals {
|
uniform u_locals {
|
||||||
@ -21,5 +22,5 @@ uniform u_globals {
|
|||||||
out vec4 tgt_color;
|
out vec4 tgt_color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
tgt_color = vec4(f_pos, 1.0);
|
tgt_color = vec4(f_col, 1.0);
|
||||||
}
|
}
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
in vec3 v_pos;
|
in vec3 v_pos;
|
||||||
in vec3 v_col;
|
in vec3 v_col;
|
||||||
in uint v_bone;
|
in uint v_bone_idx;
|
||||||
|
|
||||||
layout (std140)
|
layout (std140)
|
||||||
uniform u_locals {
|
uniform u_locals {
|
||||||
@ -20,13 +20,26 @@ uniform u_globals {
|
|||||||
vec4 time;
|
vec4 time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BoneData {
|
||||||
|
mat4 bone_mat;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout (std140)
|
||||||
|
uniform u_bones {
|
||||||
|
BoneData bones[16];
|
||||||
|
};
|
||||||
|
|
||||||
out vec3 f_pos;
|
out vec3 f_pos;
|
||||||
|
out vec3 f_col;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
f_pos = v_pos;
|
f_pos = v_pos;
|
||||||
|
f_col = v_col;
|
||||||
|
|
||||||
gl_Position =
|
gl_Position =
|
||||||
proj_mat *
|
proj_mat *
|
||||||
view_mat *
|
view_mat *
|
||||||
vec4(0.5 * v_pos + cam_pos.xyz, 1);
|
model_mat *
|
||||||
|
bones[v_bone_idx].bone_mat *
|
||||||
|
vec4(v_pos, 1);
|
||||||
}
|
}
|
63
voxygen/src/anim/mod.rs
Normal file
63
voxygen/src/anim/mod.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// Library
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
// Crate
|
||||||
|
use crate::render::FigureBoneData;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Bone {
|
||||||
|
parent: Option<u8>, // MUST be less than the current bone index
|
||||||
|
pub offset: Vec3<f32>,
|
||||||
|
pub ori: Quaternion<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bone {
|
||||||
|
pub fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
parent: None,
|
||||||
|
offset: Vec3::zero(),
|
||||||
|
ori: Quaternion::identity(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compute_base_matrix(&self) -> Mat4<f32> {
|
||||||
|
Mat4::<f32>::translation_3d(self.offset) * Mat4::from(self.ori)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct Skeleton {
|
||||||
|
bones: [Bone; 16],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Skeleton {
|
||||||
|
pub fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
bones: [Bone::default(); 16],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_bone(mut self, bone_idx: u8, bone: Bone) -> Self {
|
||||||
|
self.bones[bone_idx as usize] = bone;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bone(&self, bone_idx: u8) -> &Bone { &self.bones[bone_idx as usize] }
|
||||||
|
pub fn bone_mut(&mut self, bone_idx: u8) -> &mut Bone { &mut self.bones[bone_idx as usize] }
|
||||||
|
|
||||||
|
pub fn compute_matrices(&self) -> [FigureBoneData; 16] {
|
||||||
|
let mut bone_data = [FigureBoneData::default(); 16];
|
||||||
|
for i in 0..16 {
|
||||||
|
bone_data[i] = FigureBoneData::new(
|
||||||
|
self.bones[i].compute_base_matrix()
|
||||||
|
// *
|
||||||
|
//if let Some(parent_idx) = self.bones[i].parent {
|
||||||
|
// bone_data[parent_idx as usize]
|
||||||
|
//} else {
|
||||||
|
// Mat4::identity()
|
||||||
|
//}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
bone_data
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,7 @@
|
|||||||
|
pub mod anim;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod menu;
|
pub mod menu;
|
||||||
|
pub mod mesh;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
pub mod scene;
|
pub mod scene;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
|
20
voxygen/src/mesh/mod.rs
Normal file
20
voxygen/src/mesh/mod.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
pub mod segment;
|
||||||
|
|
||||||
|
// Library
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
// Crate
|
||||||
|
use crate::render::{
|
||||||
|
self,
|
||||||
|
Mesh,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait Meshable {
|
||||||
|
type Pipeline: render::Pipeline;
|
||||||
|
|
||||||
|
fn generate_mesh(&self) -> Mesh<Self::Pipeline> {
|
||||||
|
self.generate_mesh_with_offset(Vec3::zero())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_mesh_with_offset(&self, offs: Vec3<f32>) -> Mesh<Self::Pipeline>;
|
||||||
|
}
|
112
voxygen/src/mesh/segment.rs
Normal file
112
voxygen/src/mesh/segment.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// Project
|
||||||
|
use common::figure::Segment;
|
||||||
|
|
||||||
|
// Library
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
// Project
|
||||||
|
use common::vol::{
|
||||||
|
SizedVol,
|
||||||
|
ReadVol,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Crate
|
||||||
|
use crate::{
|
||||||
|
mesh::Meshable,
|
||||||
|
render::{
|
||||||
|
self,
|
||||||
|
Mesh,
|
||||||
|
Quad,
|
||||||
|
FigurePipeline,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
type FigureVertex = <FigurePipeline as render::Pipeline>::Vertex;
|
||||||
|
|
||||||
|
// Utility function
|
||||||
|
// TODO: Evaluate how useful this is
|
||||||
|
fn create_quad(
|
||||||
|
origin: Vec3<f32>,
|
||||||
|
unit_x: Vec3<f32>,
|
||||||
|
unit_y: Vec3<f32>,
|
||||||
|
col: Rgb<f32>,
|
||||||
|
bone: u8,
|
||||||
|
) -> Quad<FigurePipeline> {
|
||||||
|
Quad::new(
|
||||||
|
FigureVertex::new(origin, col, bone),
|
||||||
|
FigureVertex::new(origin + unit_x, col, bone),
|
||||||
|
FigureVertex::new(origin + unit_x + unit_y, col, bone),
|
||||||
|
FigureVertex::new(origin + unit_y, col, bone),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Meshable for Segment {
|
||||||
|
type Pipeline = FigurePipeline;
|
||||||
|
|
||||||
|
fn generate_mesh_with_offset(&self, offs: Vec3<f32>) -> Mesh<FigurePipeline> {
|
||||||
|
let mut mesh = Mesh::new();
|
||||||
|
|
||||||
|
for pos in self.iter_positions() {
|
||||||
|
if let Some(col) = self
|
||||||
|
.get(pos)
|
||||||
|
.ok()
|
||||||
|
.and_then(|vox| vox.get_color())
|
||||||
|
{
|
||||||
|
let col = col.map(|e| e as f32 / 255.0);
|
||||||
|
|
||||||
|
// TODO: Face occlusion
|
||||||
|
|
||||||
|
// -x
|
||||||
|
mesh.push_quad(create_quad(
|
||||||
|
offs + pos.map(|e| e as f32) + Vec3::unit_y(),
|
||||||
|
-Vec3::unit_y(),
|
||||||
|
Vec3::unit_z(),
|
||||||
|
col,
|
||||||
|
0,
|
||||||
|
));
|
||||||
|
// +x
|
||||||
|
mesh.push_quad(create_quad(
|
||||||
|
offs + pos.map(|e| e as f32) + Vec3::unit_x(),
|
||||||
|
Vec3::unit_y(),
|
||||||
|
Vec3::unit_z(),
|
||||||
|
col,
|
||||||
|
0,
|
||||||
|
));
|
||||||
|
// -y
|
||||||
|
mesh.push_quad(create_quad(
|
||||||
|
offs + pos.map(|e| e as f32),
|
||||||
|
Vec3::unit_x(),
|
||||||
|
Vec3::unit_z(),
|
||||||
|
col,
|
||||||
|
0,
|
||||||
|
));
|
||||||
|
// +y
|
||||||
|
mesh.push_quad(create_quad(
|
||||||
|
offs + pos.map(|e| e as f32) + Vec3::unit_y(),
|
||||||
|
Vec3::unit_z(),
|
||||||
|
Vec3::unit_x(),
|
||||||
|
col,
|
||||||
|
0,
|
||||||
|
));
|
||||||
|
// -z
|
||||||
|
mesh.push_quad(create_quad(
|
||||||
|
offs + pos.map(|e| e as f32),
|
||||||
|
Vec3::unit_y(),
|
||||||
|
Vec3::unit_x(),
|
||||||
|
col,
|
||||||
|
0,
|
||||||
|
));
|
||||||
|
// +z
|
||||||
|
mesh.push_quad(create_quad(
|
||||||
|
offs + pos.map(|e| e as f32) + Vec3::unit_z(),
|
||||||
|
Vec3::unit_x(),
|
||||||
|
Vec3::unit_y(),
|
||||||
|
col,
|
||||||
|
0,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mesh
|
||||||
|
}
|
||||||
|
}
|
@ -19,9 +19,9 @@ pub struct Consts<T: Copy + gfx::traits::Pod> {
|
|||||||
|
|
||||||
impl<T: Copy + gfx::traits::Pod> Consts<T> {
|
impl<T: Copy + gfx::traits::Pod> Consts<T> {
|
||||||
/// Create a new `Const<T>`
|
/// Create a new `Const<T>`
|
||||||
pub fn new(factory: &mut gfx_backend::Factory) -> Self {
|
pub fn new(factory: &mut gfx_backend::Factory, len: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
buf: factory.create_constant_buffer(1),
|
buf: factory.create_constant_buffer(len),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,9 +29,9 @@ impl<T: Copy + gfx::traits::Pod> Consts<T> {
|
|||||||
pub fn update(
|
pub fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
encoder: &mut gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
|
||||||
val: T,
|
vals: &[T],
|
||||||
) -> Result<(), RenderError> {
|
) -> Result<(), RenderError> {
|
||||||
encoder.update_buffer(&self.buf, &[val], 0)
|
encoder.update_buffer(&self.buf, vals, 0)
|
||||||
.map_err(|err| RenderError::UpdateError(err))
|
.map_err(|err| RenderError::UpdateError(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
use super::Pipeline;
|
use super::Pipeline;
|
||||||
|
|
||||||
/// A `Vec`-based mesh structure used to store mesh data on the CPU.
|
/// A `Vec`-based mesh structure used to store mesh data on the CPU.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Mesh<P: Pipeline> {
|
pub struct Mesh<P: Pipeline> {
|
||||||
verts: Vec<P::Vertex>,
|
verts: Vec<P::Vertex>,
|
||||||
}
|
}
|
||||||
@ -43,6 +44,22 @@ impl<P: Pipeline> Mesh<P> {
|
|||||||
self.verts.push(quad.d);
|
self.verts.push(quad.d);
|
||||||
self.verts.push(quad.a);
|
self.verts.push(quad.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Push the vertices of another mesh onto the end of this mesh
|
||||||
|
pub fn push_mesh(&mut self, other: &Mesh<P>) {
|
||||||
|
self.verts.extend_from_slice(other.vertices());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Push the vertices of another mesh onto the end of this mesh
|
||||||
|
pub fn push_mesh_map<F: FnMut(P::Vertex) -> P::Vertex>(&mut self, other: &Mesh<P>, mut f: F) {
|
||||||
|
// Reserve enough space in our Vec. This isn't necessary, but it tends to reduce the number
|
||||||
|
// of required (re)allocations.
|
||||||
|
self.verts.reserve(other.vertices().len());
|
||||||
|
|
||||||
|
for vert in other.vertices() {
|
||||||
|
self.verts.push(f(vert.clone()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a triangle stored on the CPU.
|
/// Represents a triangle stored on the CPU.
|
||||||
|
@ -8,14 +8,15 @@ mod util;
|
|||||||
// Reexports
|
// Reexports
|
||||||
pub use self::{
|
pub use self::{
|
||||||
consts::Consts,
|
consts::Consts,
|
||||||
mesh::{Mesh, Quad},
|
mesh::{Mesh, Tri, Quad},
|
||||||
model::Model,
|
model::Model,
|
||||||
renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
|
renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
|
||||||
pipelines::{
|
pipelines::{
|
||||||
Globals,
|
Globals,
|
||||||
character::{
|
figure::{
|
||||||
CharacterPipeline,
|
FigurePipeline,
|
||||||
Locals as CharacterLocals,
|
Locals as FigureLocals,
|
||||||
|
BoneData as FigureBoneData,
|
||||||
},
|
},
|
||||||
skybox::{
|
skybox::{
|
||||||
create_mesh as create_skybox_mesh,
|
create_mesh as create_skybox_mesh,
|
||||||
@ -47,7 +48,7 @@ pub enum RenderError {
|
|||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// - `SkyboxPipeline`
|
/// - `SkyboxPipeline`
|
||||||
/// - `CharacterPipeline`
|
/// - `FigurePipeline`
|
||||||
pub trait Pipeline {
|
pub trait Pipeline {
|
||||||
type Vertex:
|
type Vertex:
|
||||||
Clone +
|
Clone +
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
// Library
|
|
||||||
use gfx::{
|
|
||||||
self,
|
|
||||||
// Macros
|
|
||||||
gfx_defines,
|
|
||||||
gfx_vertex_struct_meta,
|
|
||||||
gfx_constant_struct_meta,
|
|
||||||
gfx_impl_struct_meta,
|
|
||||||
gfx_pipeline,
|
|
||||||
gfx_pipeline_inner,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Local
|
|
||||||
use super::{
|
|
||||||
Globals,
|
|
||||||
super::{
|
|
||||||
Pipeline,
|
|
||||||
TgtColorFmt,
|
|
||||||
TgtDepthFmt,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
gfx_defines! {
|
|
||||||
vertex Vertex {
|
|
||||||
pos: [f32; 3] = "v_pos",
|
|
||||||
col: [f32; 3] = "v_col",
|
|
||||||
bone: u8 = "v_bone",
|
|
||||||
}
|
|
||||||
|
|
||||||
constant Locals {
|
|
||||||
model_mat: [[f32; 4]; 4] = "model_mat",
|
|
||||||
}
|
|
||||||
|
|
||||||
pipeline pipe {
|
|
||||||
vbuf: gfx::VertexBuffer<Vertex> = (),
|
|
||||||
locals: gfx::ConstantBuffer<Locals> = "u_locals",
|
|
||||||
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
|
||||||
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
|
|
||||||
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CharacterPipeline;
|
|
||||||
|
|
||||||
impl Pipeline for CharacterPipeline {
|
|
||||||
type Vertex = Vertex;
|
|
||||||
}
|
|
93
voxygen/src/render/pipelines/figure.rs
Normal file
93
voxygen/src/render/pipelines/figure.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// Library
|
||||||
|
use gfx::{
|
||||||
|
self,
|
||||||
|
// Macros
|
||||||
|
gfx_defines,
|
||||||
|
gfx_vertex_struct_meta,
|
||||||
|
gfx_constant_struct_meta,
|
||||||
|
gfx_impl_struct_meta,
|
||||||
|
gfx_pipeline,
|
||||||
|
gfx_pipeline_inner,
|
||||||
|
};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
// Local
|
||||||
|
use super::{
|
||||||
|
Globals,
|
||||||
|
super::{
|
||||||
|
Pipeline,
|
||||||
|
TgtColorFmt,
|
||||||
|
TgtDepthFmt,
|
||||||
|
util::arr_to_mat,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
gfx_defines! {
|
||||||
|
vertex Vertex {
|
||||||
|
pos: [f32; 3] = "v_pos",
|
||||||
|
col: [f32; 3] = "v_col",
|
||||||
|
bone_idx: u8 = "v_bone_idx",
|
||||||
|
}
|
||||||
|
|
||||||
|
constant Locals {
|
||||||
|
model_mat: [[f32; 4]; 4] = "model_mat",
|
||||||
|
}
|
||||||
|
|
||||||
|
constant BoneData {
|
||||||
|
bone_mat: [[f32; 4]; 4] = "bone_mat",
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline pipe {
|
||||||
|
vbuf: gfx::VertexBuffer<Vertex> = (),
|
||||||
|
|
||||||
|
locals: gfx::ConstantBuffer<Locals> = "u_locals",
|
||||||
|
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
||||||
|
bones: gfx::ConstantBuffer<BoneData> = "u_bones",
|
||||||
|
|
||||||
|
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
|
||||||
|
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::LESS_EQUAL_WRITE,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vertex {
|
||||||
|
pub fn new(pos: Vec3<f32>, col: Rgb<f32>, bone_idx: u8) -> Self {
|
||||||
|
Self {
|
||||||
|
pos: pos.into_array(),
|
||||||
|
col: col.into_array(),
|
||||||
|
bone_idx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_bone_idx(mut self, bone_idx: u8) -> Self {
|
||||||
|
self.bone_idx = bone_idx;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Locals {
|
||||||
|
pub fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
model_mat: arr_to_mat(Mat4::identity().into_col_array()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoneData {
|
||||||
|
pub fn new(bone_mat: Mat4<f32>) -> Self {
|
||||||
|
Self {
|
||||||
|
bone_mat: arr_to_mat(bone_mat.into_col_array()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
bone_mat: arr_to_mat(Mat4::identity().into_col_array()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct FigurePipeline;
|
||||||
|
|
||||||
|
impl Pipeline for FigurePipeline {
|
||||||
|
type Vertex = Vertex;
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
pub mod character;
|
pub mod figure;
|
||||||
pub mod skybox;
|
pub mod skybox;
|
||||||
|
|
||||||
// Library
|
// Library
|
||||||
|
@ -33,8 +33,10 @@ gfx_defines! {
|
|||||||
|
|
||||||
pipeline pipe {
|
pipeline pipe {
|
||||||
vbuf: gfx::VertexBuffer<Vertex> = (),
|
vbuf: gfx::VertexBuffer<Vertex> = (),
|
||||||
|
|
||||||
locals: gfx::ConstantBuffer<Locals> = "u_locals",
|
locals: gfx::ConstantBuffer<Locals> = "u_locals",
|
||||||
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
||||||
|
|
||||||
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
|
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
|
||||||
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::PASS_TEST,
|
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::PASS_TEST,
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,13 @@ use super::{
|
|||||||
gfx_backend,
|
gfx_backend,
|
||||||
pipelines::{
|
pipelines::{
|
||||||
Globals,
|
Globals,
|
||||||
character,
|
figure,
|
||||||
skybox,
|
skybox,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Represents the format of the window's color target.
|
/// Represents the format of the window's color target.
|
||||||
pub type TgtColorFmt = gfx::format::Srgba8;
|
pub type TgtColorFmt = gfx::format::Rgba8;
|
||||||
/// Represents the format of the window's depth target.
|
/// Represents the format of the window's depth target.
|
||||||
pub type TgtDepthFmt = gfx::format::DepthStencil;
|
pub type TgtDepthFmt = gfx::format::DepthStencil;
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ pub struct Renderer {
|
|||||||
tgt_depth_view: TgtDepthView,
|
tgt_depth_view: TgtDepthView,
|
||||||
|
|
||||||
skybox_pipeline: GfxPipeline<skybox::pipe::Init<'static>>,
|
skybox_pipeline: GfxPipeline<skybox::pipe::Init<'static>>,
|
||||||
character_pipeline: GfxPipeline<character::pipe::Init<'static>>,
|
figure_pipeline: GfxPipeline<figure::pipe::Init<'static>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer {
|
impl Renderer {
|
||||||
@ -62,12 +62,12 @@ impl Renderer {
|
|||||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/skybox.frag")),
|
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/skybox.frag")),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Construct a pipeline for rendering characters
|
// Construct a pipeline for rendering figures
|
||||||
let character_pipeline = create_pipeline(
|
let figure_pipeline = create_pipeline(
|
||||||
&mut factory,
|
&mut factory,
|
||||||
character::pipe::new(),
|
figure::pipe::new(),
|
||||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/character.vert")),
|
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/figure.vert")),
|
||||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/character.frag")),
|
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/figure.frag")),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@ -79,7 +79,7 @@ impl Renderer {
|
|||||||
tgt_depth_view,
|
tgt_depth_view,
|
||||||
|
|
||||||
skybox_pipeline,
|
skybox_pipeline,
|
||||||
character_pipeline,
|
figure_pipeline,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,28 +96,23 @@ impl Renderer {
|
|||||||
self.device.cleanup();
|
self.device.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new set of constants.
|
/// Create a new set of constants with the provided values.
|
||||||
pub fn create_consts<T: Copy + gfx::traits::Pod>(&mut self) -> Result<Consts<T>, RenderError> {
|
pub fn create_consts<T: Copy + gfx::traits::Pod>(
|
||||||
Ok(Consts::new(&mut self.factory))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new set of constants with a value.
|
|
||||||
pub fn create_consts_with<T: Copy + gfx::traits::Pod>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
val: T
|
vals: &[T],
|
||||||
) -> Result<Consts<T>, RenderError> {
|
) -> Result<Consts<T>, RenderError> {
|
||||||
let mut consts = self.create_consts()?;
|
let mut consts = Consts::new(&mut self.factory, vals.len());
|
||||||
consts.update(&mut self.encoder, val)?;
|
consts.update(&mut self.encoder, vals)?;
|
||||||
Ok(consts)
|
Ok(consts)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update a set of constants with a new value.
|
/// Update a set of constants with the provided values.
|
||||||
pub fn update_consts<T: Copy + gfx::traits::Pod>(
|
pub fn update_consts<T: Copy + gfx::traits::Pod>(
|
||||||
&mut self,
|
&mut self,
|
||||||
consts: &mut Consts<T>,
|
consts: &mut Consts<T>,
|
||||||
val: T
|
vals: &[T]
|
||||||
) -> Result<(), RenderError> {
|
) -> Result<(), RenderError> {
|
||||||
consts.update(&mut self.encoder, val)
|
consts.update(&mut self.encoder, vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new model from the provided mesh.
|
/// Create a new model from the provided mesh.
|
||||||
@ -132,8 +127,8 @@ impl Renderer {
|
|||||||
pub fn render_skybox(
|
pub fn render_skybox(
|
||||||
&mut self,
|
&mut self,
|
||||||
model: &Model<skybox::SkyboxPipeline>,
|
model: &Model<skybox::SkyboxPipeline>,
|
||||||
locals: &Consts<skybox::Locals>,
|
|
||||||
globals: &Consts<Globals>,
|
globals: &Consts<Globals>,
|
||||||
|
locals: &Consts<skybox::Locals>,
|
||||||
) {
|
) {
|
||||||
self.encoder.draw(
|
self.encoder.draw(
|
||||||
&model.slice,
|
&model.slice,
|
||||||
@ -147,6 +142,28 @@ impl Renderer {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Queue the rendering of the provided figure model in the upcoming frame.
|
||||||
|
pub fn render_figure(
|
||||||
|
&mut self,
|
||||||
|
model: &Model<figure::FigurePipeline>,
|
||||||
|
globals: &Consts<Globals>,
|
||||||
|
locals: &Consts<figure::Locals>,
|
||||||
|
bones: &Consts<figure::BoneData>,
|
||||||
|
) {
|
||||||
|
self.encoder.draw(
|
||||||
|
&model.slice,
|
||||||
|
&self.figure_pipeline.pso,
|
||||||
|
&figure::pipe::Data {
|
||||||
|
vbuf: model.vbuf.clone(),
|
||||||
|
locals: locals.buf.clone(),
|
||||||
|
globals: globals.buf.clone(),
|
||||||
|
bones: bones.buf.clone(),
|
||||||
|
tgt_color: self.tgt_color_view.clone(),
|
||||||
|
tgt_depth: self.tgt_depth_view.clone(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GfxPipeline<P: gfx::pso::PipelineInit> {
|
struct GfxPipeline<P: gfx::pso::PipelineInit> {
|
||||||
|
@ -19,9 +19,9 @@ impl Camera {
|
|||||||
/// Create a new `Camera` with default parameters.
|
/// Create a new `Camera` with default parameters.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
focus: Vec3::zero(),
|
focus: Vec3::unit_z() * 10.0,
|
||||||
ori: Vec3::zero(),
|
ori: Vec3::zero(),
|
||||||
dist: 5.0,
|
dist: 40.0,
|
||||||
fov: 1.3,
|
fov: 1.3,
|
||||||
aspect: 1.618,
|
aspect: 1.618,
|
||||||
}
|
}
|
||||||
|
79
voxygen/src/scene/figure.rs
Normal file
79
voxygen/src/scene/figure.rs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// Crate
|
||||||
|
use crate::{
|
||||||
|
Error,
|
||||||
|
render::{
|
||||||
|
Consts,
|
||||||
|
Globals,
|
||||||
|
Mesh,
|
||||||
|
Model,
|
||||||
|
Renderer,
|
||||||
|
FigurePipeline,
|
||||||
|
FigureBoneData,
|
||||||
|
FigureLocals,
|
||||||
|
},
|
||||||
|
anim::Skeleton,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct Figure {
|
||||||
|
// GPU data
|
||||||
|
model: Model<FigurePipeline>,
|
||||||
|
bone_consts: Consts<FigureBoneData>,
|
||||||
|
locals: Consts<FigureLocals>,
|
||||||
|
|
||||||
|
// CPU data
|
||||||
|
bone_meshes: [Option<Mesh<FigurePipeline>>; 16],
|
||||||
|
pub skeleton: Skeleton,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Figure {
|
||||||
|
pub fn new(
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
bone_meshes: [Option<Mesh<FigurePipeline>>; 16]
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let skeleton = Skeleton::default();
|
||||||
|
let mut this = Self {
|
||||||
|
model: renderer.create_model(&Mesh::new())?,
|
||||||
|
bone_consts: renderer.create_consts(&skeleton.compute_matrices())?,
|
||||||
|
locals: renderer.create_consts(&[FigureLocals::default()])?,
|
||||||
|
|
||||||
|
bone_meshes,
|
||||||
|
skeleton,
|
||||||
|
};
|
||||||
|
this.update_model(renderer)?;
|
||||||
|
Ok(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_model(&mut self, renderer: &mut Renderer) -> Result<(), Error> {
|
||||||
|
let mut mesh = Mesh::new();
|
||||||
|
|
||||||
|
self.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))
|
||||||
|
});
|
||||||
|
|
||||||
|
self.model = renderer.create_model(&mesh)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_skeleton(&mut self, renderer: &mut Renderer) -> Result<(), Error> {
|
||||||
|
renderer.update_consts(&mut self.bone_consts, &self.skeleton.compute_matrices())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_locals(&mut self, renderer: &mut Renderer, locals: FigureLocals) -> Result<(), Error> {
|
||||||
|
renderer.update_consts(&mut self.locals, &[locals])?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) {
|
||||||
|
renderer.render_figure(
|
||||||
|
&self.model,
|
||||||
|
globals,
|
||||||
|
&self.locals,
|
||||||
|
&self.bone_consts,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,19 @@
|
|||||||
pub mod camera;
|
pub mod camera;
|
||||||
|
pub mod figure;
|
||||||
|
|
||||||
// Standard
|
// Standard
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
// Library
|
// Library
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
use dot_vox;
|
||||||
|
|
||||||
// Project
|
// Project
|
||||||
use client::{
|
use client::{
|
||||||
self,
|
self,
|
||||||
Client,
|
Client,
|
||||||
};
|
};
|
||||||
|
use common::figure::Segment;
|
||||||
|
|
||||||
// Crate
|
// Crate
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -22,47 +25,82 @@ use crate::{
|
|||||||
Renderer,
|
Renderer,
|
||||||
SkyboxPipeline,
|
SkyboxPipeline,
|
||||||
SkyboxLocals,
|
SkyboxLocals,
|
||||||
|
FigureLocals,
|
||||||
create_skybox_mesh,
|
create_skybox_mesh,
|
||||||
},
|
},
|
||||||
window::Event,
|
window::Event,
|
||||||
|
mesh::Meshable,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Local
|
// Local
|
||||||
use self::camera::Camera;
|
use self::{
|
||||||
|
camera::Camera,
|
||||||
|
figure::Figure,
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Don't hard-code this
|
||||||
|
const CURSOR_PAN_SCALE: f32 = 0.005;
|
||||||
|
|
||||||
struct Skybox {
|
struct Skybox {
|
||||||
model: Model<SkyboxPipeline>,
|
model: Model<SkyboxPipeline>,
|
||||||
locals: Consts<SkyboxLocals>,
|
locals: Consts<SkyboxLocals>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Don't hard-code this
|
|
||||||
const CURSOR_PAN_SCALE: f32 = 0.005;
|
|
||||||
|
|
||||||
pub struct Scene {
|
pub struct Scene {
|
||||||
camera: Camera,
|
camera: Camera,
|
||||||
globals: Consts<Globals>,
|
globals: Consts<Globals>,
|
||||||
skybox: Skybox,
|
skybox: Skybox,
|
||||||
|
|
||||||
|
test_figure: Figure,
|
||||||
|
|
||||||
client: Client,
|
client: Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Make a proper asset loading system
|
||||||
|
fn load_segment(filename: &'static str) -> Segment {
|
||||||
|
Segment::from(dot_vox::load(&(concat!(env!("CARGO_MANIFEST_DIR"), "/test_assets/").to_string() + filename)).unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
impl Scene {
|
impl Scene {
|
||||||
/// Create a new `Scene` with default parameters.
|
/// Create a new `Scene` with default parameters.
|
||||||
pub fn new(renderer: &mut Renderer) -> Self {
|
pub fn new(renderer: &mut Renderer) -> Self {
|
||||||
Self {
|
Self {
|
||||||
camera: Camera::new(),
|
camera: Camera::new(),
|
||||||
globals: renderer
|
globals: renderer
|
||||||
.create_consts_with(Globals::default())
|
.create_consts(&[Globals::default()])
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
skybox: Skybox {
|
skybox: Skybox {
|
||||||
model: renderer
|
model: renderer
|
||||||
.create_model(&create_skybox_mesh())
|
.create_model(&create_skybox_mesh())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
locals: renderer
|
locals: renderer
|
||||||
.create_consts_with(SkyboxLocals::default())
|
.create_consts(&[SkyboxLocals::default()])
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
test_figure: Figure::new(
|
||||||
|
renderer,
|
||||||
|
[
|
||||||
|
Some(load_segment("head.vox").generate_mesh_with_offset(Vec3::new(-7.0, -5.5, -1.0))),
|
||||||
|
Some(load_segment("chest.vox").generate_mesh_with_offset(Vec3::new(-6.0, -3.0, 0.0))),
|
||||||
|
Some(load_segment("belt.vox").generate_mesh_with_offset(Vec3::new(-5.0, -3.0, 0.0))),
|
||||||
|
Some(load_segment("pants.vox").generate_mesh_with_offset(Vec3::new(-5.0, -3.0, 0.0))),
|
||||||
|
Some(load_segment("foot.vox").generate_mesh_with_offset(Vec3::new(-2.5, -3.0, 0.0))),
|
||||||
|
Some(load_segment("foot.vox").generate_mesh_with_offset(Vec3::new(-2.5, -3.0, 0.0))),
|
||||||
|
Some(load_segment("hand.vox").generate_mesh_with_offset(Vec3::new(-2.0, -2.0, -1.0))),
|
||||||
|
Some(load_segment("hand.vox").generate_mesh_with_offset(Vec3::new(-2.0, -2.0, -1.0))),
|
||||||
|
Some(load_segment("sword.vox").generate_mesh_with_offset(Vec3::new(-6.5, -1.0, 0.0))),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
|
||||||
client: Client::new(),
|
client: Client::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,7 +130,7 @@ impl Scene {
|
|||||||
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents();
|
let (view_mat, proj_mat, cam_pos) = self.camera.compute_dependents();
|
||||||
|
|
||||||
// Update global constants
|
// Update global constants
|
||||||
renderer.update_consts(&mut self.globals, Globals::new(
|
renderer.update_consts(&mut self.globals, &[Globals::new(
|
||||||
view_mat,
|
view_mat,
|
||||||
proj_mat,
|
proj_mat,
|
||||||
cam_pos,
|
cam_pos,
|
||||||
@ -100,8 +138,32 @@ impl Scene {
|
|||||||
10.0,
|
10.0,
|
||||||
self.client.state().get_time_of_day(),
|
self.client.state().get_time_of_day(),
|
||||||
0.0,
|
0.0,
|
||||||
))
|
)])
|
||||||
.expect("Failed to update global constants");
|
.expect("Failed to update global constants");
|
||||||
|
|
||||||
|
// TODO: Don't do this here
|
||||||
|
let offs = (self.client.state().get_tick() as f32 * 10.0).sin();
|
||||||
|
self.test_figure.skeleton.bone_mut(0).offset = Vec3::new(0.0, 0.0, 13.0);
|
||||||
|
self.test_figure.skeleton.bone_mut(0).ori = Quaternion::rotation_z(offs * 0.3);
|
||||||
|
// Chest
|
||||||
|
self.test_figure.skeleton.bone_mut(1).offset = Vec3::new(0.0, 0.0, 9.0);
|
||||||
|
self.test_figure.skeleton.bone_mut(2).offset = Vec3::new(0.0, 0.0, 7.0);
|
||||||
|
self.test_figure.skeleton.bone_mut(3).offset = Vec3::new(0.0, 0.0, 4.0);
|
||||||
|
self.test_figure.skeleton.bone_mut(1).ori = Quaternion::rotation_z(offs * 0.15);
|
||||||
|
self.test_figure.skeleton.bone_mut(2).ori = Quaternion::rotation_z(offs * 0.15);
|
||||||
|
self.test_figure.skeleton.bone_mut(3).ori = Quaternion::rotation_z(offs * 0.15);
|
||||||
|
//Feet
|
||||||
|
self.test_figure.skeleton.bone_mut(4).offset = Vec3::new(-3.0, -offs * 4.0, 0.0);
|
||||||
|
self.test_figure.skeleton.bone_mut(5).offset = Vec3::new(3.0, offs * 4.0, 0.0);
|
||||||
|
// Hands
|
||||||
|
self.test_figure.skeleton.bone_mut(6).offset = Vec3::new(-8.0, offs * 4.0, 9.0);
|
||||||
|
self.test_figure.skeleton.bone_mut(7).offset = Vec3::new(8.0, -offs * 4.0, 9.0);
|
||||||
|
// Sword
|
||||||
|
self.test_figure.skeleton.bone_mut(8).offset = Vec3::new(-8.0, 5.0, 24.0);
|
||||||
|
self.test_figure.skeleton.bone_mut(8).ori = Quaternion::rotation_y(2.5);
|
||||||
|
|
||||||
|
self.test_figure.update_locals(renderer, FigureLocals::default());
|
||||||
|
self.test_figure.update_skeleton(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render the scene using the provided `Renderer`
|
/// Render the scene using the provided `Renderer`
|
||||||
@ -109,8 +171,11 @@ impl Scene {
|
|||||||
// Render the skybox first (it appears over everything else so must be rendered first)
|
// Render the skybox first (it appears over everything else so must be rendered first)
|
||||||
renderer.render_skybox(
|
renderer.render_skybox(
|
||||||
&self.skybox.model,
|
&self.skybox.model,
|
||||||
&self.skybox.locals,
|
|
||||||
&self.globals,
|
&self.globals,
|
||||||
|
&self.skybox.locals,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Render the test figure
|
||||||
|
self.test_figure.render(renderer, &self.globals);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
voxygen/test_assets/belt.vox
Normal file
BIN
voxygen/test_assets/belt.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/chest.vox
Normal file
BIN
voxygen/test_assets/chest.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/foot.vox
Normal file
BIN
voxygen/test_assets/foot.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/hand.vox
Normal file
BIN
voxygen/test_assets/hand.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/head.vox
Normal file
BIN
voxygen/test_assets/head.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/knight.vox
Normal file
BIN
voxygen/test_assets/knight.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/pants.vox
Normal file
BIN
voxygen/test_assets/pants.vox
Normal file
Binary file not shown.
BIN
voxygen/test_assets/sword.vox
Normal file
BIN
voxygen/test_assets/sword.vox
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user