mod ffi {
pub use crate::ffi::{world_v0 as v0, world_v0::*};
pub use crate::ffi::{world_v1 as v1, world_v1::*};
pub use crate::ffi::{world_v2 as v2, world_v2::*};
pub use crate::ffi::{world_v3 as v3, world_v3::*};
pub use crate::ffi::{world_v4 as v4, world_v4::*};
}
pub use ffi::{
AudioClipInfo, BoneWeightFlags, CameraProjectionMode, CombineMode, ComponentMetaDataEntry,
ComponentType, ComponentsMetaDataEntry, CreateDataType, D6Axis, D6Drive, D6MotionType,
DynamicLockFlags, EntityTemplate, ForceMode, ForceType, JointLimitType, JointType,
MeshStyleFlags, MeshVisibilityFlags, ParameterMetaDataEntry, ParameterSemantic, RigidBodyMode,
SdfSkinInfo, Space, TriggerEvent, Value, ValueData, ValueType, WorldDataType,
{AnimationCurve, AnimationOptions, SpatialQueryOptions},
};
use crate::{Error, Quat, Vec2, Vec3, Vec4};
pub use ffi::MaterialDesc;
#[doc(hidden)]
pub use ffi::v3::API as FFI_API;
pub use ffi::v3::BoneTransform;
pub use ffi::v4::{
EntityBounds, EntityDebugOptions, EntityMeshStyleTint, EntityRenderEnable, EntityStateFlags,
EntityTransformConformal3, EntityValueType, EntityVelocity, MeasuredTextSize,
RaycastQueryOptions, RaycastQueryWithOptions,
};
mod mesh;
pub use mesh::*;
mod entity;
pub use entity::*;
mod value_converter;
pub use value_converter::*;
#[macro_use]
mod value_accessor;
pub use value_accessor::*;
mod entity_messenger;
pub use entity_messenger::*;
#[macro_use]
mod components;
pub use components::*;
mod data;
pub use data::*;
mod player;
pub use player::*;
mod reflection;
pub use reflection::*;
mod param_type;
pub use param_type::*;
mod query;
pub use query::*;
use crate::api::world::entity_messenger::AnimationReplyFn;
use std::{
cell::RefCell,
ops::{Deref, DerefMut},
};
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct LimitPair {
pub lower: f32,
pub upper: f32,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Pose {
pub pos: Vec3,
pub orientation: Quat,
}
#[derive(Copy, Clone, Debug)]
pub struct RaycastQuery {
pub ray: macaw::Ray3,
pub layer_mask: EntityLayerMask,
pub ignore_entity: Option<Entity>,
pub max_distance: f32,
pub options: RaycastQueryOptions,
pub spherecast_radius: f32,
}
impl Default for RaycastQuery {
fn default() -> Self {
Self {
ray: macaw::Ray3::ZERO,
layer_mask: EntityLayerMask::everything(),
ignore_entity: None,
max_distance: std::f32::INFINITY,
options: RaycastQueryOptions::empty(),
spherecast_radius: 0.0,
}
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct RaycastHit {
pub point: Vec3,
pub distance: f32,
pub normal: Vec3,
pub entity: Entity,
}
impl RaycastQuery {
fn as_ffi(&self) -> ffi::v4::SpherecastQuery {
ffi::v4::SpherecastQuery {
ray: ffi::Ray {
origin: self.ray.origin.into(),
dir: self.ray.dir.into(),
},
layer_mask: self.layer_mask.value(),
ignore_entity: self.ignore_entity.unwrap_or_else(Entity::invalid).as_ffi(),
max_distance: self.max_distance,
options: self.options,
spherecast_radius: self.spherecast_radius,
_pad: Default::default(),
}
}
}
impl RaycastHit {
fn from_ffi(hit: ffi::v3::RaycastHit) -> Self {
Self {
point: hit.point.into(),
distance: hit.distance,
normal: hit.normal.into(),
entity: Entity::from_ffi(hit.entity),
}
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct MeshStyleData {
pub diffuse_tint: Vec4,
pub flags: MeshStyleFlags,
}
impl MeshStyleData {
pub fn new(diffuse_tint: Vec4) -> Self {
Self {
diffuse_tint,
flags: MeshStyleFlags::default(),
}
}
}
impl Default for MeshStyleData {
fn default() -> Self {
Self {
diffuse_tint: Vec4::ONE,
flags: MeshStyleFlags::default(),
}
}
}
#[derive(Default, Debug, Clone, Copy)]
pub struct MeshStyleDataBuilder {
style: MeshStyleData,
}
impl MeshStyleDataBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_diffuse_tint(&mut self, tint: Vec4) -> &mut Self {
self.style.diffuse_tint = tint;
self
}
pub fn with_lighting(&mut self, e: bool) -> &mut Self {
self.style.flags.set(MeshStyleFlags::LIGHTING, e);
self
}
pub fn with_alpha_blending(&mut self, e: bool) -> &mut Self {
self.style.flags.set(MeshStyleFlags::ALPHA_BLENDING, e);
self
}
pub fn with_premultiplied_alpha(&mut self, e: bool) -> &mut Self {
self.style.flags.set(MeshStyleFlags::PREMULTIPLIED_ALPHA, e);
self
}
pub fn with_flat_shading(&mut self, e: bool) -> &mut Self {
self.style.flags.set(MeshStyleFlags::FLAT_SHADING, e);
self
}
pub fn with_billboard_rendering(&mut self, e: bool) -> &mut Self {
self.style.flags.set(MeshStyleFlags::BILLBOARD, e);
self
}
pub fn with_two_sided(&mut self, e: bool) -> &mut Self {
self.style.flags.set(MeshStyleFlags::TWO_SIDED, e);
self
}
pub fn build(&self) -> MeshStyleData {
self.style
}
}
#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
pub enum EntityValueError {
NanValue,
InfiniteParamValue,
InvalidComponentType,
InvalidComponentParameterId,
InvalidComponent,
InvalidEntityKey,
InvalidParentOfParent,
IncompatibleValueType,
IncompatibleValue,
Unsettable,
Ungettable,
NotAvailable,
Unknown(String),
}
impl std::fmt::Display for EntityValueError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EntityValueError::NanValue => {
write!(f, "The component parameter value is a NaN value.")
}
EntityValueError::InfiniteParamValue => {
write!(f, "The component parameter value is an infinite value.")
}
EntityValueError::InvalidComponentType => {
write!(f, "The supplied component type is invalid.")
}
EntityValueError::InvalidComponentParameterId => {
write!(f, "The supplied component parameter id is invalid.")
}
EntityValueError::InvalidComponent => write!(f, "The component did not exist."),
EntityValueError::InvalidEntityKey => write!(f, "Invalid supplied entity key."),
EntityValueError::InvalidParentOfParent => write!(
f,
" Invalid parent of parent (a parent was pointing to an invalid entity)."
),
EntityValueError::IncompatibleValueType => {
write!(f, "Trying to set an entity value that is incompatible with the component parameter value type.")
}
EntityValueError::IncompatibleValue => {
write!(f, "Trying to set an entity value that is incompatible with the component parameter value.")
}
EntityValueError::Unsettable => {
write!(f, "Could not set the entity component parameter value.")
}
EntityValueError::Ungettable => {
write!(f, "Could not get the entity component parameter value.")
}
EntityValueError::NotAvailable => {
write!(f, "The component was not available.")
}
EntityValueError::Unknown(e) => {
write!(f, "{e}")
}
}?;
Ok(())
}
}
impl std::error::Error for EntityValueError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
impl From<ffi::v4::EntityValueError> for EntityValueError {
fn from(error: ffi::v4::EntityValueError) -> Self {
match error {
ffi::v4::EntityValueError::NanValue => EntityValueError::NanValue,
ffi::v4::EntityValueError::InfiniteParamValue => EntityValueError::InfiniteParamValue,
ffi::v4::EntityValueError::InvalidComponentType => {
EntityValueError::InvalidComponentType
}
ffi::v4::EntityValueError::InvalidComponentParameterId => {
EntityValueError::InvalidComponentParameterId
}
ffi::v4::EntityValueError::InvalidComponent => EntityValueError::InvalidComponent,
ffi::v4::EntityValueError::InvalidEntityKey => EntityValueError::InvalidEntityKey,
ffi::v4::EntityValueError::InvalidParentOfParent => {
EntityValueError::InvalidParentOfParent
}
ffi::v4::EntityValueError::IncompatibleValueType => {
EntityValueError::IncompatibleValueType
}
ffi::v4::EntityValueError::IncompatibleValue => EntityValueError::IncompatibleValue,
ffi::v4::EntityValueError::Unsettable => EntityValueError::Unsettable,
ffi::v4::EntityValueError::Ungettable => EntityValueError::Ungettable,
ffi::v4::EntityValueError::NotAvailable => EntityValueError::NotAvailable,
e @ (ffi::v4::EntityValueError::Undefined | _) => {
EntityValueError::Unknown(format!("Unknown error code '{e:?}' returned."))
}
}
}
}
pub struct World {
entities_destroyed_this_frame: Vec<Entity>,
entities_destroyed_previous_frame: Vec<Entity>,
}
static mut WORLD: Option<RefCell<World>> = None;
impl World {
fn new() -> Self {
Self {
entities_destroyed_this_frame: vec![],
entities_destroyed_previous_frame: vec![],
}
}
pub fn instance_mut() -> impl DerefMut<Target = World> {
unsafe { WORLD.get_or_insert_with(|| RefCell::new(Self::new())) }.borrow_mut()
}
pub fn instance() -> impl Deref<Target = World> {
unsafe { WORLD.get_or_insert_with(|| RefCell::new(Self::new())) }.borrow()
}
fn next_frame(&mut self) {
std::mem::swap(
&mut self.entities_destroyed_previous_frame,
&mut self.entities_destroyed_this_frame,
);
self.entities_destroyed_this_frame.clear();
}
#[inline]
pub fn create_entity(name: &str, entity_template: EntityTemplate) -> Entity {
Entity::from_ffi(ffi::create_entity(name, entity_template))
}
#[inline]
pub fn add_component(entity: Entity, component_type: ComponentType) {
assert!(
entity.is_valid(),
"Trying to access {:?} on invalid entity",
component_type
);
ffi::add_component(entity.0, component_type);
}
#[inline]
pub fn remove_component(entity: Entity, component_type: ComponentType) {
assert!(
entity.is_valid(),
"Trying to access {:?} on invalid entity",
component_type
);
ffi::remove_component(entity.0, component_type);
}
#[inline]
pub fn has_component(entity: Entity, component_type: ComponentType) -> bool {
assert!(
entity.is_valid(),
"Trying to access {:?} on invalid entity",
component_type
);
ffi::has_component(entity.0, component_type) != 0
}
#[inline]
pub fn destroy_entity(entity: Entity) {
ffi::destroy_entity(entity.0);
}
#[inline]
pub fn clone_entity(name: &str, entity_src: Entity) -> Entity {
let mut dest = Entity::invalid().as_ffi();
ffi::clone_entities(name, std::slice::from_mut(&mut dest), &[entity_src.0]);
Entity::from_ffi(dest)
}
#[inline]
pub fn clone_entities(name: &str, entity_dst: &mut [Entity], entity_src: &[Entity]) {
let src = unsafe { &*(entity_src as *const [Entity] as *const [ffi::EntityHandle]) };
let dst = unsafe { &mut *(entity_dst as *mut [Entity] as *mut [ffi::EntityHandle]) };
ffi::clone_entities(name, dst, src);
}
#[inline]
pub fn copy_component(entity_dst: Entity, entity_src: Entity, component_type: ComponentType) {
ffi::copy_component(entity_dst.0, entity_src.0, component_type);
}
#[inline]
pub fn is_valid_entity(entity: Entity) -> bool {
ffi::is_valid_entity(entity.0) != 0
}
#[inline]
pub fn set_entity_value(
entity: Entity,
component_type: ComponentType,
param_id: u32,
value: &Value,
) {
ffi::set_entity_value_checked(entity.0, component_type, param_id, value);
}
#[inline]
pub fn try_set_entity_value(
entity: Entity,
component_type: ComponentType,
param_id: u32,
value: &Value,
) -> Result<(), EntityValueError> {
let mut error = ffi::v4::EntityValueError::Undefined;
let ffi_result =
ffi::try_set_entity_value(entity.0, component_type.into(), param_id, value, &mut error);
match ffi_result {
Ok(_) => Ok(()),
Err(_e) => Err(error.into()),
}
}
#[inline]
pub fn get_entity_value(entity: Entity, component_type: ComponentType, param_id: u32) -> Value {
let mut value = unsafe { std::mem::zeroed::<Value>() };
ffi::get_entity_value_checked(entity.0, component_type, param_id, &mut value);
value
}
#[inline]
pub fn try_get_entity_value(
entity: Entity,
component_type: ComponentType,
param_id: u32,
) -> Result<Value, EntityValueError> {
let mut error = ffi::v4::EntityValueError::Undefined;
let mut value = unsafe { std::mem::zeroed::<Value>() };
let ffi_result = ffi::try_get_entity_value(
entity.0,
component_type.into(),
param_id,
&mut value,
&mut error,
);
match ffi_result {
Ok(_) => Ok(value),
Err(_e) => Err(error.into()),
}
}
#[inline]
pub fn get_entity_values<T: Sized>(
entities: &[Entity],
value_type: ffi::v4::EntityValueType,
out_data: &mut Vec<T>,
) -> Result<(), Error> {
if std::mem::size_of::<T>() != value_type.size_of_element() as usize {
return Err(Error::InvalidArguments);
}
out_data.reserve(entities.len());
let (entities, out_data_slice) = unsafe {
out_data.set_len(entities.len());
(
&*(entities as *const [Entity] as *const [u64]),
std::slice::from_raw_parts_mut(
out_data.as_mut_ptr().cast::<u8>(),
out_data.len() * std::mem::size_of::<T>(),
),
)
};
ffi::v4::get_entity_values(entities, value_type, out_data_slice);
Ok(())
}
pub fn set_entity_values<T: Sized>(
entities: &[Entity],
value_type: ffi::v4::EntityValueType,
in_data: &[T],
) -> Result<(), Error> {
if std::mem::size_of::<T>() != value_type.size_of_element() as usize {
return Err(Error::InvalidArguments);
}
let (entities, in_data_slice) = unsafe {
(
&*(entities as *const [Entity] as *const [u64]),
std::slice::from_raw_parts(
in_data.as_ptr().cast::<u8>(),
in_data.len() * std::mem::size_of::<T>(),
),
)
};
ffi::v4::set_entity_values(entities, value_type, in_data_slice);
Ok(())
}
pub fn set_entity_local_transforms(
entities: &[Entity],
input: &[ffi::v4::EntityTransformConformal3],
) {
Self::set_entity_values(
entities,
ffi::v4::EntityValueType::EntityLocalTransformConformal3,
input,
)
.expect("Failed to execute set_entity_values. Invalid arguments.");
}
pub fn get_entity_local_transforms(
entities: &[Entity],
output: &mut Vec<ffi::v4::EntityTransformConformal3>,
) {
Self::get_entity_values(
entities,
ffi::v4::EntityValueType::EntityLocalTransformConformal3,
output,
)
.expect("Failed to execute get_entity_values. Invalid arguments.");
}
pub fn set_entity_world_transforms(
entities: &[Entity],
input: &[ffi::v4::EntityTransformConformal3],
) {
Self::set_entity_values(
entities,
ffi::v4::EntityValueType::EntityWorldTransformConformal3,
input,
)
.expect("Failed to execute set_entity_values. Invalid arguments.");
}
pub fn get_entity_world_transforms(
entities: &[Entity],
output: &mut Vec<ffi::v4::EntityTransformConformal3>,
) {
Self::get_entity_values(
entities,
ffi::v4::EntityValueType::EntityWorldTransformConformal3,
output,
)
.expect("Failed to execute get_entity_values. Invalid arguments.");
}
pub fn get_entities_state(entities: &[Entity], output: &mut Vec<ffi::v4::EntityStateFlags>) {
Self::get_entity_values(entities, ffi::v4::EntityValueType::EntityStateFlags, output)
.expect("Failed to execute get_entity_values. Invalid arguments.");
}
pub fn get_entity_local_bounds(entities: &[Entity], output: &mut Vec<ffi::v4::EntityBounds>) {
Self::get_entity_values(
entities,
ffi::v4::EntityValueType::EntityLocalBounds,
output,
)
.expect("Failed to execute get_entity_values. Invalid arguments.");
}
pub fn get_entity_physics_velocities(
entities: &[Entity],
output: &mut Vec<ffi::v4::EntityVelocity>,
) {
Self::get_entity_values(
entities,
ffi::v4::EntityValueType::EntityPhysicsVelocity,
output,
)
.expect("Failed to execute get_entity_values. Invalid arguments.");
}
pub fn set_entity_render_tints(entities: &[Entity], input: &[ffi::v4::EntityMeshStyleTint]) {
Self::set_entity_values(entities, ffi::v4::EntityValueType::EntityRenderTint, input)
.expect("Failed to execute set_entity_values. Invalid arguments.");
}
pub fn set_entity_render_enables(entities: &[Entity], input: &[ffi::v4::EntityRenderEnable]) {
Self::set_entity_values(
entities,
ffi::v4::EntityValueType::EntityRenderEnable,
input,
)
.expect("Failed to execute set_entity_values. Invalid arguments.");
}
pub fn create_body_immediate(entity: Entity) {
ffi::v3::create_body_immediate(entity.0);
}
#[inline]
pub fn get_mesh_properties(mesh_handle: DataHandle) -> MeshProperties {
ffi::get_mesh_properties(mesh_handle.as_ffi())
}
#[inline]
pub fn get_mesh_morph_target_names(mesh_handle: DataHandle) -> Vec<String> {
let count = ffi::get_mesh_morph_target_count(mesh_handle.as_ffi());
let mut retval = Vec::with_capacity(count as usize);
for i in 0..count {
let name_len = ffi::get_mesh_morph_target_name_len(mesh_handle.as_ffi(), i);
let mut v = vec![0; name_len as usize];
ffi::get_mesh_morph_target_name(mesh_handle.as_ffi(), i, &mut v);
retval.push(String::from_utf8(v).unwrap());
}
retval
}
pub fn is_valid_mesh(mesh_handle: DataHandle) -> bool {
ffi::is_valid_mesh(mesh_handle.0) != 0
}
pub fn raycast(raycast: &RaycastQuery) -> Option<RaycastHit> {
let hit = RaycastHit::from_ffi(ffi::v4::spherecast(&raycast.as_ffi()));
hit.entity.is_valid().then_some(hit)
}
pub fn raycast_batched(
raycasts: impl Iterator<Item = RaycastQuery>,
) -> Vec<Option<RaycastHit>> {
let raycasts_ffi = raycasts.map(|r| r.as_ffi()).collect::<Vec<_>>();
let mut hits_ffi = Vec::<ffi::v3::RaycastHit>::with_capacity(raycasts_ffi.len());
#[allow(clippy::uninit_vec)]
unsafe {
hits_ffi.set_len(raycasts_ffi.len());
}
ffi::v4::spherecast_batched(&raycasts_ffi, &mut hits_ffi);
hits_ffi
.into_iter()
.map(|h| {
let hit = RaycastHit::from_ffi(h);
hit.entity.is_valid().then_some(hit)
})
.collect::<Vec<_>>()
}
#[deprecated(note = "Use raycast instead")]
pub fn ray_cast(
ray_origin: Vec3,
ray_dir: Vec3,
min_t: f32,
max_t: f32,
any_hit: bool,
exclude_entity: Entity,
) -> Option<(Entity, f32)> {
let ray = ffi::Ray {
origin: ray_origin.into(),
dir: ray_dir.into(),
};
let mut t: f32 = -1.0;
let handle = ffi::ray_cast(
&ray,
min_t,
max_t,
u32::from(any_hit),
&mut t,
exclude_entity.as_ffi(),
);
Entity::try_from_ffi(handle).map(|entity| (entity, t))
}
#[inline]
pub fn send_messages(entity: Entity, messages: &[ffi::Message]) {
ffi::send_messages(
std::mem::size_of::<ffi::Message>() as u32,
&[ffi::MessageRangeAndReceiver {
entity: entity.as_ffi(),
start_index: 0u32,
length: messages.len() as u32,
}],
messages,
);
}
#[inline]
fn get_message_count(entity: Entity) -> u32 {
let entities = &[entity.as_ffi()];
let mut message_counts = [0u32];
let mut total = 0u32;
ffi::get_message_counts(
std::mem::size_of::<ffi::Message>() as u32,
entities,
&mut message_counts,
&mut total,
);
let count = *message_counts.first().unwrap();
assert_eq!(count, total);
count
}
pub fn retrieve_messages(entity: Entity) -> Vec<ffi::Message> {
let count = World::get_message_count(entity) as usize;
if count == 0 {
return vec![];
}
let mut out_messages = vec![ffi::Message::invalid(); count];
ffi::retrieve_messages(
std::mem::size_of::<ffi::Message>() as u32,
&[entity.as_ffi()],
&mut out_messages,
);
out_messages
}
#[inline]
pub fn get_components(entity: Entity, components: &mut [ComponentType]) -> u32 {
ffi::get_components(entity.0, components)
}
pub fn get_components_vec(entity: Entity) -> Vec<ComponentType> {
let mut c = [ComponentType::Invalid; 128];
let size = Self::get_components(entity, &mut c) as usize;
c[0..size].to_vec()
}
#[inline]
pub fn create_data(create_data_type: CreateDataType, data: &[u8]) -> DataHandle {
DataHandle::from_ffi(ffi::create_data(create_data_type, data))
}
#[inline]
pub fn retrieve_data(
data_handle: DataHandle,
retrieve_data_type: ffi::RetrieveDataType,
out_data: &mut [u8],
) -> u32 {
ffi::retrieve_data(data_handle.0, retrieve_data_type, out_data)
}
pub fn retrieve_data_vec(
data_handle: DataHandle,
retrieve_data_type: ffi::RetrieveDataType,
) -> Vec<u8> {
let len = Self::retrieve_data(data_handle, retrieve_data_type, &mut []);
let mut data: Vec<u8> = vec![0u8; len as usize];
let new_len = Self::retrieve_data(data_handle, retrieve_data_type, &mut data);
assert!(new_len == len);
data
}
#[inline]
pub fn destroy_data(data: DataHandle) {
ffi::destroy_data(data.0);
}
#[inline]
pub fn retain_data(data: DataHandle) {
ffi::retain_data(data.0);
}
#[inline]
pub fn is_valid_data(data_handle: DataHandle) -> bool {
ffi::is_valid_data(data_handle.0) != 0
}
#[inline]
pub fn set_data_debug_name(data_handle: DataHandle, name: &str) {
ffi::v4::set_data_debug_name(data_handle.0, name);
}
#[inline]
pub fn get_data_debug_name(data_handle: DataHandle) -> String {
ffi::v4::get_data_debug_name(data_handle.0)
}
#[inline]
pub fn set_entity_debug_options(entities: &[Entity], options: EntityDebugOptions) {
ffi::v4::set_entity_debug_options(
unsafe { &*(entities as *const [Entity] as *const [u64]) },
&options,
);
}
pub(crate) fn notify_destroyed(&mut self, entity: Entity) {
self.entities_destroyed_this_frame.push(entity);
}
pub(crate) fn entities_destroyed_this_and_last_frame(&self) -> impl Iterator<Item = &Entity> {
self.entities_destroyed_previous_frame
.iter()
.chain(self.entities_destroyed_this_frame.iter())
}
fn pre_update() {
puffin::profile_function!();
{
let mut instance = Self::instance_mut();
instance.next_frame();
}
EntityArena::global().destroy_pending_entities();
EntityMessenger::get().process_messages();
EntityMessageDispatcher::global().update();
}
fn post_update() {
puffin::profile_function!();
EntityMessenger::get().send_messages();
}
pub fn update<F: FnOnce()>(f: F) {
puffin::profile_function!();
Self::pre_update();
f();
Self::post_update();
}
pub fn measure_formatted_text(formatted_text: &FormattedText) -> MeasuredTextSize {
let mut text_size = MeasuredTextSize {
min_x: 0.0,
min_y: 0.0,
width: 0.0,
height: 0.0,
};
ffi::v4::measure_formatted_text(formatted_text.data.get_data_handle().0, &mut text_size);
text_size
}
}