Skip to content

Commit

Permalink
fix: camera raycast and uitext size computing (#434)
Browse files Browse the repository at this point in the history
* fix: raycast from camera or player entity not working if they haven't been created before
fix preview hotreload

* fix: the size of UI is now calculated without redrawing and the flexbox is well-defined with a measure function
  • Loading branch information
leanmendoza authored Jul 11, 2024
1 parent b81a27a commit f4fa5d2
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 44 deletions.
7 changes: 7 additions & 0 deletions godot/src/logic/scene_fetcher.gd
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,13 @@ func reload_scene(scene_id: String) -> void:
if scene_number_id != -1:
Global.scene_runner.kill_scene(scene_number_id)

var scene_entity_definition: DclSceneEntityDefinition = scene.scene_entity_definition
var local_main_js_path: String = (
"user://content/" + scene_entity_definition.get_main_js_hash()
)
if not local_main_js_path.is_empty() and FileAccess.file_exists(local_main_js_path):
DirAccess.remove_absolute(local_main_js_path)

loaded_scenes.erase(scene_id)
scene_entity_coordinator.reload_scene_data(scene_id)
_is_reloading = true
Expand Down
2 changes: 1 addition & 1 deletion lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ futures-util = "0.3.30"

livekit = { git = "https://github.com/livekit/rust-sdks", features=["rustls-tls-webpki-roots"], optional = true, rev="8b276f9d4b98437a139e1cbe41cfda1332ce1120" }

taffy = { git = "https://github.com/DioxusLabs/taffy", rev="7eee673c5ea65f64f35c53f5ee2fe5faf62b9c1e" }
taffy = "0.5.2"
tracing-test = "0.2.4"

base64 = "0.21.5"
Expand Down
4 changes: 3 additions & 1 deletion lib/src/dcl/common/scene.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::ops::Range;
use std::{collections::HashMap, ops::Range};

use godot::builtin::{Vector2i, Vector3};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -74,6 +74,8 @@ pub struct SceneEntityMetadata {
pub scene: SceneMetaScene,
pub runtime_version: Option<String>,
pub spawn_points: Option<Vec<SpawnPoint>>,
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}

impl<'de> serde::Deserialize<'de> for SceneMetaScene {
Expand Down
13 changes: 7 additions & 6 deletions lib/src/godot_classes/dcl_ui_text.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use godot::{
engine::{
control::{LayoutPreset, LayoutPresetMode},
control::LayoutPreset,
global::{HorizontalAlignment, VerticalAlignment},
text_server::JustificationFlag,
Label,
},
prelude::*,
Expand Down Expand Up @@ -69,14 +70,16 @@ impl DclUiText {
.add_theme_color_override("font_outline_color".into(), outline_font_color);
self.base
.add_theme_constant_override("outline_size".into(), outline_width);
self.base
.add_theme_constant_override("line_spacing".into(), 0);

let text_align = new_value
.text_align
.map(TextAlignMode::from_i32)
.unwrap_or(Some(TextAlignMode::TamMiddleCenter))
.unwrap();

let (hor_align, vert_align, anchor) = match text_align {
let (hor_align, vert_align, _) = match text_align {
TextAlignMode::TamTopLeft => (
HorizontalAlignment::HORIZONTAL_ALIGNMENT_LEFT,
VerticalAlignment::VERTICAL_ALIGNMENT_TOP,
Expand Down Expand Up @@ -127,6 +130,8 @@ impl DclUiText {
self.base.set_vertical_alignment(vert_align);
self.base.set_horizontal_alignment(hor_align);
self.base.set_text(new_value.value.clone().into());
self.base
.set_justification_flags(JustificationFlag::JUSTIFICATION_NONE);

if new_value.font() != self.current_font {
self.current_font = new_value.font();
Expand All @@ -141,9 +146,5 @@ impl DclUiText {
self.base
.set_autowrap_mode(godot::engine::text_server::AutowrapMode::AUTOWRAP_OFF);
}
self.base
.set_anchors_and_offsets_preset_ex(anchor)
.resize_mode(LayoutPresetMode::PRESET_MODE_KEEP_SIZE)
.done();
}
}
7 changes: 3 additions & 4 deletions lib/src/scene_runner/components/raycast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@ pub fn update_raycasts(scene: &mut Scene, crdt_state: &mut SceneCrdtState) {
.chain(scene.continuos_raycast.iter());
let mut raycast_results = Vec::new();
for entity in raycasts {
let Some(entity_node) = scene.godot_dcl_scene.get_node_3d(entity) else {
continue;
};
let (_, node_3d) = scene.godot_dcl_scene.ensure_node_3d(entity);

let Some(raycast) = raycast_component.get(entity) else {
continue;
};
Expand All @@ -67,7 +66,7 @@ pub fn update_raycasts(scene: &mut Scene, crdt_state: &mut SceneCrdtState) {
continue;
};

let result = do_raycast(scene, entity_node, raycast);
let result = do_raycast(scene, &node_3d, raycast);
raycast_results.push((entity, result));
}

Expand Down
136 changes: 106 additions & 30 deletions lib/src/scene_runner/components/ui/scene_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@ use std::{
rc::Rc,
};

use godot::engine::NodeExt;
use godot::{
engine::{
text_server::{JustificationFlag, LineBreakFlag},
NodeExt,
},
obj::Gd,
};

use crate::{
dcl::{
Expand Down Expand Up @@ -56,6 +62,10 @@ const UI_COMPONENT_IDS: [SceneComponentId; 5] = [
SceneComponentId::UI_BACKGROUND,
];

enum ContextNode {
UiText(bool, Gd<godot::engine::Label>),
}

fn update_layout(
scene: &mut Scene,
crdt_state: &SceneCrdtState,
Expand All @@ -69,7 +79,7 @@ fn update_layout(

let ui_text_components = SceneCrdtStateProtoComponents::get_ui_text(crdt_state);

let mut taffy: taffy::Taffy<()> = taffy::Taffy::new();
let mut taffy: taffy::TaffyTree<ContextNode> = taffy::TaffyTree::new();
let root_node = taffy
.new_leaf(taffy::style::Style {
size: taffy::Size {
Expand Down Expand Up @@ -116,18 +126,24 @@ fn update_layout(
let child = taffy
.new_leaf(ui_node.ui_transform.taffy_style.clone())
.expect("failed to create node");
if let Some(text_size) = ui_node.text_size {
let size_child = taffy
.new_leaf(taffy::style::Style {
size: taffy::Size {
width: taffy::style::Dimension::Length(text_size.x),
height: taffy::style::Dimension::Length(text_size.y),
},
..Default::default()
})
.expect("failed to create node");

let _ = taffy.add_child(child, size_child);
if let Some(ui_text_control) = ui_node
.base_control
.try_get_node_as::<godot::engine::Label>("text")
{
let text_wrapping = if let Some(ui_text) = ui_text_components
.get(entity)
.and_then(|v| v.value.as_ref())
{
ui_text.text_wrap_compat() == TextWrap::TwWrap
} else {
false
};

let _ = taffy.set_node_context(
child,
Some(ContextNode::UiText(text_wrapping, ui_text_control)),
);
}

let _ = taffy.add_child(parent.0, child);
Expand All @@ -152,7 +168,76 @@ fn update_layout(
};

taffy
.compute_layout(root_node, size)
.compute_layout_with_measure(
root_node,
size,
|size, available, node_id, node_context, _style| match node_context {
Some(ContextNode::UiText(wrapping, text_node)) => {
let Some(font) = text_node.get_theme_font("font".into()) else {
return taffy::Size::ZERO;
};
let line_width = match size.width {
Some(value) => value,
None => match available.width {
taffy::AvailableSpace::Definite(v) => v,
taffy::AvailableSpace::MinContent => 1.0,
taffy::AvailableSpace::MaxContent => -1.0,
},
};

let font_size = text_node.get_theme_font_size("font_size".into());
let font_rect = if *wrapping {
font.get_multiline_string_size_ex(text_node.get_text())
.max_lines(-1)
.width(line_width)
.font_size(font_size)
.alignment(text_node.get_horizontal_alignment())
.justification_flags(JustificationFlag::JUSTIFICATION_NONE)
.brk_flags(
LineBreakFlag::BREAK_WORD_BOUND | LineBreakFlag::BREAK_MANDATORY,
)
.done()
} else {
font.get_string_size_ex(text_node.get_text())
.width(line_width)
.alignment(text_node.get_horizontal_alignment())
.justification_flags(JustificationFlag::JUSTIFICATION_NONE)
.font_size(font_size)
.done()
};

let width = match size.width {
Some(value) => value,
None => match available.width {
taffy::AvailableSpace::Definite(v) => v.clamp(0.0, font_rect.x),
taffy::AvailableSpace::MinContent => 1.0,
taffy::AvailableSpace::MaxContent => font_rect.x,
},
};

let height = match size.height {
Some(value) => value,
None => match available.height {
taffy::AvailableSpace::Definite(v) => v.clamp(0.0, font_rect.y),
taffy::AvailableSpace::MinContent => 1.0,
taffy::AvailableSpace::MaxContent => font_rect.y,
},
};

tracing::debug!(
"text node {:?}, wrapping {:?}, size: {:?}, font_rect {:?}, available {:?}",
node_id,
*wrapping,
size,
font_rect,
available
);

taffy::Size { width, height }
}
None => taffy::Size::ZERO,
},
)
.expect("failed to compute layout");

for (entity, key_node) in processed_nodes_sorted.iter() {
Expand Down Expand Up @@ -185,22 +270,13 @@ fn update_layout(
let is_hidden = taffy.style(*key_node).unwrap().display == taffy::style::Display::None;
control.set_visible(!is_hidden);

if let Some(ui_text) = ui_text_components
.get(entity)
.and_then(|v| v.value.as_ref())
{
if ui_text.text_wrap_compat() == TextWrap::TwWrap {
if let Some(mut ui_text_control) = ui_node
.base_control
.try_get_node_as::<godot::engine::Control>("text")
{
ui_text_control.set_size(godot::builtin::Vector2::new(
layout.size.width,
layout.size.height,
));
}
}
}
tracing::debug!(
"node {:?}, entity: {:?}, location: {:?}, size: {:?}",
key_node,
entity,
layout.location,
layout.size
);
}
}

Expand Down
1 change: 1 addition & 0 deletions lib/src/scene_runner/components/ui/ui_text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub fn update_ui_text(scene: &mut Scene, crdt_state: &mut SceneCrdtState) {
} else {
let mut node: Gd<DclUiText> = DclUiText::alloc_gd();
node.set_name("text".into());
node.set_anchors_preset(godot::engine::control::LayoutPreset::PRESET_FULL_RECT);

existing_ui_text
.base_control
Expand Down
14 changes: 12 additions & 2 deletions src/copy_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,23 @@ pub fn copy_library(debug_mode: bool, link_libs: bool) -> Result<(), anyhow::Err
let source_folder = format!("{RUST_LIB_PROJECT_FOLDER}{source_folder}");

let source_file =
adjust_canonicalization(fs::canonicalize(source_folder)?.join(file_name.clone()));
adjust_canonicalization(fs::canonicalize(source_folder.clone())?.join(file_name.clone()));

let lib_folder = format!("{GODOT_PROJECT_FOLDER}lib/");
let destination_file =
adjust_canonicalization(fs::canonicalize(lib_folder.as_str())?.join(file_name));
adjust_canonicalization(fs::canonicalize(lib_folder.as_str())?.join(file_name.clone()));
copy_if_modified(source_file, destination_file, link_libs)?;

if debug_mode && os == "windows" {
let source_file = adjust_canonicalization(
fs::canonicalize(source_folder)?.join("dclgodot.pdb".to_string()),
);
let destination_file = adjust_canonicalization(
fs::canonicalize(lib_folder.as_str())?.join("dclgodot.pdb".to_string()),
);
copy_if_modified(source_file, destination_file, link_libs)?;
}

copy_ffmpeg_libraries(lib_folder, link_libs)?;

Ok(())
Expand Down

0 comments on commit f4fa5d2

Please sign in to comment.