ui refactor, started implementing save/load

This commit is contained in:
Dmitry
2019-08-13 23:03:03 +03:00
parent fd66a486e4
commit 6a3f5295d9
15 changed files with 30744 additions and 354 deletions
+12 -5
View File
@@ -6,7 +6,19 @@
<component name="ChangeListManager">
<list default="true" id="1932b2c4-d6ff-413c-9558-19959667326b" name="Default Changelist" comment="scene graph">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/engine/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/engine/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/game/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/game/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/gui/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/gui/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/math/mat4.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/math/mat4.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/physics/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/physics/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/resource/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/resource/model.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/model.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/resource/texture.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/resource/texture.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/animation.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/animation.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/mod.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/mod.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/scene/node.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/scene/node.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/utils/pool.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/pool.rs" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/utils/rcpool.rs" beforeDir="false" afterPath="$PROJECT_DIR$/src/utils/rcpool.rs" afterDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
@@ -91,11 +103,6 @@
<envs />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Cargo Command.Debug" />
</list>
</recent_temporary>
</component>
<component name="RustProjectSettings">
<option name="toolchainHomeDirectory" value="$USER_HOME$/.cargo/bin" />
+30115
View File
File diff suppressed because it is too large Load Diff
+64 -9
View File
@@ -1,6 +1,12 @@
use crate::{
scene::*,
utils::pool::*,
utils::{
pool::*,
rcpool::{
RcPool,
RcHandle
}
},
renderer::{
renderer::*,
surface::SurfaceSharedData
@@ -11,7 +17,6 @@ use crate::{
model::Model,
ttf::Font
},
utils::rcpool::{RcPool, RcHandle},
gui::UserInterface,
math::vec2::Vec2
};
@@ -20,8 +25,13 @@ use std::{
collections::VecDeque,
time::Duration
};
use serde::{Serialize, Deserialize};
use serde::{
Serialize,
Deserialize
};
use std::any::{Any, TypeId};
#[derive(Serialize, Deserialize)]
pub struct ResourceManager {
resources: RcPool<Resource>,
/// Path to textures, extensively used for resource files
@@ -102,9 +112,8 @@ impl ResourceManager {
#[derive(Serialize, Deserialize)]
pub struct State {
scenes: Pool<Scene>,
surf_data_storage: RcPool<SurfaceSharedData>,
#[serde(skip)]
surf_data_storage: RcPool<SurfaceSharedData>,
resource_manager: ResourceManager,
}
@@ -174,14 +183,50 @@ impl State {
ResourceKind::Model(model) => {
self.destroy_scene_internal(model.get_scene_mut());
}
ResourceKind::Texture(texture) => {
}
ResourceKind::Texture(texture) => ()
}
println!("Resource destroyed: {}!", resource.get_path().display());
}
}
fn clear(&mut self) {
for i in 0..self.scenes.get_capacity() {
if let Some(mut scene) = self.scenes.take_at(i) {
self.destroy_scene_internal(&mut scene);
}
}
if self.surf_data_storage.alive_count() != 0 {
println!("Not all shared surface data was freed! {} left alive!", self.surf_data_storage.alive_count());
}
}
fn resolve(&mut self) {
// Reload all resources first.
for i in 0..self.resource_manager.resources.get_capacity() {
let path;
let id;
if let Some(resource) = self.resource_manager.resources.at(i) {
path = PathBuf::from(resource.get_path());
match resource.borrow_kind() {
ResourceKind::Model(model) => id = model.type_id(),
ResourceKind::Texture(texture) => id = texture.type_id()
}
} else {
continue
}
let handle = self.resource_manager.resources.handle_from_index(i);
if id == TypeId::of::<Model>() {
let model = Model::load(path.as_path(), self).unwrap();
let resource = Resource::new(path.as_path(), ResourceKind::Model(model));
self.resource_manager.resources.replace(&handle, resource);
} else if id == TypeId::of::<Texture>() {
}
}
}
#[inline]
pub fn get_scenes(&self) -> &Pool<Scene> {
&self.scenes
@@ -248,7 +293,7 @@ impl State {
pub struct Engine {
renderer: Renderer,
state: State,
pub state: State,
events: VecDeque<glutin::Event>,
running: bool,
font_cache: Pool<Font>,
@@ -336,6 +381,16 @@ impl Engine {
self.renderer.get_statistics()
}
pub fn save<W>(&self, writer: W) where W: std::io::Write {
serde_json::to_writer_pretty(writer, &self.state).unwrap();
}
pub fn load<R>(&mut self, reader: R) where R: std::io::Read {
self.state.clear();
self.state = serde_json::from_reader(reader).unwrap();
self.state.resolve();
}
pub fn render(&mut self) {
self.renderer.upload_font_cache(&mut self.font_cache);
self.renderer.upload_resources(&mut self.state);
+44 -17
View File
@@ -17,6 +17,7 @@ use crate::{
ButtonBuilder,
Thickness,
TextBuilder,
ScrollBarBuilder
},
utils::pool::Handle,
math::vec2::Vec2,
@@ -29,11 +30,12 @@ use std::{
time::Instant,
rc::Rc,
};
use crate::gui::ScrollBarBuilder;
pub struct MenuState {
start_new_game: bool,
quit_game: bool
save_game: Option<()>,
load_game: Option<()>,
start_new_game: Option<()>,
quit_game: Option<()>
}
pub struct Menu {
@@ -57,8 +59,10 @@ impl Game {
let engine = Engine::new();
let mut game = Game {
menu: Menu { state: Rc::new(RefCell::new(MenuState {
start_new_game: false,
quit_game: false,
start_new_game: None,
quit_game: None,
save_game: None,
load_game: None,
})) },
debug_text: Handle::none(),
engine,
@@ -96,30 +100,36 @@ impl Game {
.with_margin(Thickness::uniform(4.0))
.with_click(Box::new(move |_ui, _handle| {
if let Ok(mut state) = menu_state.try_borrow_mut() {
state.start_new_game = true;
state.start_new_game = Some(());
}
}))
.build(ui)
})
.with_child({
let menu_state = self.menu.state.clone();
ButtonBuilder::new()
.with_text("Save Game")
.on_column(0)
.on_row(1)
.with_margin(Thickness::uniform(4.0))
.with_click(Box::new(|_ui, _handle| {
println!("Save Game Clicked!");
.with_click(Box::new(move |_ui, _handle| {
if let Ok(mut state) = menu_state.try_borrow_mut() {
state.save_game = Some(());
}
}))
.build(ui)
})
.with_child({
let menu_state = self.menu.state.clone();
ButtonBuilder::new()
.with_text("Load Game")
.on_column(0)
.on_row(2)
.with_margin(Thickness::uniform(4.0))
.with_click(Box::new(|_ui, _handle| {
println!("Load Game Clicked!");
.with_click(Box::new(move |_ui, _handle| {
if let Ok(mut state) = menu_state.try_borrow_mut() {
state.load_game = Some(());
}
}))
.build(ui)
})
@@ -143,7 +153,7 @@ impl Game {
.with_margin(Thickness::uniform(4.0))
.with_click(Box::new(move |_ui, _handle| {
if let Ok(mut state) = menu_state.try_borrow_mut() {
state.quit_game = true;
state.quit_game = Some(());
}
}))
.build(ui)
@@ -155,15 +165,24 @@ impl Game {
.build(ui);
}
pub fn make_save(&self) {
match File::create(Path::new("test.json")) {
pub fn save_game(&self) {
match File::create(Path::new("save.json")) {
Ok(file) => {
serde_json::to_writer_pretty(file, self.engine.get_state()).unwrap();
self.engine.save(file)
}
Err(_) => println!("unable to create a save"),
}
}
pub fn load_game(&mut self) {
match File::open(Path::new("save.json")) {
Ok(file) => {
self.engine.load(file)
}
Err(_) => println!("failed to load a save!")
}
}
fn destroy_level(&mut self) {
if let Some(ref mut level) = self.level.take() {
level.destroy(&mut self.engine);
@@ -177,15 +196,22 @@ impl Game {
pub fn update_menu(&mut self) {
if let Ok(mut state) = self.menu.state.clone().try_borrow_mut() {
if state.start_new_game {
state.start_new_game = false;
if let Some(_) = state.start_new_game.take() {
self.start_new_game();
}
if state.quit_game {
if let Some(_) = state.quit_game.take() {
self.destroy_level();
self.engine.stop();
}
if let Some(_) = state.save_game.take() {
self.save_game();
}
if let Some(_) = state.load_game.take() {
self.load_game();
}
}
}
@@ -247,5 +273,6 @@ impl Game {
// Render at max speed
self.engine.render();
}
self.destroy_level();
}
}
+405 -318
View File
@@ -331,7 +331,7 @@ impl CanvasBuilder {
impl_default_builder_methods!();
pub fn build(self, ui: &mut UserInterface) -> Handle<UINode> {
GenericNodeBuilder::new(UINodeKind::Canvas, self.common).build(ui)
GenericNodeBuilder::new(UINodeKind::Canvas(Canvas {}), self.common).build(ui)
}
}
@@ -439,12 +439,89 @@ impl BorderBuilder {
}
}
pub trait Layout {
fn measure_override(&mut self, ui: &mut UserInterface, children: &UnsafeCollectionView<Handle<UINode>>, available_size: &Vec2) -> Vec2;
fn arrange_override(&self, ui: &mut UserInterface, children: &UnsafeCollectionView<Handle<UINode>>, final_size: &Vec2) -> Vec2;
}
#[derive(Debug)]
pub struct Border {
stroke_thickness: Thickness,
stroke_color: Color,
}
impl Layout for Border {
fn measure_override(&mut self, ui: &mut UserInterface, children: &UnsafeCollectionView<Handle<UINode>>, available_size: &Vec2) -> Vec2 {
let margin_x = self.stroke_thickness.left + self.stroke_thickness.right;
let margin_y = self.stroke_thickness.top + self.stroke_thickness.bottom;
let size_for_child = Vec2::make(
available_size.x - margin_x,
available_size.y - margin_y,
);
let mut desired_size = Vec2::new();
for child_handle in children.iter() {
ui.measure(child_handle, &size_for_child);
if let Some(child) = ui.nodes.borrow(child_handle) {
if child.desired_size.x > desired_size.x {
desired_size.x = child.desired_size.x;
}
if child.desired_size.y > desired_size.y {
desired_size.y = child.desired_size.y;
}
}
}
desired_size.x += margin_x;
desired_size.y += margin_y;
desired_size
}
fn arrange_override(&self, ui: &mut UserInterface, children: &UnsafeCollectionView<Handle<UINode>>, final_size: &Vec2) -> Vec2 {
let rect_for_child = Rect::new(
self.stroke_thickness.left, self.stroke_thickness.top,
final_size.x - (self.stroke_thickness.right + self.stroke_thickness.left),
final_size.y - (self.stroke_thickness.bottom + self.stroke_thickness.top),
);
for child_handle in children.iter() {
ui.arrange(child_handle, &rect_for_child);
}
*final_size
}
}
impl Layout for UINodeKind {
fn measure_override(&mut self, ui: &mut UserInterface, children: &UnsafeCollectionView<Handle<UINode>>, available_size: &Vec2) -> Vec2 {
match self {
UINodeKind::Border(border) => border.measure_override(ui, children, available_size),
UINodeKind::Canvas(canvas) => canvas.measure_override(ui, children, available_size),
UINodeKind::Grid(grid) => grid.measure_override(ui, children, available_size),
_ => ui.default_measure_override(children, available_size)
}
}
fn arrange_override(&self, ui: &mut UserInterface, children: &UnsafeCollectionView<Handle<UINode>>, final_size: &Vec2) -> Vec2 {
match self {
UINodeKind::Border(border) => border.arrange_override(ui, children, final_size),
UINodeKind::Canvas(canvas) => canvas.arrange_override(ui, children, final_size),
UINodeKind::Grid(grid) => grid.arrange_override(ui, children, final_size),
// Default arrangement
_ => {
let final_rect = Rect::new(0.0, 0.0, final_size.x, final_size.y);
for child_handle in children.iter() {
ui.arrange(child_handle, &final_rect);
}
*final_size
}
}
}
}
impl Border {
pub fn new() -> Border {
Border {
@@ -991,6 +1068,70 @@ impl ScrollBarBuilder {
}
}
pub struct ScrollContentPresenter {
scroll: Vec2,
vertical_scroll_allowed: bool,
horizontal_scroll_allowed: bool,
}
impl ScrollContentPresenter {
pub fn new() -> Self {
Self {
scroll: Vec2::new(),
vertical_scroll_allowed: true,
horizontal_scroll_allowed: true,
}
}
}
pub struct ScrollContentPresenterBuilder {
vertical_scroll_allowed: Option<bool>,
horizontal_scroll_allowed: Option<bool>,
content: Option<Handle<UINode>>,
common: CommonBuilderFields,
}
impl ScrollContentPresenterBuilder {
pub fn new() -> Self {
Self {
vertical_scroll_allowed: None,
horizontal_scroll_allowed: None,
common: CommonBuilderFields::new(),
content: None,
}
}
impl_default_builder_methods!();
pub fn with_content(mut self, content: Handle<UINode>) -> Self {
self.content = Some(content);
self
}
pub fn with_vertical_scroll_allowed(mut self, value: bool) -> Self {
self.vertical_scroll_allowed = Some(value);
self
}
pub fn with_horizontal_scroll_allowed(mut self, value: bool) -> Self {
self.horizontal_scroll_allowed = Some(value);
self
}
pub fn build(self, ui: &mut UserInterface) -> Handle<UINode> {
let mut scp = ScrollContentPresenter::new();
if let Some(vertical_scroll_allowed) = self.vertical_scroll_allowed {
scp.vertical_scroll_allowed = vertical_scroll_allowed;
}
if let Some(horizontal_scroll_allowed) = self.horizontal_scroll_allowed {
scp.horizontal_scroll_allowed = horizontal_scroll_allowed;
}
GenericNodeBuilder::new(UINodeKind::ScrollContentPresenter(scp), self.common)
.with_child(self.content.unwrap_or(Handle::none()))
.build(ui)
}
}
#[derive(PartialEq)]
pub enum SizeMode {
Strict,
@@ -1094,6 +1235,210 @@ pub struct Grid {
draw_borders: bool,
}
impl Layout for Grid {
fn measure_override(&mut self, ui: &mut UserInterface, children: &UnsafeCollectionView<Handle<UINode>>, available_size: &Vec2) -> Vec2 {
// In case of no rows or columns, grid acts like default panel.
if self.columns.is_empty() || self.rows.is_empty() {
return ui.default_measure_override(children, available_size);
}
// Step 1. Measure every children with relaxed constraints (size of grid).
for child_handle in children.iter() {
ui.measure(child_handle, available_size);
}
// Step 2. Calculate width of columns and heights of rows.
let mut preset_width = 0.0;
let mut preset_height = 0.0;
// Step 2.1. Calculate size of strict-sized and auto-sized columns.
for (i, col) in self.columns.iter_mut().enumerate() {
if col.size_mode == SizeMode::Strict {
col.actual_width = col.desired_width;
preset_width += col.actual_width;
} else if col.size_mode == SizeMode::Auto {
col.actual_width = col.desired_width;
for child_handle in children.iter() {
if let Some(child) = ui.nodes.borrow(child_handle) {
if child.column == i && child.visibility == Visibility::Visible {
if child.desired_size.x > col.actual_width {
col.actual_width = child.desired_size.x;
}
}
}
}
preset_width += col.actual_width;
}
}
// Step 2.2. Calculate size of strict-sized and auto-sized rows.
for (i, row) in self.rows.iter_mut().enumerate() {
if row.size_mode == SizeMode::Strict {
row.actual_height = row.desired_height;
preset_height += row.actual_height;
} else if row.size_mode == SizeMode::Auto {
row.actual_height = row.desired_height;
for child_handle in children.iter() {
if let Some(child) = ui.nodes.borrow(child_handle) {
if child.row == i && child.visibility == Visibility::Visible {
if child.desired_size.y > row.actual_height {
row.actual_height = child.desired_size.y;
}
}
}
}
preset_height += row.actual_height;
}
}
// Step 2.3. Fit stretch-sized columns
let mut rest_width = 0.0;
if available_size.x.is_infinite() {
for child_handle in children.iter() {
if let Some(child) = ui.nodes.borrow(child_handle) {
if let Some(column) = self.columns.get(child.column) {
if column.size_mode == SizeMode::Stretch {
rest_width += child.desired_size.x;
}
}
}
}
} else {
rest_width = available_size.x - preset_width;
}
// count columns first
let mut stretch_sized_columns = 0;
for column in self.columns.iter() {
if column.size_mode == SizeMode::Stretch {
stretch_sized_columns += 1;
}
}
if stretch_sized_columns > 0 {
let width_per_col = rest_width / stretch_sized_columns as f32;
for column in self.columns.iter_mut() {
if column.size_mode == SizeMode::Stretch {
column.actual_width = width_per_col;
}
}
}
// Step 2.4. Fit stretch-sized rows.
let mut stretch_sized_rows = 0;
let mut rest_height = 0.0;
if available_size.y.is_infinite() {
for child_handle in children.iter() {
if let Some(child) = ui.nodes.borrow(child_handle) {
if let Some(row) = self.rows.get(child.row) {
if row.size_mode == SizeMode::Stretch {
rest_height += child.desired_size.y;
}
}
}
}
} else {
rest_height = available_size.y - preset_height;
}
// count rows first
for row in self.rows.iter() {
if row.size_mode == SizeMode::Stretch {
stretch_sized_rows += 1;
}
}
if stretch_sized_rows > 0 {
let height_per_row = rest_height / stretch_sized_rows as f32;
for row in self.rows.iter_mut() {
if row.size_mode == SizeMode::Stretch {
row.actual_height = height_per_row;
}
}
}
// Step 2.5. Calculate positions of each column.
let mut y = 0.0;
for row in self.rows.iter_mut() {
row.y = y;
y += row.actual_height;
}
// Step 2.6. Calculate positions of each row.
let mut x = 0.0;
for column in self.columns.iter_mut() {
column.x = x;
x += column.actual_width;
}
// Step 3. Re-measure children with new constraints.
for child_handle in children.iter() {
let size_for_child = {
if let Some(child) = ui.nodes.borrow(child_handle) {
Vec2 {
x: self.columns[child.column].actual_width,
y: self.rows[child.row].actual_height,
}
} else {
Vec2 {
x: match self.columns.first() {
Some(column) => column.actual_width,
None => 0.0
},
y: match self.rows.first() {
Some(row) => row.actual_height,
None => 0.0
},
}
}
};
ui.measure(child_handle, &size_for_child);
}
// Step 4. Calculate desired size of grid.
let mut desired_size = Vec2::new();
for column in self.columns.iter() {
desired_size.x += column.actual_width;
}
for row in self.rows.iter() {
desired_size.y += row.actual_height;
}
desired_size
}
fn arrange_override(&self, ui: &mut UserInterface, children: &UnsafeCollectionView<Handle<UINode>>, final_size: &Vec2) -> Vec2 {
if self.columns.is_empty() || self.rows.is_empty() {
let rect = Rect::new(0.0, 0.0, final_size.x, final_size.y);
for child_handle in children.iter() {
ui.arrange(child_handle, &rect);
}
return *final_size;
}
for child_handle in children.iter() {
let mut final_rect = None;
if let Some(child) = ui.nodes.borrow(&child_handle) {
if let Some(column) = self.columns.get(child.column) {
if let Some(row) = self.rows.get(child.row) {
final_rect = Some(Rect::new(
column.x,
row.y,
column.actual_width,
row.actual_height,
));
}
}
}
if let Some(rect) = final_rect {
ui.arrange(child_handle, &rect);
}
}
*final_size
}
}
pub struct GridBuilder {
rows: Vec<Row>,
columns: Vec<Column>,
@@ -1156,6 +1501,43 @@ impl Grid {
}
}
pub struct Canvas {}
impl Layout for Canvas {
fn measure_override(&mut self, ui: &mut UserInterface, children: &UnsafeCollectionView<Handle<UINode>>, _available_size: &Vec2) -> Vec2 {
let size_for_child = Vec2::make(
std::f32::INFINITY,
std::f32::INFINITY,
);
for child_handle in children.iter() {
ui.measure(child_handle, &size_for_child);
}
Vec2::new()
}
fn arrange_override(&self, ui: &mut UserInterface, children: &UnsafeCollectionView<Handle<UINode>>, final_size: &Vec2) -> Vec2 {
for child_handle in children.iter() {
let mut final_rect = None;
if let Some(child) = ui.nodes.borrow(&child_handle) {
final_rect = Some(Rect::new(
child.desired_local_position.x,
child.desired_local_position.y,
child.desired_size.x,
child.desired_size.y));
}
if let Some(rect) = final_rect {
ui.arrange(child_handle, &rect);
}
}
*final_size
}
}
pub enum UINodeKind {
Base,
Text(Text),
@@ -1163,7 +1545,6 @@ pub enum UINodeKind {
/// TODO
Window,
Button(Button),
/// TODO
ScrollBar(ScrollBar),
/// TODO
ScrollViewer,
@@ -1173,10 +1554,10 @@ pub enum UINodeKind {
Image,
/// Automatically arranges children by rows and columns
Grid(Grid),
/// TODO Allows user to directly set position and size of a node
Canvas,
/// TODO Allows user to scroll content
ScrollContentPresenter,
/// Allows user to directly set position and size of a node
Canvas(Canvas),
/// Allows user to scroll content
ScrollContentPresenter(ScrollContentPresenter),
/// TODO
SlideSelector,
/// TODO
@@ -1324,7 +1705,7 @@ impl UserInterface {
visual_debug: false,
default_font,
captured_node: Handle::none(),
root_canvas: nodes.spawn(UINode::new(UINodeKind::Canvas)),
root_canvas: nodes.spawn(UINode::new(UINodeKind::Canvas(Canvas {}))),
nodes,
mouse_position: Vec2::new(),
drawing_context: DrawingContext::new(),
@@ -1427,228 +1808,9 @@ impl UserInterface {
size
}
/// Performs recursive kind-specific measurement of children nodes
///
/// Returns desired size.
fn measure_override(&mut self, node_kind: &mut UINodeKind, children: &UnsafeCollectionView<Handle<UINode>>, available_size: &Vec2) -> Vec2 {
match node_kind {
// TODO: Type-specific measure
UINodeKind::Border(border) => {
let margin_x = border.stroke_thickness.left + border.stroke_thickness.right;
let margin_y = border.stroke_thickness.top + border.stroke_thickness.bottom;
let size_for_child = Vec2::make(
available_size.x - margin_x,
available_size.y - margin_y,
);
let mut desired_size = Vec2::new();
for child_handle in children.iter() {
self.measure(child_handle, &size_for_child);
if let Some(child) = self.nodes.borrow(child_handle) {
if child.desired_size.x > desired_size.x {
desired_size.x = child.desired_size.x;
}
if child.desired_size.y > desired_size.y {
desired_size.y = child.desired_size.y;
}
}
}
desired_size.x += margin_x;
desired_size.y += margin_y;
desired_size
}
UINodeKind::Canvas => {
let size_for_child = Vec2::make(
std::f32::INFINITY,
std::f32::INFINITY,
);
for child_handle in children.iter() {
self.measure(child_handle, &size_for_child);
}
Vec2::new()
}
UINodeKind::Grid(grid) => {
// In case of no rows or columns, grid acts like default panel.
if grid.columns.is_empty() || grid.rows.is_empty() {
return self.default_measure_override(children, available_size);
}
// Step 1. Measure every children with relaxed constraints (size of grid).
for child_handle in children.iter() {
self.measure(child_handle, available_size);
}
// Step 2. Calculate width of columns and heights of rows.
let mut preset_width = 0.0;
let mut preset_height = 0.0;
// Step 2.1. Calculate size of strict-sized and auto-sized columns.
for (i, col) in grid.columns.iter_mut().enumerate() {
if col.size_mode == SizeMode::Strict {
col.actual_width = col.desired_width;
preset_width += col.actual_width;
} else if col.size_mode == SizeMode::Auto {
col.actual_width = col.desired_width;
for child_handle in children.iter() {
if let Some(child) = self.nodes.borrow(child_handle) {
if child.column == i && child.visibility == Visibility::Visible {
if child.desired_size.x > col.actual_width {
col.actual_width = child.desired_size.x;
}
}
}
}
preset_width += col.actual_width;
}
}
// Step 2.2. Calculate size of strict-sized and auto-sized rows.
for (i, row) in grid.rows.iter_mut().enumerate() {
if row.size_mode == SizeMode::Strict {
row.actual_height = row.desired_height;
preset_height += row.actual_height;
} else if row.size_mode == SizeMode::Auto {
row.actual_height = row.desired_height;
for child_handle in children.iter() {
if let Some(child) = self.nodes.borrow(child_handle) {
if child.row == i && child.visibility == Visibility::Visible {
if child.desired_size.y > row.actual_height {
row.actual_height = child.desired_size.y;
}
}
}
}
preset_height += row.actual_height;
}
}
// Step 2.3. Fit stretch-sized columns
let mut rest_width = 0.0;
if available_size.x.is_infinite() {
for child_handle in children.iter() {
if let Some(child) = self.nodes.borrow(child_handle) {
if let Some(column) = grid.columns.get(child.column) {
if column.size_mode == SizeMode::Stretch {
rest_width += child.desired_size.x;
}
}
}
}
} else {
rest_width = available_size.x - preset_width;
}
// count columns first
let mut stretch_sized_columns = 0;
for column in grid.columns.iter() {
if column.size_mode == SizeMode::Stretch {
stretch_sized_columns += 1;
}
}
if stretch_sized_columns > 0 {
let width_per_col = rest_width / stretch_sized_columns as f32;
for column in grid.columns.iter_mut() {
if column.size_mode == SizeMode::Stretch {
column.actual_width = width_per_col;
}
}
}
// Step 2.4. Fit stretch-sized rows.
let mut stretch_sized_rows = 0;
let mut rest_height = 0.0;
if available_size.y.is_infinite() {
for child_handle in children.iter() {
if let Some(child) = self.nodes.borrow(child_handle) {
if let Some(row) = grid.rows.get(child.row) {
if row.size_mode == SizeMode::Stretch {
rest_height += child.desired_size.y;
}
}
}
}
} else {
rest_height = available_size.y - preset_height;
}
// count rows first
for row in grid.rows.iter() {
if row.size_mode == SizeMode::Stretch {
stretch_sized_rows += 1;
}
}
if stretch_sized_rows > 0 {
let height_per_row = rest_height / stretch_sized_rows as f32;
for row in grid.rows.iter_mut() {
if row.size_mode == SizeMode::Stretch {
row.actual_height = height_per_row;
}
}
}
// Step 2.5. Calculate positions of each column.
let mut y = 0.0;
for row in grid.rows.iter_mut() {
row.y = y;
y += row.actual_height;
}
// Step 2.6. Calculate positions of each row.
let mut x = 0.0;
for column in grid.columns.iter_mut() {
column.x = x;
x += column.actual_width;
}
// Step 3. Re-measure children with new constraints.
for child_handle in children.iter() {
let size_for_child = {
if let Some(child) = self.nodes.borrow(child_handle) {
Vec2 {
x: grid.columns[child.column].actual_width,
y: grid.rows[child.row].actual_height,
}
} else {
Vec2 {
x: match grid.columns.first() {
Some(column) => column.actual_width,
None => 0.0
},
y: match grid.rows.first() {
Some(row) => row.actual_height,
None => 0.0
},
}
}
};
self.measure(child_handle, &size_for_child);
}
// Step 4. Calculate desired size of grid.
let mut desired_size = Vec2::new();
for column in grid.columns.iter() {
desired_size.x += column.actual_width;
}
for row in grid.rows.iter() {
desired_size.y += row.actual_height;
}
desired_size
}
// Default measure
_ => {
self.default_measure_override(children, available_size)
}
}
}
fn measure(&mut self, node_handle: &Handle<UINode>, available_size: &Vec2) {
let mut children: UnsafeCollectionView<Handle<UINode>> = UnsafeCollectionView::empty();
let mut node_kind: *mut UINodeKind = std::ptr::null_mut();
let children;
let node_kind;
let size_for_child;
let margin;
@@ -1700,15 +1862,17 @@ impl UserInterface {
// during measure pass. Also this step *cannot* be performed in parallel so we don't
// have to bother about thread-safety here.
children = UnsafeCollectionView::from_vec(&node.children);
// Also store mutable pointer to node kind to perform kind-specific measurement.
node_kind = &mut node.kind as *mut UINodeKind;
} else {
// We do not have any children so node want to collapse into point.
node.desired_size = Vec2::make(0.0, 0.0);
return;
}
}
}
let desired_size = self.measure_override(unsafe { &mut *node_kind }, &children, &size_for_child);
let desired_size = (unsafe { &mut *node_kind }).measure_override(self, &children, &size_for_child);
if let Some(node) = self.nodes.borrow_mut(&node_handle) {
node.desired_size = desired_size;
@@ -1745,97 +1909,13 @@ impl UserInterface {
}
}
/// Performs recursive kind-specific arrangement of children nodes
///
/// Returns actual size.
fn arrange_override(&mut self, node_kind: &UINodeKind, children: &UnsafeCollectionView<Handle<UINode>>, final_size: &Vec2) -> Vec2 {
match node_kind {
// TODO: Kind-specific arrangement
UINodeKind::Border(border) => {
let rect_for_child = Rect::new(
border.stroke_thickness.left, border.stroke_thickness.top,
final_size.x - (border.stroke_thickness.right + border.stroke_thickness.left),
final_size.y - (border.stroke_thickness.bottom + border.stroke_thickness.top),
);
for child_handle in children.iter() {
self.arrange(child_handle, &rect_for_child);
}
*final_size
}
UINodeKind::Canvas => {
for child_handle in children.iter() {
let mut final_rect = None;
if let Some(child) = self.nodes.borrow(&child_handle) {
final_rect = Some(Rect::new(
child.desired_local_position.x,
child.desired_local_position.y,
child.desired_size.x,
child.desired_size.y));
}
if let Some(rect) = final_rect {
self.arrange(child_handle, &rect);
}
}
*final_size
}
UINodeKind::Grid(grid) => {
if grid.columns.is_empty() || grid.rows.is_empty() {
let rect = Rect::new(0.0, 0.0, final_size.x, final_size.y);
for child_handle in children.iter() {
self.arrange(child_handle, &rect);
}
return *final_size;
}
for child_handle in children.iter() {
let mut final_rect = None;
if let Some(child) = self.nodes.borrow(&child_handle) {
if let Some(column) = grid.columns.get(child.column) {
if let Some(row) = grid.rows.get(child.row) {
final_rect = Some(Rect::new(
column.x,
row.y,
column.actual_width,
row.actual_height,
));
}
}
}
if let Some(rect) = final_rect {
self.arrange(child_handle, &rect);
}
}
*final_size
}
// Default arrangement
_ => {
let final_rect = Rect::new(0.0, 0.0, final_size.x, final_size.y);
for child_handle in children.iter() {
self.arrange(child_handle, &final_rect);
}
*final_size
}
}
}
fn arrange(&mut self, node_handle: &Handle<UINode>, final_rect: &Rect<f32>) {
let children: UnsafeCollectionView<Handle<UINode>>;
let children;
let mut size;
let size_without_margin;
let mut origin_x;
let mut origin_y;
let node_kind: *const UINodeKind;
let node_kind;
match self.nodes.borrow_mut(node_handle) {
None => return,
@@ -1878,7 +1958,7 @@ impl UserInterface {
}
}
size = self.arrange_override(unsafe { &*node_kind }, &children, &size);
size = (unsafe { &*node_kind }).arrange_override(self, &children, &size);
if let Some(node) = self.nodes.borrow_mut(node_handle) {
if size.x > final_rect.w {
@@ -1941,6 +2021,8 @@ impl UserInterface {
self.measure(&root_canvas_handle, screen_size);
self.arrange(&root_canvas_handle, &Rect::new(0.0, 0.0, screen_size.x, screen_size.y));
self.update_transform(&root_canvas_handle);
// Do deferred actions. Some sort of simplest dispatcher.
while let Some(mut action) = self.deferred_actions.pop_front() {
action(self)
}
@@ -1955,7 +2037,6 @@ impl UserInterface {
self.drawing_context.set_nesting(nesting);
node.command_indices.push(self.drawing_context.commit_clip_rect(&bounds.inflate(0.9, 0.9)));
match &mut node.kind {
UINodeKind::Border(border) => {
self.drawing_context.push_rect_filled(&bounds, None, node.color);
@@ -2152,7 +2233,7 @@ impl UserInterface {
Handle::none()
}
/// Searches a node up on tree starting from give root that matches a criteria
/// Searches a node up on tree starting from given root that matches a criteria
/// defined by a given func.
pub fn find_by_criteria_up<Func>(&self, node_handle: &Handle<UINode>, func: Func) -> Handle<UINode>
where Func: Fn(&UINode) -> bool {
@@ -2167,26 +2248,32 @@ impl UserInterface {
Handle::none()
}
/// Searches a node by name up on tree starting from given root node.
pub fn find_by_name_up(&self, node_handle: &Handle<UINode>, name: &str) -> Handle<UINode> {
self.find_by_criteria_up(node_handle, |node| node.name == name)
}
/// Searches a node by name down on tree starting from given root node.
pub fn find_by_name_down(&self, node_handle: &Handle<UINode>, name: &str) -> Handle<UINode> {
self.find_by_criteria_down(node_handle, &|node| node.name == name)
}
/// Searches a node by name up on tree starting from given root node and tries to borrow it if exists.
pub fn borrow_by_name_up(&self, start_node_handle: &Handle<UINode>, name: &str) -> Option<&UINode> {
self.nodes.borrow(&self.find_by_name_up(start_node_handle, name))
}
/// Searches a node by name up on tree starting from given root node and tries to borrow it as mutable if exists.
pub fn borrow_by_name_up_mut(&mut self, start_node_handle: &Handle<UINode>, name: &str) -> Option<&mut UINode> {
self.nodes.borrow_mut(&self.find_by_name_up(start_node_handle, name))
}
/// Searches a node by name down on tree starting from given root node and tries to borrow it if exists.
pub fn borrow_by_name_down(&self, start_node_handle: &Handle<UINode>, name: &str) -> Option<&UINode> {
self.nodes.borrow(&self.find_by_name_down(start_node_handle, name))
}
/// Searches a node by name down on tree starting from given root node and tries to borrow it as mutable if exists.
pub fn borrow_by_name_down_mut(&mut self, start_node_handle: &Handle<UINode>, name: &str) -> Option<&mut UINode> {
self.nodes.borrow_mut(&self.find_by_name_down(start_node_handle, name))
}
+6
View File
@@ -12,6 +12,12 @@ pub struct Mat4 {
pub f: [f32; 16]
}
impl Default for Mat4 {
fn default() -> Self {
Mat4::identity()
}
}
impl Mat4 {
pub fn identity() -> Self {
Self {
+1
View File
@@ -35,6 +35,7 @@ impl StaticGeometry {
#[derive(Serialize, Deserialize)]
pub struct StaticTriangle {
#[serde(skip)]
points: [Vec3; 3],
#[serde(skip)]
ca: Vec3,
+3
View File
@@ -3,6 +3,7 @@ pub mod fbx;
pub mod model;
pub mod ttf;
use serde::{Serialize, Deserialize};
use std::path::*;
use crate::{
resource::{
@@ -11,11 +12,13 @@ use crate::{
}
};
#[derive(Serialize, Deserialize)]
pub enum ResourceKind {
Texture(Texture),
Model(Model),
}
#[derive(Serialize, Deserialize)]
pub struct Resource {
path: PathBuf,
kind: ResourceKind
+4
View File
@@ -14,7 +14,11 @@ use crate::{
};
use std::path::Path;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Model {
#[serde(skip)]
scene: Scene,
}
+8
View File
@@ -1,5 +1,7 @@
use std::path::*;
use serde::{Serialize, Deserialize};
pub struct Rgba8 {
pub r: u8,
pub g: u8,
@@ -7,11 +9,17 @@ pub struct Rgba8 {
pub a: u8,
}
#[derive(Serialize, Deserialize)]
pub struct Texture {
#[serde(skip)]
pub(crate) width: u32,
#[serde(skip)]
pub(crate) height: u32,
#[serde(skip)]
pub(crate) gpu_tex: u32,
#[serde(skip)]
pub(crate) need_upload: bool,
#[serde(skip)]
pub(crate) pixels: Vec<Rgba8>,
}
+24 -2
View File
@@ -1,7 +1,29 @@
pub struct KeyFrame {
use crate::{
math::{
vec3::Vec3,
quat::Quat
},
utils::rcpool::RcHandle,
resource::Resource
};
pub struct KeyFrame {
position: Vec3,
scale: Vec3,
rotation: Quat,
time: f32,
}
pub struct Track {
frames: Vec<KeyFrame>
}
pub struct Animation {
tracks: Vec<Track>,
speed: f32,
length: f32,
time_position: f32,
weight: f32,
fade_step: f32,
resource: RcHandle<Resource>
}
+9 -3
View File
@@ -29,9 +29,8 @@ pub struct Scene {
stack: Vec<Handle<Node>>,
}
impl Scene {
#[inline]
pub fn new() -> Scene {
impl Default for Scene {
fn default() -> Self {
let mut nodes: Pool<Node> = Pool::new();
let root = nodes.spawn(Node::new(NodeKind::Base));
Scene {
@@ -41,6 +40,13 @@ impl Scene {
physics: Physics::new(),
}
}
}
impl Scene {
#[inline]
pub fn new() -> Scene {
Scene::default()
}
/// Transfers ownership of node into scene.
/// Returns handle to node.
+2
View File
@@ -181,7 +181,9 @@ pub struct Node {
pub(super) global_visibility: bool,
pub(super) parent: Handle<Node>,
pub(crate) children: Vec<Handle<Node>>,
#[serde(skip)]
pub(super) local_transform: Mat4,
#[serde(skip)]
pub(crate) global_transform: Mat4,
body: Handle<Body>,
resource: RcHandle<Resource>
+22
View File
@@ -210,6 +210,10 @@ impl<T> Pool<T> {
self.records.len()
}
pub fn clear(&mut self) {
self.records.clear()
}
#[inline]
#[must_use]
pub fn at_mut(&mut self, n: usize) -> Option<&mut T> {
@@ -243,6 +247,12 @@ impl<T> Pool<T> {
Handle::none()
}
#[inline]
#[must_use]
pub fn alive_count(&self) -> usize {
self.records.iter().count()
}
/// Moves object by specified handle out of the pool.
#[inline]
#[must_use]
@@ -255,6 +265,18 @@ impl<T> Pool<T> {
}
}
/// Moves object by specified index out of the pool.
#[inline]
#[must_use]
pub fn take_at(&mut self, index: usize) -> Option<T> {
if let Some(record) = self.records.get_mut(index) {
self.free_stack.push(index as u32);
record.payload.take()
} else {
None
}
}
#[inline]
pub fn is_valid_handle(&self, handle: &Handle<T>) -> bool {
if let Some(record) = self.records.get(handle.index as usize) {
+25
View File
@@ -19,6 +19,12 @@ pub struct RcPool<T: Sized> {
free_stack: Vec<u32>,
}
impl<T> Default for RcPool<T> {
fn default() -> Self {
RcPool::new()
}
}
///
/// Handle is some sort of non-owning reference to content in a pool.
/// It stores index of object and additional information that
@@ -218,6 +224,19 @@ impl<T> RcPool<T> {
None
}
pub fn replace(&mut self, handle: &RcHandle<T>, payload: T) -> Option<T> {
if let Some(record) = self.records.get_mut(handle.index as usize) {
if record.generation == handle.generation {
return record.payload.replace(payload);
} else if handle.generation != RcPool::<T>::INVALID_GENERATION {
println!("RcPool: Generation does not match: record has {} generation, but handle has {}", record.generation, handle.generation);
}
} else {
println!("RcPool: Invalid index: got {}, but valid range is 0..{}", handle.index, self.records.len());
}
None
}
#[inline]
#[must_use]
pub fn get_capacity(&self) -> usize {
@@ -234,6 +253,12 @@ impl<T> RcPool<T> {
}
}
#[inline]
#[must_use]
pub fn alive_count(&self) -> usize {
self.records.iter().count()
}
#[inline]
#[must_use]
pub fn at_mut(&mut self, n: usize) -> Option<&mut T> {