mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
+2
-2
@@ -1,7 +1,7 @@
|
||||
# Examples
|
||||
|
||||
The engine contains examples for various aspects. Currently, there is not much, but I'm working on it.
|
||||
It is better to run examples with the `--release` flag, because Debug is too slow. Also Debug may suffer from
|
||||
It is better to run examples with the `--release` flag, because Debug is too slow. Also, Debug may suffer from
|
||||
a "glitch" when model loads faster than its textures, it is due asynchronous resource loading.
|
||||
|
||||
## Example 01 - Simple Scene
|
||||
@@ -53,7 +53,7 @@ Same as Example 03, but also has "save/load" functionality - F5 and F9 keys resp
|
||||
|
||||
## Example 07 - Sound
|
||||
|
||||
Same as Example 04, but also has foot step sounds and a reverb effect.
|
||||
Same as Example 04, but also has footstep sounds and a reverb effect.
|
||||
|
||||
## Example 08 - Level of detail
|
||||
|
||||
|
||||
+1
-1
@@ -206,7 +206,7 @@ impl AsyncLoaderContext {
|
||||
// Spawn separate thread which will create scene by loading various assets.
|
||||
std::thread::spawn(move || {
|
||||
// Scene will be loaded in separate thread.
|
||||
futures::executor::block_on(SceneLoader::load_with(resource_manager, context.clone()))
|
||||
futures::executor::block_on(SceneLoader::load_with(resource_manager, context))
|
||||
});
|
||||
|
||||
// Immediately return shared context.
|
||||
|
||||
@@ -112,7 +112,7 @@ impl Visit for Game {
|
||||
}
|
||||
|
||||
// For simplicity we'll be save (or load) game from hardcoded path.
|
||||
const SAVE_FILE: &'static str = "save.bin";
|
||||
const SAVE_FILE: &str = "save.bin";
|
||||
|
||||
fn save(game: &mut Game) {
|
||||
// To save a game state all we need to do is to create new instance of Visitor
|
||||
|
||||
+10
-10
@@ -501,7 +501,7 @@ impl Player {
|
||||
);
|
||||
scene.physics.add_collider(capsule, &body);
|
||||
|
||||
scene.physics_binder.bind(pivot, body.into());
|
||||
scene.physics_binder.bind(pivot, body);
|
||||
|
||||
context
|
||||
.lock()
|
||||
@@ -512,7 +512,7 @@ impl Player {
|
||||
LocomotionMachine::new(scene, model_handle, resource_manager).await;
|
||||
|
||||
Self {
|
||||
body: body.into(),
|
||||
body,
|
||||
pivot,
|
||||
model: model_handle,
|
||||
camera_pivot,
|
||||
@@ -533,13 +533,13 @@ impl Player {
|
||||
|
||||
let look_vector = pivot
|
||||
.look_vector()
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.unwrap_or(Vector3::z());
|
||||
.try_normalize(f32::EPSILON)
|
||||
.unwrap_or_else(Vector3::z);
|
||||
|
||||
let side_vector = pivot
|
||||
.side_vector()
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.unwrap_or(Vector3::x());
|
||||
.try_normalize(f32::EPSILON)
|
||||
.unwrap_or_else(Vector3::x);
|
||||
|
||||
let position = **pivot.local_transform().position();
|
||||
|
||||
@@ -560,9 +560,9 @@ impl Player {
|
||||
|
||||
let speed = 2.0 * dt;
|
||||
let velocity = velocity
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.and_then(|v| Some(v.scale(speed)))
|
||||
.unwrap_or(Vector3::default());
|
||||
.try_normalize(f32::EPSILON)
|
||||
.map(|v| v.scale(speed))
|
||||
.unwrap_or_default();
|
||||
let is_moving = velocity.norm_squared() > 0.0;
|
||||
|
||||
let body = scene.physics.bodies.get_mut(&self.body).unwrap();
|
||||
@@ -766,7 +766,7 @@ pub fn create_scene_async(resource_manager: ResourceManager) -> Arc<Mutex<SceneL
|
||||
|
||||
scene.graph.update_hierarchical_data();
|
||||
|
||||
// And create collision mesh so our character won't fall thru ground.
|
||||
// And create collision mesh so our character won't fall through ground.
|
||||
let collision_mesh_handle = scene.graph.find_by_name_from_root("CollisionShape");
|
||||
let collision_mesh = &mut scene.graph[collision_mesh_handle];
|
||||
|
||||
|
||||
+2
-2
@@ -166,11 +166,11 @@ fn main() {
|
||||
.add_source(
|
||||
SpatialSourceBuilder::new(
|
||||
GenericSourceBuilder::new()
|
||||
.with_buffer(foot_step.into())
|
||||
.with_buffer(foot_step)
|
||||
// rg3d-sound provides built-in way to create temporary sounds that will die immediately
|
||||
// after first play. This is very useful for foot step sounds.
|
||||
.with_play_once(true)
|
||||
// Every sound source must be explicity set to Playing status, otherwise it will be stopped.
|
||||
// Every sound source must be explicitly set to Playing status, otherwise it will be stopped.
|
||||
.with_status(Status::Playing)
|
||||
.build()
|
||||
.unwrap()
|
||||
|
||||
+5
-5
@@ -431,13 +431,13 @@ fn main() {
|
||||
if ui_message.direction() == MessageDirection::FromWidget =>
|
||||
{
|
||||
// Some of our scroll bars has changed its value. Check which one.
|
||||
if let &ScrollBarMessage::Value(value) = msg {
|
||||
if let ScrollBarMessage::Value(value) = msg {
|
||||
// Each message has source - a handle of UI element that created this message.
|
||||
// It is used to understand from which UI element message has come.
|
||||
if ui_message.destination() == interface.scale {
|
||||
model_scale = value;
|
||||
model_scale = *value;
|
||||
} else if ui_message.destination() == interface.yaw {
|
||||
model_angle = value;
|
||||
model_angle = *value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -464,9 +464,9 @@ fn main() {
|
||||
UiMessageData::DropdownList(msg) => {
|
||||
if let DropdownListMessage::SelectionChanged(idx) = msg {
|
||||
// Video mode has changed and we must change video mode to what user wants.
|
||||
if let &Some(idx) = idx {
|
||||
if let Some(idx) = idx {
|
||||
if ui_message.destination() == interface.resolutions {
|
||||
let video_mode = interface.video_modes.get(idx).unwrap();
|
||||
let video_mode = interface.video_modes.get(*idx).unwrap();
|
||||
engine.get_window().set_fullscreen(Some(
|
||||
Fullscreen::Exclusive(video_mode.clone()),
|
||||
));
|
||||
|
||||
@@ -7,12 +7,12 @@ Simple example showing how to use rg3d with WebAssembly.
|
||||
1. Make sure you have `wasm32-unknown-unknown` target installed in rustup (if not, do: `rustup target add wasm32-unknown-unknown`)
|
||||
2. Make sure you have `wasm-pack` installed (if not, do: `cargo install wasm-pack`)
|
||||
3. Make sure you have `basic-http-server` installed (if not do: `cargo install basic-http-server`)
|
||||
4. Finally execute this:
|
||||
4. Finally, execute this:
|
||||
|
||||
```shell
|
||||
wasm-pack build --target web
|
||||
basic-http-server
|
||||
```
|
||||
|
||||
If everything has succeded, open web browser at http://localhost:4000/ and you should a scene with 3d model which
|
||||
If everything has succeeded, open web browser at http://localhost:4000/ and you should a scene with 3d model which
|
||||
can be rotated using A D keys.
|
||||
@@ -29,7 +29,7 @@ pub fn save_load<T: Visit>(test_name: &str, data: &mut T, data_default: &mut T)
|
||||
file.write(visitor.save_text().as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
// Load the saevd data to `data_default`
|
||||
// Load the saved data to `data_default`
|
||||
{
|
||||
let mut visitor = block_on(Visitor::load_binary(&bin)).unwrap();
|
||||
// overwrite the default data with saved data
|
||||
|
||||
@@ -136,11 +136,11 @@ impl<K: Hash + Eq + Clone, V: Hash + Eq + Clone> BiDirHashMap<K, V> {
|
||||
}
|
||||
|
||||
pub fn value_of(&self, node: &K) -> Option<&V> {
|
||||
self.forward_map.get(&node)
|
||||
self.forward_map.get(node)
|
||||
}
|
||||
|
||||
pub fn key_of(&self, value: &V) -> Option<&K> {
|
||||
self.backward_map.get(&value)
|
||||
self.backward_map.get(value)
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) {
|
||||
|
||||
@@ -10,8 +10,8 @@ pub struct AxisAlignedBoundingBox {
|
||||
impl Default for AxisAlignedBoundingBox {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
min: Vector3::new(std::f32::MAX, std::f32::MAX, std::f32::MAX),
|
||||
max: Vector3::new(-std::f32::MAX, -std::f32::MAX, -std::f32::MAX),
|
||||
min: Vector3::new(f32::MAX, f32::MAX, f32::MAX),
|
||||
max: Vector3::new(-f32::MAX, -f32::MAX, -f32::MAX),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ pub fn get_polygon_normal(polygon: &[Vector3<f32>]) -> Result<Vector3<f32>, &'st
|
||||
}
|
||||
|
||||
normal
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.try_normalize(f32::EPSILON)
|
||||
.ok_or("Unable to get normal of degenerated polygon!")
|
||||
}
|
||||
|
||||
@@ -417,7 +417,7 @@ pub fn cubicf(p0: f32, p1: f32, t: f32, m0: f32, m1: f32) -> f32 {
|
||||
|
||||
pub fn get_farthest_point(points: &[Vector3<f32>], dir: Vector3<f32>) -> Vector3<f32> {
|
||||
let mut n_farthest = 0;
|
||||
let mut max_dot = -std::f32::MAX;
|
||||
let mut max_dot = -f32::MAX;
|
||||
for (i, point) in points.iter().enumerate() {
|
||||
let dot = dir.dot(point);
|
||||
if dot > max_dot {
|
||||
@@ -676,7 +676,7 @@ impl AsMut<[u32]> for TriangleDefinition {
|
||||
///
|
||||
/// O(n) complexity.
|
||||
pub fn get_closest_point<P: PositionProvider>(points: &[P], point: Vector3<f32>) -> Option<usize> {
|
||||
let mut closest_sqr_distance = std::f32::MAX;
|
||||
let mut closest_sqr_distance = f32::MAX;
|
||||
let mut closest_index = None;
|
||||
for (i, vertex) in points.iter().enumerate() {
|
||||
let sqr_distance = (vertex.position() - point).norm_squared();
|
||||
@@ -694,7 +694,7 @@ pub fn get_closest_point_triangles<P: PositionProvider>(
|
||||
triangle_indices: &[u32],
|
||||
point: Vector3<f32>,
|
||||
) -> Option<usize> {
|
||||
let mut closest_sqr_distance = std::f32::MAX;
|
||||
let mut closest_sqr_distance = f32::MAX;
|
||||
let mut closest_index = None;
|
||||
for triangle_index in triangle_indices {
|
||||
let triangle = triangles.get(*triangle_index as usize).unwrap();
|
||||
@@ -715,7 +715,7 @@ pub fn get_closest_point_triangle_set<P: PositionProvider>(
|
||||
triangles: &[TriangleDefinition],
|
||||
point: Vector3<f32>,
|
||||
) -> Option<usize> {
|
||||
let mut closest_sqr_distance = std::f32::MAX;
|
||||
let mut closest_sqr_distance = f32::MAX;
|
||||
let mut closest_index = None;
|
||||
for triangle in triangles {
|
||||
for point_index in triangle.0.iter() {
|
||||
@@ -776,7 +776,7 @@ impl SmoothAngle {
|
||||
}
|
||||
|
||||
pub fn at_target(&self) -> bool {
|
||||
(self.target - self.angle).abs() <= std::f32::EPSILON
|
||||
(self.target - self.angle).abs() <= f32::EPSILON
|
||||
}
|
||||
|
||||
pub fn distance(&self) -> f32 {
|
||||
|
||||
@@ -48,7 +48,7 @@ impl Plane {
|
||||
|
||||
#[inline]
|
||||
pub fn dot(&self, point: &Vector3<f32>) -> f32 {
|
||||
self.normal.dot(&point) + self.d
|
||||
self.normal.dot(point) + self.d
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -29,8 +29,8 @@ pub struct IntersectionResult {
|
||||
|
||||
impl IntersectionResult {
|
||||
pub fn from_slice(roots: &[f32]) -> Self {
|
||||
let mut min = std::f32::MAX;
|
||||
let mut max = -std::f32::MAX;
|
||||
let mut min = f32::MAX;
|
||||
let mut max = -f32::MAX;
|
||||
for n in roots {
|
||||
min = min.min(*n);
|
||||
max = max.max(*n);
|
||||
@@ -300,7 +300,7 @@ impl Ray {
|
||||
kind: CylinderKind,
|
||||
) -> Option<IntersectionResult> {
|
||||
let va = (*pb - *pa)
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.try_normalize(f32::EPSILON)
|
||||
.unwrap_or_else(|| Vector3::new(0.0, 1.0, 0.0));
|
||||
let vl = self.dir - va.scale(self.dir.dot(&va));
|
||||
let dp = self.origin - *pa;
|
||||
|
||||
@@ -105,11 +105,11 @@ pub fn triangulate(vertices: &[Vector3<f32>], out_triangles: &mut Vec<[usize; 3]
|
||||
for i in 0..4 {
|
||||
let v = vertices[i];
|
||||
let v0 = vertices[(i + 3) % 4];
|
||||
if let Some(left) = (v0 - v).try_normalize(std::f32::EPSILON) {
|
||||
if let Some(left) = (v0 - v).try_normalize(f32::EPSILON) {
|
||||
let v1 = vertices[(i + 2) % 4];
|
||||
if let Some(diag) = (v1 - v).try_normalize(std::f32::EPSILON) {
|
||||
if let Some(diag) = (v1 - v).try_normalize(f32::EPSILON) {
|
||||
let v2 = vertices[(i + 1) % 4];
|
||||
if let Some(right) = (v2 - v).try_normalize(std::f32::EPSILON) {
|
||||
if let Some(right) = (v2 - v).try_normalize(f32::EPSILON) {
|
||||
// Check for concave vertex
|
||||
let angle = left.dot(&diag).acos() + right.dot(&diag).acos();
|
||||
if angle > std::f32::consts::PI {
|
||||
@@ -125,7 +125,7 @@ pub fn triangulate(vertices: &[Vector3<f32>], out_triangles: &mut Vec<[usize; 3]
|
||||
} else {
|
||||
// Ear-clipping for arbitrary polygon (requires one additional memory allocation, so
|
||||
// relatively slow)
|
||||
if let Ok(normal) = math::get_polygon_normal(&vertices) {
|
||||
if let Ok(normal) = math::get_polygon_normal(vertices) {
|
||||
let plane_class = math::classify_plane(normal);
|
||||
let mut polygon = Polygon {
|
||||
vertices: vertices
|
||||
|
||||
@@ -35,7 +35,7 @@ impl Octree {
|
||||
|
||||
// Inflate initial bounds by very low value to fix floating-point calculation
|
||||
// issues when splitting and checking intersection later on.
|
||||
let inflation = 2.0 * std::f32::EPSILON;
|
||||
let inflation = 2.0 * f32::EPSILON;
|
||||
bounds.inflate(Vector3::new(inflation, inflation, inflation));
|
||||
|
||||
// Get initial list of indices.
|
||||
|
||||
@@ -138,7 +138,7 @@ impl Profiler {
|
||||
offset: usize,
|
||||
full_time: f64,
|
||||
) -> fmt::Result {
|
||||
let sample = self.samples.get(&scope_mark).unwrap();
|
||||
let sample = self.samples.get(scope_mark).unwrap();
|
||||
|
||||
if scope_mark == &ENTRY_SCOPE_MARK {
|
||||
writeln!(buffer, "=========================================================================================================")?;
|
||||
@@ -159,7 +159,7 @@ impl Profiler {
|
||||
|
||||
for child_scope in self
|
||||
.samples
|
||||
.get(&scope_mark)
|
||||
.get(scope_mark)
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.children
|
||||
@@ -185,7 +185,7 @@ impl Profiler {
|
||||
offset: usize,
|
||||
full_time: f64,
|
||||
) -> fmt::Result {
|
||||
let sample = self.samples.get(&scope_mark).unwrap();
|
||||
let sample = self.samples.get(scope_mark).unwrap();
|
||||
|
||||
if scope_mark == &ENTRY_SCOPE_MARK {
|
||||
writeln!(buffer,"=========================================================================================================")?;
|
||||
@@ -208,7 +208,7 @@ impl Profiler {
|
||||
let mut hot_time = 0.0;
|
||||
for child_scope in self
|
||||
.samples
|
||||
.get(&scope_mark)
|
||||
.get(scope_mark)
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.children
|
||||
|
||||
@@ -164,7 +164,7 @@ impl<T: ResourceData, E: ResourceLoadError> Resource<T, E> {
|
||||
|
||||
/// Returns exact amount of users of the resource.
|
||||
pub fn use_count(&self) -> usize {
|
||||
Arc::strong_count(&self.state.as_ref().unwrap())
|
||||
Arc::strong_count(self.state.as_ref().unwrap())
|
||||
}
|
||||
|
||||
/// Returns a pointer as numeric value which can be used as a hash.
|
||||
|
||||
@@ -48,7 +48,7 @@ This library wouldn't have been ever created without work of these people. Thank
|
||||
5. [IRCAM Head-related impulse response database](http://recherche.ircam.fr/equipes/salles/listen/)
|
||||
6. [Reverb](https://ccrma.stanford.edu/~jos/pasp/Freeverb.html)
|
||||
7. [Overlap-add convolution](https://en.wikipedia.org/wiki/Overlap%E2%80%93add_method) - not used anymore due to significant distortions at segment boundary when impulse response changes.
|
||||
8. [Overlap-save convolution](https://dsp-nbsphinx.readthedocs.io/en/nbsphinx-experiment/nonrecursive_filters/segmented_convolution.html) - works much better when impulse response changes, there are only phase shift issues which are more less acceptable.
|
||||
8. [Overlap-save convolution](https://dsp-nbsphinx.readthedocs.io/en/nbsphinx-experiment/nonrecursive_filters/segmented_convolution.html) - works much better when impulse response changes, there are only phase shift issues which are more or less acceptable.
|
||||
9. [OpenAL Specification](https://www.openal.org/documentation/openal-1.1-specification.pdf) - distance models and general design considerations.
|
||||
10. http://csoundjournal.com/issue9/newHRTFOpcodes.html - some ideas to remove clicks in hrtf renderer
|
||||
11. https://phaidra.kug.ac.at/open/o:11024
|
||||
|
||||
@@ -350,7 +350,7 @@ impl SoundContext {
|
||||
self.state.as_ref().unwrap().lock().unwrap()
|
||||
}
|
||||
|
||||
/// Creates deep copy intead of shallow which is done by clone().
|
||||
/// Creates deep copy instead of shallow which is done by clone().
|
||||
pub fn deep_clone(&self) -> SoundContext {
|
||||
SoundContext {
|
||||
state: Some(Arc::new(Mutex::new(self.state().clone()))),
|
||||
|
||||
@@ -43,7 +43,7 @@ fn check(error: OSStatus, msg: &str) -> Result<(), SoundError> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Callback function set on `AufioQueueNewOutput`
|
||||
/// Callback function set on `AudioQueueNewOutput`
|
||||
unsafe extern "C" fn audio_queue_callback(
|
||||
user_data: *mut c_void,
|
||||
queue: AudioQueueRef,
|
||||
|
||||
@@ -43,7 +43,7 @@ pub struct MixContext<'a> {
|
||||
}
|
||||
|
||||
fn sample_to_i16(sample: f32) -> i16 {
|
||||
const SCALE: f32 = std::i16::MAX as f32;
|
||||
const SCALE: f32 = i16::MAX as f32;
|
||||
let clamped = if sample > 1.0 {
|
||||
1.0
|
||||
} else if sample < -1.0 {
|
||||
|
||||
@@ -66,7 +66,7 @@ impl DerefMut for StubEffect {
|
||||
pub enum Effect {
|
||||
/// Stub effect that does nothing.
|
||||
Stub(StubEffect),
|
||||
/// Reberberation effect. See corresponding module for more info.
|
||||
/// Reverberation effect. See corresponding module for more info.
|
||||
Reverb(Reverb),
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//!
|
||||
//! HRTF stands for [Head-Related Transfer Function](https://en.wikipedia.org/wiki/Head-related_transfer_function)
|
||||
//! and can work only with spatial sounds. For each of such sound source after it was processed by HRTF you can
|
||||
//! defininitely tell from which locationsound came from. In other words HRTF improves perception of sound to
|
||||
//! definitely tell from which locationsound came from. In other words HRTF improves perception of sound to
|
||||
//! the level of real life.
|
||||
//!
|
||||
//! # HRIR Spheres
|
||||
|
||||
@@ -138,7 +138,7 @@ impl SpatialSource {
|
||||
|
||||
pub(in crate) fn get_panning(&self, listener: &Listener) -> f32 {
|
||||
(self.position - listener.position())
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.try_normalize(f32::EPSILON)
|
||||
// Fallback to look axis will give zero panning which will result in even
|
||||
// gain in each channels (as if there was no panning at all).
|
||||
.unwrap_or_else(|| listener.look_axis())
|
||||
@@ -149,7 +149,7 @@ impl SpatialSource {
|
||||
let to_self = self.position - listener.position();
|
||||
|
||||
(listener.basis() * to_self)
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.try_normalize(f32::EPSILON)
|
||||
// This is ok to fallback to (0, 0, 1) vector because it's given
|
||||
// in listener coordinate system.
|
||||
.unwrap_or_else(|| Vector3::new(0.0, 0.0, 1.0))
|
||||
@@ -187,7 +187,7 @@ impl Default for SpatialSource {
|
||||
generic: Default::default(),
|
||||
radius: 1.0,
|
||||
position: Vector3::new(0.0, 0.0, 0.0),
|
||||
max_distance: std::f32::MAX,
|
||||
max_distance: f32::MAX,
|
||||
rolloff_factor: 1.0,
|
||||
prev_left_samples: Default::default(),
|
||||
prev_right_samples: Default::default(),
|
||||
@@ -214,7 +214,7 @@ impl SpatialSourceBuilder {
|
||||
generic,
|
||||
radius: 1.0,
|
||||
position: Vector3::new(0.0, 0.0, 0.0),
|
||||
max_distance: std::f32::MAX,
|
||||
max_distance: f32::MAX,
|
||||
rolloff_factor: 1.0,
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ Retained mode, general purpose, graphics API agnostic user interface library. In
|
||||
- Powerful layout system
|
||||
- Fully customizable - you can construct visual trees of any complexity: for example a tree view item can have any sub-widgets as contents.
|
||||
- GAPI-agnostic - this crate does not know anything about the rendering backend: it can be OpenGL, DirectX, Vulkan, Metal, or even built-in OS drawing API.
|
||||
- OS-agnostic - similar look of all widgets across all operation systems and window managers.
|
||||
- OS-agnostic - similar look of all widgets across all operating systems and window managers.
|
||||
- Extendable - full support of user-defined widgets.
|
||||
|
||||
## Widgets
|
||||
@@ -50,13 +50,13 @@ Retained mode, general purpose, graphics API agnostic user interface library. In
|
||||
|
||||
## Limitations
|
||||
|
||||
- Since this library is OS-, GAPI-agnostic it cannot create native OS' windows and it cannot render anything on screen. Instead it uses an internal draw buffer which holds a list of commands, which has to be interpreted in your game/app. This is very a flexible way, but it has some limitations: multiwindow (native) configuration is hard to implement, you have to implement your own UI renderer what can be difficult if you not familiar with anything like this.
|
||||
- Since this library is OS-, GAPI-agnostic it cannot create native OS' windows, and it cannot render anything on screen. Instead, it uses an internal draw buffer which holds a list of commands, which has to be interpreted in your game/app. This is very a flexible way, but it has some limitations: multiwindow (native) configuration is hard to implement, you have to implement your own UI renderer what can be difficult if you not familiar with anything like this.
|
||||
- There is still no keyboard navigation, it is planned but not with high priority.
|
||||
- No support for right-to-left text (arabic, hebrew, etc.)
|
||||
|
||||
## Performance
|
||||
|
||||
- In general rg3d-ui is fast, however it can be slow if used incorrectly. Since this library uses a very complex layout system, it may work slow if there are lots of ui elements being moved (i.e. when scrolling). Hopefully it has built-in layout caching system and it relies on layout invalidation so it won't do layout calculations each frame - only if something significant changed (position, size, etc.).
|
||||
- In general rg3d-ui is fast, however it can be slow if used incorrectly. Since this library uses a very complex layout system, it may work slow if there are lots of ui elements being moved (i.e. when scrolling). Hopefully it has built-in layout caching system, and it relies on layout invalidation, so it won't do layout calculations each frame - only if something significant changed (position, size, etc.).
|
||||
- Batching of render commands can be difficult, because this library extensively uses clipping, and each clipping geometry has to be drawn into the stencil buffer as separate draw call. Rendering still has to be optimized, it is inefficient for now.
|
||||
|
||||
## Styling
|
||||
|
||||
@@ -22,7 +22,7 @@ impl<M: MessageData, C: Control<M, C>> Control<M, C> for Canvas<M, C> {
|
||||
) -> Vector2<f32> {
|
||||
scope_profile!();
|
||||
|
||||
let size_for_child = Vector2::new(std::f32::INFINITY, std::f32::INFINITY);
|
||||
let size_for_child = Vector2::new(f32::INFINITY, f32::INFINITY);
|
||||
|
||||
for child_handle in self.widget.children() {
|
||||
ui.measure_node(*child_handle, size_for_child);
|
||||
|
||||
@@ -490,7 +490,7 @@ impl<M: MessageData, C: Control<M, C>> CurveEditorBuilder<M, C> {
|
||||
.curve
|
||||
.keys()
|
||||
.iter()
|
||||
.map(|k| CurveKeyView::from(k))
|
||||
.map(CurveKeyView::from)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let editor = CurveEditor {
|
||||
|
||||
+4
-4
@@ -287,14 +287,14 @@ impl<M: MessageData, C: Control<M, C>> Control<M, C> for Tile<M, C> {
|
||||
ui.send_message(WidgetMessage::height(
|
||||
self.splitter,
|
||||
MessageDirection::ToWidget,
|
||||
std::f32::INFINITY,
|
||||
f32::INFINITY,
|
||||
));
|
||||
}
|
||||
TileContent::VerticalTiles { .. } => {
|
||||
ui.send_message(WidgetMessage::width(
|
||||
self.splitter,
|
||||
MessageDirection::ToWidget,
|
||||
std::f32::INFINITY,
|
||||
f32::INFINITY,
|
||||
));
|
||||
ui.send_message(WidgetMessage::height(
|
||||
self.splitter,
|
||||
@@ -904,14 +904,14 @@ impl<M: MessageData, C: Control<M, C>> TileBuilder<M, C> {
|
||||
if let TileContent::HorizontalTiles { .. } = self.content {
|
||||
DEFAULT_SPLITTER_SIZE
|
||||
} else {
|
||||
std::f32::INFINITY
|
||||
f32::INFINITY
|
||||
}
|
||||
})
|
||||
.with_height({
|
||||
if let TileContent::VerticalTiles { .. } = self.content {
|
||||
DEFAULT_SPLITTER_SIZE
|
||||
} else {
|
||||
std::f32::INFINITY
|
||||
f32::INFINITY
|
||||
}
|
||||
})
|
||||
.with_visibility(matches!(
|
||||
|
||||
+1
-1
@@ -318,7 +318,7 @@ pub struct DrawingContext {
|
||||
}
|
||||
|
||||
fn get_line_thickness_vector(a: Vector2<f32>, b: Vector2<f32>, thickness: f32) -> Vector2<f32> {
|
||||
if let Some(dir) = (b - a).try_normalize(std::f32::EPSILON) {
|
||||
if let Some(dir) = (b - a).try_normalize(f32::EPSILON) {
|
||||
Vector2::new(dir.y, -dir.x).scale(thickness * 0.5)
|
||||
} else {
|
||||
Vector2::default()
|
||||
|
||||
@@ -206,7 +206,7 @@ impl<M: MessageData, C: Control<M, C>> DropdownListBuilder<M, C> {
|
||||
Self: Sized,
|
||||
{
|
||||
let items_control = ListViewBuilder::new(
|
||||
WidgetBuilder::new().with_max_size(Vector2::new(std::f32::INFINITY, 200.0)),
|
||||
WidgetBuilder::new().with_max_size(Vector2::new(f32::INFINITY, 200.0)),
|
||||
)
|
||||
.with_items(self.items.clone())
|
||||
.build(ctx);
|
||||
|
||||
@@ -460,7 +460,7 @@ fn build_all<M: MessageData, C: Control<M, C>>(
|
||||
} else {
|
||||
root.as_path()
|
||||
};
|
||||
let item = build_tree_item(path, &Path::new(""), ctx);
|
||||
let item = build_tree_item(path, Path::new(""), ctx);
|
||||
root_items.push(item);
|
||||
item
|
||||
} else {
|
||||
|
||||
@@ -313,7 +313,7 @@ impl FormattedText {
|
||||
}
|
||||
}
|
||||
|
||||
// White-space characters are not part of word so pass them thru.
|
||||
// White-space characters are not part of word so pass them through.
|
||||
if is_white_space {
|
||||
current_line.end += 1;
|
||||
current_line.width += advance;
|
||||
|
||||
@@ -169,8 +169,8 @@ impl<M: MessageData, C: Control<M, C>> NumericUpDownBuilder<M, C> {
|
||||
widget_builder,
|
||||
value: 0.0,
|
||||
step: 0.1,
|
||||
min_value: -std::f32::MAX,
|
||||
max_value: std::f32::MAX,
|
||||
min_value: -f32::MAX,
|
||||
max_value: f32::MAX,
|
||||
precision: 3,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ impl<M: MessageData, C: Control<M, C>> Control<M, C> for ScrollBar<M, C> {
|
||||
ScrollBarMessage::Value(value) => {
|
||||
let old_value = self.value;
|
||||
let new_value = math::clampf(value, self.min, self.max);
|
||||
if (new_value - old_value).abs() > std::f32::EPSILON {
|
||||
if (new_value - old_value).abs() > f32::EPSILON {
|
||||
self.value = new_value;
|
||||
self.invalidate_arrange();
|
||||
|
||||
@@ -184,7 +184,7 @@ impl<M: MessageData, C: Control<M, C>> Control<M, C> for ScrollBar<M, C> {
|
||||
}
|
||||
let old_value = self.value;
|
||||
let new_value = math::clampf(self.value, self.min, self.max);
|
||||
if (new_value - old_value).abs() > std::f32::EPSILON {
|
||||
if (new_value - old_value).abs() > f32::EPSILON {
|
||||
ui.send_message(ScrollBarMessage::value(
|
||||
self.handle(),
|
||||
MessageDirection::ToWidget,
|
||||
@@ -209,7 +209,7 @@ impl<M: MessageData, C: Control<M, C>> Control<M, C> for ScrollBar<M, C> {
|
||||
}
|
||||
let old_value = self.value;
|
||||
let value = math::clampf(self.value, self.min, self.max);
|
||||
if (value - old_value).abs() > std::f32::EPSILON {
|
||||
if (value - old_value).abs() > f32::EPSILON {
|
||||
ui.send_message(ScrollBarMessage::value(
|
||||
self.handle(),
|
||||
MessageDirection::ToWidget,
|
||||
|
||||
@@ -30,12 +30,12 @@ impl<M: MessageData, C: Control<M, C>> Control<M, C> for ScrollPanel<M, C> {
|
||||
|
||||
let size_for_child = Vector2::new(
|
||||
if self.horizontal_scroll_allowed {
|
||||
std::f32::INFINITY
|
||||
f32::INFINITY
|
||||
} else {
|
||||
available_size.x
|
||||
},
|
||||
if self.vertical_scroll_allowed {
|
||||
std::f32::INFINITY
|
||||
f32::INFINITY
|
||||
} else {
|
||||
available_size.y
|
||||
},
|
||||
|
||||
@@ -100,7 +100,7 @@ impl<M: MessageData, C: Control<M, C>> Control<M, C> for ScrollViewer<M, C> {
|
||||
if let UINode::ScrollBar(v_scroll_bar) = ui.node(self.v_scroll_bar) {
|
||||
let old_value = v_scroll_bar.value();
|
||||
let new_value = old_value - amount * 17.0;
|
||||
if (old_value - new_value).abs() > std::f32::EPSILON {
|
||||
if (old_value - new_value).abs() > f32::EPSILON {
|
||||
message.set_handled(true);
|
||||
}
|
||||
ui.send_message(ScrollBarMessage::value(
|
||||
@@ -162,7 +162,7 @@ impl<M: MessageData, C: Control<M, C>> Control<M, C> for ScrollViewer<M, C> {
|
||||
if let UINode::ScrollBar(scroll_bar) = ui.node(self.v_scroll_bar) {
|
||||
let visibility = (scroll_bar.max_value() - scroll_bar.min_value())
|
||||
.abs()
|
||||
>= std::f32::EPSILON;
|
||||
>= f32::EPSILON;
|
||||
ui.send_message(WidgetMessage::visibility(
|
||||
self.v_scroll_bar,
|
||||
MessageDirection::ToWidget,
|
||||
@@ -175,7 +175,7 @@ impl<M: MessageData, C: Control<M, C>> Control<M, C> for ScrollViewer<M, C> {
|
||||
if let UINode::ScrollBar(scroll_bar) = ui.node(self.h_scroll_bar) {
|
||||
let visibility = (scroll_bar.max_value() - scroll_bar.min_value())
|
||||
.abs()
|
||||
>= std::f32::EPSILON;
|
||||
>= f32::EPSILON;
|
||||
ui.send_message(WidgetMessage::visibility(
|
||||
self.h_scroll_bar,
|
||||
MessageDirection::ToWidget,
|
||||
|
||||
@@ -44,7 +44,7 @@ impl<M: MessageData, C: Control<M, C>> Control<M, C> for StackPanel<M, C> {
|
||||
) -> Vector2<f32> {
|
||||
scope_profile!();
|
||||
|
||||
let mut child_constraint = Vector2::new(std::f32::INFINITY, std::f32::INFINITY);
|
||||
let mut child_constraint = Vector2::new(f32::INFINITY, f32::INFINITY);
|
||||
|
||||
match self.orientation {
|
||||
Orientation::Vertical => {
|
||||
|
||||
@@ -26,7 +26,7 @@ pub enum Primitive {
|
||||
}
|
||||
|
||||
fn line_thickness_vector(a: Vector2<f32>, b: Vector2<f32>, thickness: f32) -> Vector2<f32> {
|
||||
if let Some(dir) = (b - a).try_normalize(std::f32::EPSILON) {
|
||||
if let Some(dir) = (b - a).try_normalize(f32::EPSILON) {
|
||||
Vector2::new(dir.y, -dir.x).scale(thickness * 0.5)
|
||||
} else {
|
||||
Vector2::default()
|
||||
@@ -84,8 +84,8 @@ impl<M: MessageData, C: Control<M, C>> Control<M, C> for VectorImage<M, C> {
|
||||
if self.primitives.is_empty() {
|
||||
Default::default()
|
||||
} else {
|
||||
let mut max = Vector2::new(-std::f32::MAX, -std::f32::MAX);
|
||||
let mut min = Vector2::new(std::f32::MAX, std::f32::MAX);
|
||||
let mut max = Vector2::new(-f32::MAX, -f32::MAX);
|
||||
let mut min = Vector2::new(f32::MAX, f32::MAX);
|
||||
|
||||
for primitive in self.primitives.iter() {
|
||||
let (pmin, pmax) = primitive.bounds();
|
||||
|
||||
@@ -732,8 +732,8 @@ impl<M: MessageData, C: Control<M, C>> WidgetBuilder<M, C> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
name: Default::default(),
|
||||
width: std::f32::NAN,
|
||||
height: std::f32::NAN,
|
||||
width: f32::NAN,
|
||||
height: f32::NAN,
|
||||
vertical_alignment: VerticalAlignment::Stretch,
|
||||
horizontal_alignment: HorizontalAlignment::Stretch,
|
||||
max_size: None,
|
||||
@@ -935,7 +935,7 @@ impl<M: MessageData, C: Control<M, C>> WidgetBuilder<M, C> {
|
||||
min_size: self.min_size.unwrap_or_default(),
|
||||
max_size: self
|
||||
.max_size
|
||||
.unwrap_or_else(|| Vector2::new(std::f32::INFINITY, std::f32::INFINITY)),
|
||||
.unwrap_or_else(|| Vector2::new(f32::INFINITY, f32::INFINITY)),
|
||||
background: self.background.unwrap_or_else(|| BRUSH_PRIMARY.clone()),
|
||||
foreground: self.foreground.unwrap_or_else(|| BRUSH_FOREGROUND.clone()),
|
||||
row: self.row,
|
||||
|
||||
@@ -505,7 +505,7 @@ impl Transition {
|
||||
}
|
||||
|
||||
pub fn is_done(&self) -> bool {
|
||||
(self.transition_time - self.elapsed_time).abs() <= std::f32::EPSILON
|
||||
(self.transition_time - self.elapsed_time).abs() <= f32::EPSILON
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,7 +532,7 @@ impl Default for LimitedEventQueue {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
queue: Default::default(),
|
||||
limit: std::u32::MAX,
|
||||
limit: u32::MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,7 +417,7 @@ impl AnimationPose {
|
||||
pub fn apply(&self, graph: &mut Graph) {
|
||||
for (node, local_pose) in self.local_poses.iter() {
|
||||
if node.is_none() {
|
||||
Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargetting failed!".to_owned());
|
||||
Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargeting failed!".to_owned());
|
||||
} else {
|
||||
graph[*node]
|
||||
.local_transform_mut()
|
||||
@@ -436,7 +436,7 @@ impl AnimationPose {
|
||||
{
|
||||
for (node, local_pose) in self.local_poses.iter() {
|
||||
if node.is_none() {
|
||||
Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargetting failed!".to_owned());
|
||||
Log::writeln(MessageKind::Error, "Invalid node handle found for animation pose, most likely it means that animation retargeting failed!".to_owned());
|
||||
} else {
|
||||
callback(&mut graph[*node], *node, local_pose);
|
||||
}
|
||||
@@ -539,7 +539,7 @@ impl Animation {
|
||||
}
|
||||
|
||||
pub fn has_ended(&self) -> bool {
|
||||
!self.looped && (self.time_position - self.length).abs() <= std::f32::EPSILON
|
||||
!self.looped && (self.time_position - self.length).abs() <= f32::EPSILON
|
||||
}
|
||||
|
||||
pub fn set_enabled(&mut self, enabled: bool) -> &mut Self {
|
||||
@@ -656,14 +656,14 @@ impl Animation {
|
||||
|
||||
// Find corresponding track in resource using names of nodes, not
|
||||
// original handles of instantiated nodes. We can't use original
|
||||
// handles here because animation can be targetted to a node that
|
||||
// handles here because animation can be targeted to a node that
|
||||
// wasn't instantiated from animation resource. It can be instantiated
|
||||
// from some other resource. For example you have a character with
|
||||
// multiple animations. Character "lives" in its own file without animations
|
||||
// but with skin. Each animation "lives" in its own file too, then
|
||||
// you did animation retargetting from animation resource to your character
|
||||
// you did animation retargeting from animation resource to your character
|
||||
// instantiated model, which is essentially copies key frames to new
|
||||
// animation targetted to character instance.
|
||||
// animation targeted to character instance.
|
||||
let mut found = false;
|
||||
for ref_track in ref_animation.get_tracks().iter() {
|
||||
if track_node.name()
|
||||
|
||||
+1
-1
@@ -225,7 +225,7 @@ impl<M: MessageData, C: Control<M, C>> Engine<M, C> {
|
||||
{
|
||||
self.renderer.render_and_swap_buffers(
|
||||
&self.scenes,
|
||||
&self.user_interface.get_drawing_context(),
|
||||
self.user_interface.get_drawing_context(),
|
||||
&self.scenes2d,
|
||||
&self.context,
|
||||
)
|
||||
|
||||
@@ -43,7 +43,7 @@ impl DebugShader {
|
||||
let fragment_source = include_str!("shaders/debug_fs.glsl");
|
||||
let vertex_source = include_str!("shaders/debug_vs.glsl");
|
||||
let program =
|
||||
GpuProgram::from_source(state, "DebugShader", &vertex_source, &fragment_source)?;
|
||||
GpuProgram::from_source(state, "DebugShader", vertex_source, fragment_source)?;
|
||||
Ok(Self {
|
||||
wvp_matrix: program.uniform_location(state, "worldViewProjection")?,
|
||||
program,
|
||||
|
||||
@@ -605,7 +605,7 @@ impl DeferredLightRenderer {
|
||||
let raw_radius = match light {
|
||||
Light::Spot(spot_light) => spot_light.distance(),
|
||||
Light::Point(point_light) => point_light.radius(),
|
||||
Light::Directional(_) => std::f32::MAX,
|
||||
Light::Directional(_) => f32::MAX,
|
||||
};
|
||||
|
||||
let light_position = light.global_position();
|
||||
@@ -616,7 +616,7 @@ impl DeferredLightRenderer {
|
||||
let light_radius_vec = Vector3::new(light_r_inflate, light_r_inflate, light_r_inflate);
|
||||
let emit_direction = light
|
||||
.up_vector()
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.try_normalize(f32::EPSILON)
|
||||
.unwrap_or_else(Vector3::z);
|
||||
|
||||
if !frustum.is_intersects_sphere(light_position, light_radius) {
|
||||
@@ -659,7 +659,7 @@ impl DeferredLightRenderer {
|
||||
|
||||
let light_up_vec = light
|
||||
.look_vector()
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.try_normalize(f32::EPSILON)
|
||||
.unwrap_or_else(Vector3::y);
|
||||
|
||||
let light_view_matrix = Matrix4::look_at_rh(
|
||||
|
||||
@@ -369,7 +369,7 @@ impl PipelineState {
|
||||
}
|
||||
|
||||
pub fn set_clear_depth(&mut self, depth: f32) {
|
||||
if (self.clear_depth - depth).abs() > std::f32::EPSILON {
|
||||
if (self.clear_depth - depth).abs() > f32::EPSILON {
|
||||
self.clear_depth = depth;
|
||||
|
||||
unsafe {
|
||||
|
||||
+2
-2
@@ -828,7 +828,7 @@ impl Renderer {
|
||||
frame_buffer,
|
||||
frame_width: ui.screen_size().x,
|
||||
frame_height: ui.screen_size().y,
|
||||
drawing_context: &ui.draw(),
|
||||
drawing_context: ui.draw(),
|
||||
white_dummy: self.white_dummy.clone(),
|
||||
texture_cache: &mut self.texture_cache,
|
||||
})?;
|
||||
@@ -960,7 +960,7 @@ impl Renderer {
|
||||
rt.key(),
|
||||
CacheEntry {
|
||||
value: gbuffer.frame_texture(),
|
||||
time_to_live: std::f32::INFINITY,
|
||||
time_to_live: f32::INFINITY,
|
||||
value_hash: 0, // TODO
|
||||
},
|
||||
);
|
||||
|
||||
@@ -130,7 +130,7 @@ impl ScreenSpaceAmbientOcclusionRenderer {
|
||||
rng.gen_range(0.0..1.0),
|
||||
)
|
||||
// Make sphere
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.try_normalize(f32::EPSILON)
|
||||
.unwrap()
|
||||
// Use non-uniform distribution to shuffle points inside hemisphere.
|
||||
.scale(scale);
|
||||
|
||||
@@ -50,7 +50,7 @@ impl std::fmt::Display for FbxError {
|
||||
Self::InvalidPoolHandle => write!(f, "Invalid pool handle."),
|
||||
Self::UnexpectedType => write!(
|
||||
f,
|
||||
"Unexpected type. This means that invalid cast has occured in fbx component."
|
||||
"Unexpected type. This means that invalid cast has occurred in fbx component."
|
||||
),
|
||||
Self::IndexOutOfBounds => write!(f, "Index out of bounds."),
|
||||
Self::UnableToFindBone => write!(f, "Unable to find bone."),
|
||||
|
||||
@@ -122,7 +122,7 @@ fn prepare_next_face(
|
||||
for i in 0..vertex_per_face {
|
||||
temp_vertices.push(vertices[fix_index(indices[i])]);
|
||||
}
|
||||
triangulate(&temp_vertices, out_face_triangles);
|
||||
triangulate(temp_vertices, out_face_triangles);
|
||||
for triangle in out_face_triangles.iter() {
|
||||
out_triangles.push([
|
||||
fix_index(indices[triangle[0]]),
|
||||
@@ -524,7 +524,7 @@ async fn convert_model(
|
||||
|
||||
track.add_key_frame(KeyFrame::new(time, translation, scale, rotation));
|
||||
|
||||
let mut next_time = std::f32::MAX;
|
||||
let mut next_time = f32::MAX;
|
||||
for node in [lcl_translation, lcl_rotation, lcl_scale].iter().flatten() {
|
||||
for &curve_handle in node.curves.iter() {
|
||||
let curve_component = fbx_scene.get(curve_handle);
|
||||
@@ -541,7 +541,7 @@ async fn convert_model(
|
||||
}
|
||||
}
|
||||
|
||||
if next_time >= std::f32::MAX {
|
||||
if next_time >= f32::MAX {
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ impl Model {
|
||||
/// Tries to retarget animations from given model resource to a node hierarchy starting
|
||||
/// from `root` on a given scene.
|
||||
///
|
||||
/// Animation retargetting allows you to "transfer" animation from a model to a model
|
||||
/// Animation retargeting allows you to "transfer" animation from a model to a model
|
||||
/// instance on a scene. Imagine you have a character that should have multiple animations
|
||||
/// like idle, run, shoot, walk, etc. and you want to store each animation in a separate
|
||||
/// file. Then when you creating a character on a level you want to have all possible
|
||||
|
||||
+1
-1
@@ -508,7 +508,7 @@ impl SkyBox {
|
||||
}
|
||||
|
||||
/// Creates a cubemap using provided faces. If some face has not been
|
||||
/// provided correcponding side will be black.
|
||||
/// provided corresponding side will be black.
|
||||
/// It will fail if provided face's kind is not TextureKind::Rectangle
|
||||
pub fn create_cubemap(&mut self) -> Result<(), SkyBoxError> {
|
||||
let (kind, pixel_kind, bytes_per_face) =
|
||||
|
||||
+1
-1
@@ -1057,7 +1057,7 @@ impl Graph {
|
||||
/// Returns global scale matrix of a node.
|
||||
pub fn global_scale_matrix(&self, node: Handle<Node>) -> Matrix4<f32> {
|
||||
let node = &self[node];
|
||||
let local_scale_matrix = Matrix4::new_nonuniform_scaling(&node.local_transform().scale());
|
||||
let local_scale_matrix = Matrix4::new_nonuniform_scaling(node.local_transform().scale());
|
||||
if node.parent().is_some() {
|
||||
self.global_scale_matrix(node.parent()) * local_scale_matrix
|
||||
} else {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! Light sources arte basic building blocks of many scenes in games, it improves
|
||||
//! perception of scene and makes it look natural. rg3d engine supports three kinds
|
||||
//! of ligth sources:
|
||||
//! of light sources:
|
||||
//!
|
||||
//! 1) Directional - similar to sun in real life, its rays are parallel.
|
||||
//! 2) Spot - similar to flash light, it has cone light volume and circle spot.
|
||||
|
||||
@@ -180,7 +180,7 @@ impl SurfaceData {
|
||||
|
||||
// Gram-Schmidt orthogonalize
|
||||
let tangent = (t1 - normal.scale(normal.dot(&t1)))
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.try_normalize(f32::EPSILON)
|
||||
.unwrap_or_else(|| Vector3::new(0.0, 1.0, 0.0));
|
||||
let handedness = normal.cross(&t1).dot(&t2).signum();
|
||||
view.write_4_f32(
|
||||
@@ -907,7 +907,7 @@ impl VertexWeightSet {
|
||||
/// equal to 1.0, we must fix that to prevent weirdly looking results.
|
||||
pub fn normalize(&mut self) {
|
||||
let len = self.iter().fold(0.0, |qs, w| qs + w.value * w.value).sqrt();
|
||||
if len >= std::f32::EPSILON {
|
||||
if len >= f32::EPSILON {
|
||||
let k = 1.0 / len;
|
||||
for w in self.iter_mut() {
|
||||
w.value *= k;
|
||||
|
||||
+4
-4
@@ -690,7 +690,7 @@ impl SceneDrawingContext {
|
||||
let length = axis.norm();
|
||||
|
||||
let z_axis = axis
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.try_normalize(f32::EPSILON)
|
||||
.unwrap_or_else(Vector3::z);
|
||||
|
||||
let y_axis = z_axis
|
||||
@@ -701,12 +701,12 @@ impl SceneDrawingContext {
|
||||
Vector3::y()
|
||||
}),
|
||||
)
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.try_normalize(f32::EPSILON)
|
||||
.unwrap_or_else(Vector3::y);
|
||||
|
||||
let x_axis = z_axis
|
||||
.cross(&y_axis)
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.try_normalize(f32::EPSILON)
|
||||
.unwrap_or_else(Vector3::x); // CHECK
|
||||
|
||||
let shaft_point = |u: f32, v: f32| -> Vector3<f32> {
|
||||
@@ -1610,7 +1610,7 @@ impl VisibilityCache {
|
||||
let radius = match light {
|
||||
Light::Spot(spot_light) => spot_light.distance(),
|
||||
Light::Point(point_light) => point_light.radius(),
|
||||
Light::Directional(_) => std::f32::MAX,
|
||||
Light::Directional(_) => f32::MAX,
|
||||
};
|
||||
|
||||
// Rough intersection check should cover most of the use cases,
|
||||
|
||||
@@ -148,7 +148,7 @@ pub struct ParticleSystem {
|
||||
color_over_lifetime: Option<ColorGradient>,
|
||||
#[visit(optional)] // Backward compatibility.
|
||||
soft_boundary_sharpness_factor: f32,
|
||||
#[visit(optional)] // Backward copmatibility.
|
||||
#[visit(optional)] // Backward compatibility.
|
||||
enabled: bool,
|
||||
}
|
||||
|
||||
|
||||
@@ -476,13 +476,13 @@ impl Physics {
|
||||
bodies: self
|
||||
.bodies
|
||||
.iter()
|
||||
.map(|b| RigidBodyDesc::from_body(b, &self.colliders.handle_map()))
|
||||
.map(|b| RigidBodyDesc::from_body(b, self.colliders.handle_map()))
|
||||
.collect::<Vec<_>>(),
|
||||
|
||||
colliders: self
|
||||
.colliders
|
||||
.iter()
|
||||
.map(|c| ColliderDesc::from_collider(c, &self.bodies.handle_map()))
|
||||
.map(|c| ColliderDesc::from_collider(c, self.bodies.handle_map()))
|
||||
.collect::<Vec<_>>(),
|
||||
|
||||
gravity: self.gravity,
|
||||
@@ -490,7 +490,7 @@ impl Physics {
|
||||
joints: self
|
||||
.joints
|
||||
.iter()
|
||||
.map(|j| JointDesc::from_joint(j, &self.bodies.handle_map()))
|
||||
.map(|j| JointDesc::from_joint(j, self.bodies.handle_map()))
|
||||
.collect::<Vec<_>>(),
|
||||
|
||||
body_handle_map,
|
||||
@@ -728,7 +728,7 @@ impl Physics {
|
||||
Point3::from(opts.ray.origin),
|
||||
opts.ray
|
||||
.dir
|
||||
.try_normalize(std::f32::EPSILON)
|
||||
.try_normalize(f32::EPSILON)
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
query.intersections_with_ray(
|
||||
@@ -921,7 +921,7 @@ impl Physics {
|
||||
for (resource_handle, body) in resource_physics.bodies.set.iter() {
|
||||
let desc = RigidBodyDesc::<ColliderHandle>::from_body(
|
||||
body,
|
||||
&resource_physics.colliders.handle_map(),
|
||||
resource_physics.colliders.handle_map(),
|
||||
);
|
||||
let new_handle = self.add_body(desc.convert_to_body());
|
||||
|
||||
@@ -945,7 +945,7 @@ impl Physics {
|
||||
|
||||
// Instantiate colliders.
|
||||
for (resource_handle, collider) in resource_physics.colliders.set.iter() {
|
||||
let desc = ColliderDesc::from_collider(collider, &resource_physics.bodies.handle_map());
|
||||
let desc = ColliderDesc::from_collider(collider, resource_physics.bodies.handle_map());
|
||||
// Remap handle from resource to one that was created above.
|
||||
let remapped_parent = *link.bodies.get(&desc.parent).unwrap();
|
||||
match desc.shape {
|
||||
@@ -1044,7 +1044,7 @@ impl Physics {
|
||||
for (resource_handle, joint) in resource_physics.joints.set.iter() {
|
||||
let desc = JointDesc::<RigidBodyHandle>::from_joint(
|
||||
joint,
|
||||
&resource_physics.bodies.handle_map(),
|
||||
resource_physics.bodies.handle_map(),
|
||||
);
|
||||
let new_body1_handle = link
|
||||
.bodies
|
||||
|
||||
@@ -32,7 +32,7 @@ use std::{
|
||||
};
|
||||
|
||||
/// Layers is a set of textures for rendering + mask texture to exclude some pixels from
|
||||
/// rendering. Terrain can have as many layers as you want, but each layer slightly decreses
|
||||
/// rendering. Terrain can have as many layers as you want, but each layer slightly decreases
|
||||
/// performance, so keep amount of layers on reasonable level (1 - 5 should be enough for most
|
||||
/// cases).
|
||||
#[derive(Default, Debug, Clone, Visit)]
|
||||
@@ -637,7 +637,7 @@ pub enum BrushShape {
|
||||
/// Radius of the circle.
|
||||
radius: f32,
|
||||
},
|
||||
/// Rectange with given width and height.
|
||||
/// Rectangle with given width and height.
|
||||
Rectangle {
|
||||
/// Width of the rectangle.
|
||||
width: f32,
|
||||
|
||||
+7
-7
@@ -36,8 +36,8 @@ impl Default for PathVertex {
|
||||
Self {
|
||||
position: Default::default(),
|
||||
parent: None,
|
||||
g_score: std::f32::MAX,
|
||||
f_score: std::f32::MAX,
|
||||
g_score: f32::MAX,
|
||||
f_score: f32::MAX,
|
||||
state: PathVertexState::NonVisited,
|
||||
neighbours: Default::default(),
|
||||
}
|
||||
@@ -62,8 +62,8 @@ impl PathVertex {
|
||||
Self {
|
||||
position,
|
||||
parent: None,
|
||||
g_score: std::f32::MAX,
|
||||
f_score: std::f32::MAX,
|
||||
g_score: f32::MAX,
|
||||
f_score: f32::MAX,
|
||||
state: PathVertexState::NonVisited,
|
||||
neighbours: Default::default(),
|
||||
}
|
||||
@@ -75,8 +75,8 @@ impl PathVertex {
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.g_score = std::f32::MAX;
|
||||
self.f_score = std::f32::MAX;
|
||||
self.g_score = f32::MAX;
|
||||
self.f_score = f32::MAX;
|
||||
self.state = PathVertexState::NonVisited;
|
||||
self.parent = None;
|
||||
}
|
||||
@@ -236,7 +236,7 @@ impl PathFinder {
|
||||
let mut open_set_size = 1;
|
||||
while open_set_size > 0 {
|
||||
let mut current_index = 0;
|
||||
let mut lowest_f_score = std::f32::MAX;
|
||||
let mut lowest_f_score = f32::MAX;
|
||||
for (i, vertex) in self.vertices.iter().enumerate() {
|
||||
if vertex.state == PathVertexState::Open && vertex.f_score < lowest_f_score {
|
||||
current_index = i;
|
||||
|
||||
@@ -423,7 +423,7 @@ impl Lightmap {
|
||||
return Err(LightmapGenerationError::Cancelled);
|
||||
}
|
||||
|
||||
let lightmap = generate_lightmap(&instance, &instances, &lights, texels_per_unit);
|
||||
let lightmap = generate_lightmap(instance, &instances, &lights, texels_per_unit);
|
||||
map.entry(instance.owner).or_default().push(LightmapEntry {
|
||||
texture: Some(Texture(Resource::new(TextureState::Ok(lightmap)))),
|
||||
lights: lights.iter().map(|light| light.handle()).collect(),
|
||||
@@ -678,7 +678,7 @@ fn generate_lightmap(
|
||||
) -> TextureData {
|
||||
// We have to re-generate new set of world-space vertices because UV generator
|
||||
// may add new vertices on seams.
|
||||
let atlas_size = estimate_size(&instance.data(), texels_per_unit);
|
||||
let atlas_size = estimate_size(instance.data(), texels_per_unit);
|
||||
let scale = 1.0 / atlas_size as f32;
|
||||
let grid = Grid::new(instance.data(), (atlas_size / 32).max(4) as usize);
|
||||
|
||||
|
||||
@@ -392,7 +392,7 @@ fn closest_point_index_in_triangle_and_adjacent(
|
||||
) -> Option<usize> {
|
||||
let mut triangles = ArrayVec::<TriangleDefinition, 4>::new();
|
||||
triangles.push(triangle);
|
||||
math::get_closest_point_triangle_set(&navmesh.pathfinder.vertices(), &triangles, to)
|
||||
math::get_closest_point_triangle_set(navmesh.pathfinder.vertices(), &triangles, to)
|
||||
}
|
||||
|
||||
impl NavmeshAgent {
|
||||
@@ -502,7 +502,7 @@ impl NavmeshAgent {
|
||||
let c = vertices[triangle[2] as usize].position;
|
||||
|
||||
// Ignore degenerated triangles.
|
||||
if let Some(normal) = (c - a).cross(&(b - a)).try_normalize(std::f32::EPSILON) {
|
||||
if let Some(normal) = (c - a).cross(&(b - a)).try_normalize(f32::EPSILON) {
|
||||
// Calculate signed distance between triangle and segment's center.
|
||||
let signed_distance = (center - a).dot(&normal);
|
||||
|
||||
@@ -535,7 +535,7 @@ impl NavmeshAgent {
|
||||
if let Some(source) = self.path.get(self.current as usize) {
|
||||
if let Some(destination) = self.path.get((self.current + 1) as usize) {
|
||||
let ray = Ray::from_two_points(*source, *destination);
|
||||
let d = ray.dir.try_normalize(std::f32::EPSILON).unwrap_or_default();
|
||||
let d = ray.dir.try_normalize(f32::EPSILON).unwrap_or_default();
|
||||
self.position += d.scale(self.speed * dt);
|
||||
if ray.project_point(&self.position) >= 1.0 {
|
||||
self.current += 1;
|
||||
|
||||
+2
-2
@@ -31,8 +31,8 @@ impl UvMesh {
|
||||
fn new(first_triangle: usize) -> Self {
|
||||
Self {
|
||||
triangles: vec![first_triangle],
|
||||
uv_max: Vector2::new(-std::f32::MAX, -std::f32::MAX),
|
||||
uv_min: Vector2::new(std::f32::MAX, std::f32::MAX),
|
||||
uv_max: Vector2::new(-f32::MAX, -f32::MAX),
|
||||
uv_min: Vector2::new(f32::MAX, f32::MAX),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user