Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: raycast and uitext size computing #434

Merged
merged 2 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading