Merge branch 'master' into 1.2
This commit is contained in:
2
.github/workflows/build_linux.yml
vendored
2
.github/workflows/build_linux.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext curl libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libcurl4-gnutls-dev
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
- name: Checkout LFS
|
||||
|
||||
@@ -32,3 +32,19 @@ Go check out our [Trello](https://trello.com/b/NQjLXRCP/flax-roadmap).
|
||||
|
||||
|
||||
Thank you for taking interest in contributing to Flax!
|
||||
|
||||
## **Common issues**
|
||||
|
||||
Below are some common issues that someone working with the FlaxEngine source code might run into. Hopefully some of those issues will get fixed in the future. If you know how, please contribute!
|
||||
|
||||
* Missing MSVC toolset
|
||||
* Install it through the Visual Studio Installer
|
||||
* Building or attaching fails
|
||||
* Run `GenerateProjectFiles.bat`
|
||||
* Rebuild `Flax.Build`
|
||||
* Make sure that there isn't a stray FlaxEngine process running in the background
|
||||
* First start Flax and then attach the C# debugger
|
||||
* Configure the C# FlaxEngine project by going into the project properties, then the debug tab and selecting "Start external program" `Flax\FlaxEngine\Binaries\Editor\Win64\Debug\FlaxEditor.exe`
|
||||
* Then you can also set command line arguments such as `-project "C:\Users\PROFILE\Documents\Flax Projects\FlaxSamples\BasicTemplate"`
|
||||
* Git LFS
|
||||
* Push with `git push --no-verify`
|
||||
|
||||
@@ -47,7 +47,7 @@ Flax Visual Studio extension provides better programming workflow, C# scripts de
|
||||
* Install Visual Studio Code
|
||||
* Install Mono ([https://www.mono-project.com/download/stable](https://www.mono-project.com/download/stable))
|
||||
* Install Git with LFS
|
||||
* Install requried packages: `sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev nuget autoconf libogg-dev automake build-essential gettext cmake python curl libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev libcurl4-gnutls-dev`
|
||||
* Install requried packages: `sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev nuget autoconf libogg-dev automake build-essential gettext cmake python libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev`
|
||||
* Install compiler `sudo apt-get install clang lldb lld` (Clang 6 or newer)
|
||||
* Clone repo (with LFS)
|
||||
* Run `./GenerateProjectFiles.sh`
|
||||
|
||||
@@ -59,7 +59,10 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// <summary>
|
||||
/// Gets the default window size.
|
||||
/// </summary>
|
||||
public virtual Vector2 DefaultSize => new Vector2(900, 580);
|
||||
/// <remarks>
|
||||
/// Scaled by the DPI, because the window should be large enough for its content on every monitor
|
||||
/// </remarks>
|
||||
public virtual Vector2 DefaultSize => new Vector2(900, 580) * DpiScale;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the serialization typename.
|
||||
|
||||
@@ -22,14 +22,25 @@ namespace FlaxEditor.Modules
|
||||
/// <seealso cref="FlaxEditor.SceneGraph.RootNode" />
|
||||
public class ScenesRootNode : RootNode
|
||||
{
|
||||
private readonly Editor _editor;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ScenesRootNode()
|
||||
{
|
||||
_editor = Editor.Instance;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Spawn(Actor actor, Actor parent)
|
||||
{
|
||||
Editor.Instance.SceneEditing.Spawn(actor, parent);
|
||||
_editor.SceneEditing.Spawn(actor, parent);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Undo Undo => Editor.Instance.Undo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override List<SceneGraphNode> Selection => _editor.SceneEditing.Selection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
|
||||
public override bool CanBeSelectedDirectly => true;
|
||||
|
||||
public override bool CanDuplicate => true;
|
||||
public override bool CanDuplicate => !Root?.Selection.Contains(ParentNode) ?? true;
|
||||
|
||||
public override bool CanDelete => true;
|
||||
|
||||
@@ -367,6 +367,15 @@ namespace FlaxEditor.SceneGraph.Actors
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool RayCastSelf(ref RayCastData ray, out float distance, out Vector3 normal)
|
||||
{
|
||||
// Select only spline points
|
||||
normal = Vector3.Up;
|
||||
distance = float.MaxValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDispose()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.SceneGraph.Actors;
|
||||
using FlaxEngine;
|
||||
|
||||
@@ -146,5 +147,10 @@ namespace FlaxEditor.SceneGraph
|
||||
/// Gets the undo.
|
||||
/// </summary>
|
||||
public abstract Undo Undo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of selected scene graph nodes in the editor context.
|
||||
/// </summary>
|
||||
public abstract List<SceneGraphNode> Selection { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,9 @@ namespace FlaxEditor.SceneGraph
|
||||
/// </summary>
|
||||
public virtual RootNode Root => ParentNode?.Root;
|
||||
|
||||
/// <inheritdoc />
|
||||
/// <summary>
|
||||
/// Gets or sets the transform of the node.
|
||||
/// </summary>
|
||||
public abstract Transform Transform { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -36,6 +36,9 @@ namespace FlaxEditor.Windows.Assets
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Undo Undo => _window.Undo;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override List<SceneGraphNode> Selection => _window.Selection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -209,9 +209,11 @@ namespace FlaxEditor.Windows
|
||||
public override void Draw()
|
||||
{
|
||||
var style = Style.Current;
|
||||
|
||||
// Draw overlay
|
||||
string overlayText = null;
|
||||
var state = Editor.StateMachine.CurrentState;
|
||||
var textWrap = TextWrapping.NoWrap;
|
||||
if (state is LoadingState)
|
||||
{
|
||||
overlayText = "Loading...";
|
||||
@@ -223,10 +225,11 @@ namespace FlaxEditor.Windows
|
||||
else if (((ContainerControl)_tree.GetChild(0)).ChildrenCount == 0)
|
||||
{
|
||||
overlayText = "No scene\nOpen one from the content window";
|
||||
textWrap = TextWrapping.WrapWords;
|
||||
}
|
||||
if (overlayText != null)
|
||||
{
|
||||
Render2D.DrawText(Style.Current.FontLarge, overlayText, GetClientArea(), style.ForegroundDisabled, TextAlignment.Center, TextAlignment.Center);
|
||||
Render2D.DrawText(style.FontLarge, overlayText, GetClientArea(), style.ForegroundDisabled, TextAlignment.Center, TextAlignment.Center, textWrap);
|
||||
}
|
||||
|
||||
base.Draw();
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <OpenAL/al.h>
|
||||
#include <OpenAL/alc.h>
|
||||
|
||||
#define FLAX_POS_TO_OAL(vec) -vec.X * 0.01f, vec.Y * 0.01f, vec.Z * 0.01f
|
||||
#define FLAX_POS_TO_OAL(vec) -vec.X * 0.01f, vec.Y * 0.01f, -vec.Z * 0.01f
|
||||
|
||||
namespace ALC
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define MAX_OUTPUT_CHANNELS 8
|
||||
#define MAX_CHANNELS_MATRIX_SIZE (MAX_INPUT_CHANNELS*MAX_OUTPUT_CHANNELS)
|
||||
|
||||
#define FLAX_POS_TO_XAUDIO(vec) X3DAUDIO_VECTOR(-vec.X * 0.01f, vec.Y * 0.01f, vec.Z * 0.01f)
|
||||
#define FLAX_POS_TO_XAUDIO(vec) X3DAUDIO_VECTOR(vec.X * 0.01f, vec.Y * 0.01f, vec.Z * 0.01f)
|
||||
#define FLAX_VEC_TO_XAUDIO(vec) (*((X3DAUDIO_VECTOR*)&vec))
|
||||
|
||||
namespace XAudio2
|
||||
|
||||
@@ -236,7 +236,7 @@ public:
|
||||
return;
|
||||
ASSERT(capacity >= 0);
|
||||
const int32 count = preserveContents ? (_count < capacity ? _count : capacity) : 0;
|
||||
_allocation.Relocate(Math::Max<ItemType>(capacity / sizeof(ItemType), 1), _count, count);
|
||||
_allocation.Relocate(Math::Max<ItemType>(capacity / sizeof(ItemType), 1), _count / sizeof(ItemType), count / sizeof(ItemType));
|
||||
_capacity = capacity;
|
||||
_count = count;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
/// <summary>
|
||||
/// Helper collection used by the sorting algorithms. Implements stack using single linear allocation with variable capacity.
|
||||
/// </summary>
|
||||
class SortingStack
|
||||
class FLAXENGINE_API SortingStack
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
@@ -37,21 +37,21 @@ public:
|
||||
virtual ~ISerializable() = default;
|
||||
|
||||
/// <summary>
|
||||
/// Serialize object to the output stream compared to the values of the other object instance (eg. default class object). If other object is null then serialize all properties.
|
||||
/// Serializes object to the output stream compared to the values of the other object instance (eg. default class object). If other object is null then serialize all properties.
|
||||
/// </summary>
|
||||
/// <param name="stream">The output stream.</param>
|
||||
/// <param name="otherObj">The instance of the object to compare with and serialize only the modified properties. If null, then serialize all properties.</param>
|
||||
virtual void Serialize(SerializeStream& stream, const void* otherObj) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize object from the input stream
|
||||
/// Deserializes object from the input stream.
|
||||
/// </summary>
|
||||
/// <param name="stream">The input stream.</param>
|
||||
/// <param name="modifier">The deserialization modifier object. Always valid.</param>
|
||||
virtual void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize object from the input stream child member. Won't deserialize it if member is missing.
|
||||
/// Deserializes object from the input stream child member. Won't deserialize it if member is missing.
|
||||
/// </summary>
|
||||
/// <param name="stream">The input stream.</param>
|
||||
/// <param name="memberName">The input stream member to lookup.</param>
|
||||
|
||||
@@ -4,11 +4,10 @@
|
||||
|
||||
#include "BaseTypes.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "Engine/Core/Formatting.h"
|
||||
#include "Engine/Core/Templates.h"
|
||||
|
||||
/// <summary>
|
||||
/// Represents the version number made of major, minor, patch and build numbers.
|
||||
/// Represents the version number made of major, minor, build and revision numbers.
|
||||
/// </summary>
|
||||
struct FLAXENGINE_API Version
|
||||
{
|
||||
|
||||
@@ -59,6 +59,7 @@ GameplayGlobals::GameplayGlobals(const SpawnParams& params, const AssetInfo* inf
|
||||
|
||||
Dictionary<String, Variant> GameplayGlobals::GetValues() const
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
Dictionary<String, Variant> result;
|
||||
for (auto& e : Variables)
|
||||
result.Add(e.Key, e.Value.Value);
|
||||
@@ -67,6 +68,7 @@ Dictionary<String, Variant> GameplayGlobals::GetValues() const
|
||||
|
||||
void GameplayGlobals::SetValues(const Dictionary<String, Variant>& values)
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
for (auto& e : values)
|
||||
{
|
||||
bool hasKey = false;
|
||||
@@ -97,6 +99,7 @@ void GameplayGlobals::SetValues(const Dictionary<String, Variant>& values)
|
||||
|
||||
Dictionary<String, Variant> GameplayGlobals::GetDefaultValues() const
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
Dictionary<String, Variant> result;
|
||||
for (auto& e : Variables)
|
||||
result.Add(e.Key, e.Value.DefaultValue);
|
||||
@@ -105,6 +108,7 @@ Dictionary<String, Variant> GameplayGlobals::GetDefaultValues() const
|
||||
|
||||
void GameplayGlobals::SetDefaultValues(const Dictionary<String, Variant>& values)
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
for (auto& e : values)
|
||||
{
|
||||
bool hasKey = false;
|
||||
@@ -135,12 +139,14 @@ void GameplayGlobals::SetDefaultValues(const Dictionary<String, Variant>& values
|
||||
|
||||
Variant GameplayGlobals::GetValue(const StringView& name) const
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
auto e = Variables.TryGet(name);
|
||||
return e ? e->Value : Variant::Zero;
|
||||
}
|
||||
|
||||
void GameplayGlobals::SetValue(const StringView& name, const Variant& value)
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
auto e = Variables.TryGet(name);
|
||||
if (e)
|
||||
{
|
||||
@@ -150,6 +156,7 @@ void GameplayGlobals::SetValue(const StringView& name, const Variant& value)
|
||||
|
||||
void GameplayGlobals::ResetValues()
|
||||
{
|
||||
ScopeLock lock(Locker);
|
||||
for (auto& e : Variables)
|
||||
{
|
||||
e.Value.Value = e.Value.DefaultValue;
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
/// Engine subsystem updating data.
|
||||
/// Used to invoke game logic updates, physics updates and rendering with possibly different frequencies.
|
||||
/// </summary>
|
||||
class TickData
|
||||
class FLAXENGINE_API TickData
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ public:
|
||||
/// <summary>
|
||||
/// The scene rendering camera. Can be used to override the rendering view properties based on the current camera setup.
|
||||
/// </summary>
|
||||
API_FIELD() Camera* Camera = nullptr;
|
||||
API_FIELD() ScriptingObjectReference<Camera> Camera;
|
||||
|
||||
/// <summary>
|
||||
/// The render view description.
|
||||
|
||||
@@ -128,6 +128,13 @@ void BoxBrush::GetSurfaces(CSG::Surface surfaces[6])
|
||||
}
|
||||
}
|
||||
|
||||
void BoxBrush::SetMaterial(int32 surfaceIndex, MaterialBase* material)
|
||||
{
|
||||
CHECK(Math::IsInRange(surfaceIndex, 0, 5));
|
||||
Surfaces[surfaceIndex].Material = material;
|
||||
OnBrushModified();
|
||||
}
|
||||
|
||||
bool BoxBrush::Intersects(int32 surfaceIndex, const Ray& ray, float& distance, Vector3& normal) const
|
||||
{
|
||||
distance = MAX_float;
|
||||
@@ -232,6 +239,26 @@ void BoxBrush::OnDebugDrawSelected()
|
||||
|
||||
#endif
|
||||
|
||||
Scene* BoxBrush::GetBrushScene() const
|
||||
{
|
||||
return GetScene();
|
||||
}
|
||||
|
||||
Guid BoxBrush::GetBrushID() const
|
||||
{
|
||||
return GetID();
|
||||
}
|
||||
|
||||
bool BoxBrush::CanUseCSG() const
|
||||
{
|
||||
return IsActiveInHierarchy();
|
||||
}
|
||||
|
||||
CSG::Mode BoxBrush::GetBrushMode() const
|
||||
{
|
||||
return _mode;
|
||||
}
|
||||
|
||||
void BoxBrush::GetSurfaces(Array<CSG::Surface>& surfaces)
|
||||
{
|
||||
surfaces.Clear();
|
||||
@@ -240,6 +267,11 @@ void BoxBrush::GetSurfaces(Array<CSG::Surface>& surfaces)
|
||||
GetSurfaces(surfaces.Get());
|
||||
}
|
||||
|
||||
int32 BoxBrush::GetSurfacesCount()
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
|
||||
void BoxBrush::OnTransformChanged()
|
||||
{
|
||||
// Base
|
||||
@@ -272,7 +304,7 @@ void BoxBrush::OnParentChanged()
|
||||
{
|
||||
// Base
|
||||
Actor::OnParentChanged();
|
||||
|
||||
|
||||
if (!IsDuringPlay())
|
||||
return;
|
||||
|
||||
|
||||
@@ -153,6 +153,13 @@ public:
|
||||
/// <param name="surfaces">Surfaces</param>
|
||||
void GetSurfaces(CSG::Surface surfaces[6]);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the brush surface material.
|
||||
/// </summary>
|
||||
/// <param name="surfaceIndex">The brush surface index.</param>
|
||||
/// <param name="material">The material.</param>
|
||||
API_FUNCTION() void SetMaterial(int32 surfaceIndex, MaterialBase* material);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
@@ -169,7 +176,7 @@ public:
|
||||
/// Otherwise performs simple <see cref="BoundingBox"/> vs <see cref="Ray"/> test.
|
||||
/// For more efficient collisions detection and ray casting use physics.
|
||||
/// </summary>
|
||||
/// <param name="surfaceIndex">The brush surface index..</param>
|
||||
/// <param name="surfaceIndex">The brush surface index.</param>
|
||||
/// <param name="ray">The ray to test.</param>
|
||||
/// <param name="distance">When the method completes and returns true, contains the distance of the intersection (if any valid).</param>
|
||||
/// <param name="normal">When the method completes, contains the intersection surface normal vector (if any valid).</param>
|
||||
@@ -179,7 +186,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the brush surface triangles array (group by 3 vertices).
|
||||
/// </summary>
|
||||
/// <param name="surfaceIndex">The brush surface index..</param>
|
||||
/// <param name="surfaceIndex">The brush surface index.</param>
|
||||
/// <param name="outputData">The output vertices buffer with triangles or empty if no data loaded.</param>
|
||||
API_FUNCTION() void GetVertices(int32 surfaceIndex, API_PARAM(Out) Array<Vector3>& outputData) const;
|
||||
|
||||
@@ -204,32 +211,12 @@ public:
|
||||
#endif
|
||||
|
||||
// [CSG::Brush]
|
||||
Scene* GetBrushScene() const override
|
||||
{
|
||||
return GetScene();
|
||||
}
|
||||
|
||||
Guid GetBrushID() const override
|
||||
{
|
||||
return GetID();
|
||||
}
|
||||
|
||||
bool CanUseCSG() const override
|
||||
{
|
||||
return IsActiveInHierarchy();
|
||||
}
|
||||
|
||||
CSG::Mode GetBrushMode() const override
|
||||
{
|
||||
return _mode;
|
||||
}
|
||||
|
||||
Scene* GetBrushScene() const override;
|
||||
Guid GetBrushID() const override;
|
||||
bool CanUseCSG() const override;
|
||||
CSG::Mode GetBrushMode() const override;
|
||||
void GetSurfaces(Array<CSG::Surface>& surfaces) override;
|
||||
|
||||
int32 GetSurfacesCount() override
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
int32 GetSurfacesCount() override;
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -17,12 +17,13 @@
|
||||
|
||||
Array<Camera*> Camera::Cameras;
|
||||
Camera* Camera::CutSceneCamera = nullptr;
|
||||
Camera* Camera::OverrideMainCamera = nullptr;
|
||||
ScriptingObjectReference<Camera> Camera::OverrideMainCamera;
|
||||
|
||||
Camera* Camera::GetMainCamera()
|
||||
{
|
||||
if (OverrideMainCamera)
|
||||
return OverrideMainCamera;
|
||||
Camera* overrideMainCamera = OverrideMainCamera.Get();
|
||||
if (overrideMainCamera)
|
||||
return overrideMainCamera;
|
||||
if (CutSceneCamera)
|
||||
return CutSceneCamera;
|
||||
return Cameras.HasItems() ? Cameras.First() : nullptr;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "Engine/Core/Math/Viewport.h"
|
||||
#include "Engine/Core/Math/Ray.h"
|
||||
#include "Engine/Core/Types/LayersMask.h"
|
||||
#include "Engine/Scripting/ScriptingObjectReference.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Graphics/Models/ModelInstanceEntry.h"
|
||||
@@ -28,7 +29,7 @@ DECLARE_SCENE_OBJECT(Camera);
|
||||
static Camera* CutSceneCamera;
|
||||
|
||||
// The overriden main camera.
|
||||
API_FIELD() static Camera* OverrideMainCamera;
|
||||
API_FIELD() static ScriptingObjectReference<Camera> OverrideMainCamera;
|
||||
|
||||
// Gets the main camera.
|
||||
API_PROPERTY() static Camera* GetMainCamera();
|
||||
|
||||
@@ -138,11 +138,10 @@ void SplineModel::OnSplineUpdated()
|
||||
Vector3 tmp = corners[i] * _preTransform.Scale;
|
||||
double rotation[4] = { (double)_preTransform.Orientation.X, (double)_preTransform.Orientation.Y, (double)_preTransform.Orientation.Z, (double)_preTransform.Orientation.W };
|
||||
const double length = sqrt(rotation[0] * rotation[0] + rotation[1] * rotation[1] + rotation[2] * rotation[2] + rotation[3] * rotation[3]);
|
||||
const double inv = 1.0 / length;
|
||||
rotation[0] *= inv;
|
||||
rotation[1] *= inv;
|
||||
rotation[2] *= inv;
|
||||
rotation[3] *= inv;
|
||||
rotation[0] /= length;
|
||||
rotation[1] /= length;
|
||||
rotation[2] /= length;
|
||||
rotation[3] /= length;
|
||||
double pos[3] = { (double)tmp.X, (double)tmp.Y, (double)tmp.Z };
|
||||
const double x = rotation[0] + rotation[0];
|
||||
const double y = rotation[1] + rotation[1];
|
||||
@@ -251,7 +250,7 @@ void SplineModel::UpdateDeformationBuffer()
|
||||
AnimationUtils::GetTangent(end.Value, end.TangentIn, length, rightTangent);
|
||||
for (int32 chunk = 0; chunk < chunksPerSegment; chunk++)
|
||||
{
|
||||
const float alpha = (float)chunk * chunksPerSegmentInv;
|
||||
const float alpha = (chunk == chunksPerSegment - 1)? 1.0f : ((float)chunk * chunksPerSegmentInv);
|
||||
|
||||
// Evaluate transformation at the curve
|
||||
AnimationUtils::Bezier(start.Value, leftTangent, rightTangent, end.Value, alpha, transform);
|
||||
|
||||
@@ -22,6 +22,7 @@ CharacterController::CharacterController(const SpawnParams& params)
|
||||
, _radius(50.0f)
|
||||
, _height(150.0f)
|
||||
, _minMoveDistance(0.0f)
|
||||
, _upDirection(Vector3::Up)
|
||||
, _isUpdatingTransform(false)
|
||||
, _nonWalkableMode(CharacterController::NonWalkableModes::PreventClimbing)
|
||||
, _lastFlags(CollisionFlags::None)
|
||||
@@ -82,6 +83,18 @@ void CharacterController::SetStepOffset(float value)
|
||||
_controller->setStepOffset(value);
|
||||
}
|
||||
|
||||
void CharacterController::SetUpDirection(const Vector3& up)
|
||||
{
|
||||
if (_controller)
|
||||
_controller->setUpDirection(C2P(up));
|
||||
_upDirection = up;
|
||||
}
|
||||
|
||||
Vector3 CharacterController::GetUpDirection() const
|
||||
{
|
||||
return _controller ? P2C(_controller->getUpDirection()) : _upDirection;
|
||||
}
|
||||
|
||||
void CharacterController::SetMinMoveDistance(float value)
|
||||
{
|
||||
_minMoveDistance = Math::Max(value, 0.0f);
|
||||
@@ -180,6 +193,7 @@ void CharacterController::CreateActor()
|
||||
// Create controller
|
||||
_controller = (PxCapsuleController*)Physics::GetControllerManager()->createController(desc);
|
||||
ASSERT(_controller);
|
||||
_controller->setUpDirection(C2P(_upDirection));
|
||||
const auto actor = _controller->getActor();
|
||||
ASSERT(actor && actor->getNbShapes() == 1);
|
||||
actor->getShapes(&_shape, 1);
|
||||
@@ -363,6 +377,7 @@ void CharacterController::Serialize(SerializeStream& stream, const void* otherOb
|
||||
SERIALIZE_MEMBER(Radius, _radius);
|
||||
SERIALIZE_MEMBER(Height, _height);
|
||||
SERIALIZE_MEMBER(MinMoveDistance, _minMoveDistance);
|
||||
SERIALIZE_MEMBER(UpDirection, _upDirection);
|
||||
}
|
||||
|
||||
void CharacterController::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
|
||||
@@ -376,4 +391,5 @@ void CharacterController::Deserialize(DeserializeStream& stream, ISerializeModif
|
||||
DESERIALIZE_MEMBER(Radius, _radius);
|
||||
DESERIALIZE_MEMBER(Height, _height);
|
||||
DESERIALIZE_MEMBER(MinMoveDistance, _minMoveDistance);
|
||||
DESERIALIZE_MEMBER(UpDirection, _upDirection);
|
||||
}
|
||||
|
||||
@@ -65,6 +65,7 @@ private:
|
||||
float _height;
|
||||
float _minMoveDistance;
|
||||
bool _isUpdatingTransform;
|
||||
Vector3 _upDirection;
|
||||
NonWalkableModes _nonWalkableMode;
|
||||
CollisionFlags _lastFlags;
|
||||
uint32 _filterData[4];
|
||||
@@ -141,6 +142,17 @@ public:
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetStepOffset(float value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the character up vector.
|
||||
/// </summary>
|
||||
API_PROPERTY(Attributes="EditorOrder(240), DefaultValue(true), EditorDisplay(\"Character Controller\")")
|
||||
Vector3 GetUpDirection() const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the character up vector.
|
||||
/// </summary>
|
||||
API_PROPERTY() void SetUpDirection(const Vector3& up);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the minimum move distance of the character controller. The minimum traveled distance to consider. If traveled distance is smaller, the character doesn't move. This is used to stop the recursive motion algorithm when remaining distance to travel is small.
|
||||
/// </summary>
|
||||
|
||||
@@ -358,6 +358,51 @@ bool Physics::SphereCastAll(const Vector3& center, const float radius, const Vec
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
||||
{
|
||||
// Prepare data
|
||||
SCENE_QUERY_SETUP_SWEEP_1();
|
||||
const PxTransform pose(C2P(center), C2P(rotation));
|
||||
const PxCapsuleGeometry geometry(radius, height * 0.5f);
|
||||
|
||||
// Perform sweep test
|
||||
return GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback());
|
||||
}
|
||||
|
||||
bool Physics::CapsuleCast(const Vector3& center, const float radius, const float height, const Vector3& direction, RayCastHit& hitInfo, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
||||
{
|
||||
// Prepare data
|
||||
SCENE_QUERY_SETUP_SWEEP_1();
|
||||
const PxTransform pose(C2P(center), C2P(rotation));
|
||||
const PxCapsuleGeometry geometry(radius, height * 0.5f);
|
||||
|
||||
// Perform sweep test
|
||||
if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()))
|
||||
return false;
|
||||
|
||||
// Collect results
|
||||
SCENE_QUERY_COLLECT_SINGLE();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Physics::CapsuleCastAll(const Vector3& center, const float radius, const float height, const Vector3& direction, Array<RayCastHit>& results, const Quaternion& rotation, const float maxDistance, uint32 layerMask, bool hitTriggers)
|
||||
{
|
||||
// Prepare data
|
||||
SCENE_QUERY_SETUP_SWEEP();
|
||||
const PxTransform pose(C2P(center), C2P(rotation));
|
||||
const PxCapsuleGeometry geometry(radius, height * 0.5f);
|
||||
|
||||
// Perform sweep test
|
||||
if (!GetScene()->sweep(geometry, pose, C2P(direction), maxDistance, buffer, hitFlags, filterData, GetQueryFilterCallback()))
|
||||
return false;
|
||||
|
||||
// Collect results
|
||||
SCENE_QUERY_COLLECT_ALL();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Physics::CheckBox(const Vector3& center, const Vector3& halfExtents, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
|
||||
{
|
||||
// Prepare data
|
||||
@@ -380,6 +425,17 @@ bool Physics::CheckSphere(const Vector3& center, const float radius, uint32 laye
|
||||
return GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback());
|
||||
}
|
||||
|
||||
bool Physics::CheckCapsule(const Vector3& center, const float radius, const float height, uint32 layerMask, bool hitTriggers)
|
||||
{
|
||||
// Prepare data
|
||||
SCENE_QUERY_SETUP_OVERLAP_1();
|
||||
const PxTransform pose(C2P(center));
|
||||
const PxCapsuleGeometry geometry(radius, height * 0.5f);
|
||||
|
||||
// Perform overlap test
|
||||
return GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback());
|
||||
}
|
||||
|
||||
bool Physics::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array<Collider*>& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
|
||||
{
|
||||
// Prepare data
|
||||
@@ -414,6 +470,23 @@ bool Physics::OverlapSphere(const Vector3& center, const float radius, Array<Col
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Physics::OverlapCapsule(const Vector3& center, const float radius, const float height, Array<Collider*>& results, uint32 layerMask, bool hitTriggers)
|
||||
{
|
||||
// Prepare data
|
||||
SCENE_QUERY_SETUP_OVERLAP();
|
||||
const PxTransform pose(C2P(center));
|
||||
const PxCapsuleGeometry geometry(radius, height * 0.5f);
|
||||
|
||||
// Perform overlap test
|
||||
if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()))
|
||||
return false;
|
||||
|
||||
// Collect results
|
||||
SCENE_QUERY_COLLECT_OVERLAP_COLLIDER();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Physics::OverlapBox(const Vector3& center, const Vector3& halfExtents, Array<PhysicsColliderActor*>& results, const Quaternion& rotation, uint32 layerMask, bool hitTriggers)
|
||||
{
|
||||
// Prepare data
|
||||
@@ -447,3 +520,20 @@ bool Physics::OverlapSphere(const Vector3& center, const float radius, Array<Phy
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Physics::OverlapCapsule(const Vector3& center, const float radius, const float height, Array<PhysicsColliderActor*>& results, uint32 layerMask, bool hitTriggers)
|
||||
{
|
||||
// Prepare data
|
||||
SCENE_QUERY_SETUP_OVERLAP();
|
||||
const PxTransform pose(C2P(center));
|
||||
const PxCapsuleGeometry geometry(radius, height * 0.5f);
|
||||
|
||||
// Perform overlap test
|
||||
if (!GetScene()->overlap(geometry, pose, buffer, filterData, GetQueryFilterCallback()))
|
||||
return false;
|
||||
|
||||
// Collect results
|
||||
SCENE_QUERY_COLLECT_OVERLAP();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -268,6 +268,50 @@ public:
|
||||
/// <returns>True if sphere hits an matching object, otherwise false.</returns>
|
||||
API_FUNCTION() static bool SphereCastAll(const Vector3& center, float radius, const Vector3& direction, API_PARAM(Out) Array<RayCastHit, HeapAllocation>& results, float maxDistance = MAX_float, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
|
||||
|
||||
/// <summary>
|
||||
/// Performs a sweep test against objects in the scene using a capsule geometry.
|
||||
/// </summary>
|
||||
/// <param name="center">The box center.</param>
|
||||
/// <param name="radius">The radius of the capsule.</param>
|
||||
/// <param name="height">The height of the capsule, excluding the top and bottom spheres.</param>
|
||||
/// <param name="direction">The normalized direction in which cast a box.</param>
|
||||
/// <param name="rotation">The capsule rotation.</param>
|
||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||
/// <param name="layerMask">The layer mask used to filter the results.</param>
|
||||
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
|
||||
/// <returns>True if capsule hits an matching object, otherwise false.</returns>
|
||||
API_FUNCTION() static bool CapsuleCast(const Vector3& center, float radius, float height, const Vector3& direction, const Quaternion& rotation = Quaternion::Identity, float maxDistance = MAX_float, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
|
||||
|
||||
/// <summary>
|
||||
/// Performs a sweep test against objects in the scene using a capsule geometry.
|
||||
/// </summary>
|
||||
/// <param name="center">The box center.</param>
|
||||
/// <param name="radius">The radius of the capsule.</param>
|
||||
/// <param name="height">The height of the capsule, excluding the top and bottom spheres.</param>
|
||||
/// <param name="direction">The normalized direction in which cast a box.</param>
|
||||
/// <param name="hitInfo">The result hit information. Valid only when method returns true.</param>
|
||||
/// <param name="rotation">The capsule rotation.</param>
|
||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||
/// <param name="layerMask">The layer mask used to filter the results.</param>
|
||||
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
|
||||
/// <returns>True if capsule hits an matching object, otherwise false.</returns>
|
||||
API_FUNCTION() static bool CapsuleCast(const Vector3& center, float radius, float height, const Vector3& direction, API_PARAM(Out) RayCastHit& hitInfo, const Quaternion& rotation = Quaternion::Identity, float maxDistance = MAX_float, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
|
||||
|
||||
/// <summary>
|
||||
/// Performs a sweep test against objects in the scene using a capsule geometry.
|
||||
/// </summary>
|
||||
/// <param name="center">The box center.</param>
|
||||
/// <param name="radius">The radius of the capsule.</param>
|
||||
/// <param name="height">The height of the capsule, excluding the top and bottom spheres.</param>
|
||||
/// <param name="direction">The normalized direction in which cast a box.</param>
|
||||
/// <param name="results">The result hits. Valid only when method returns true.</param>
|
||||
/// <param name="rotation">The capsule rotation.</param>
|
||||
/// <param name="maxDistance">The maximum distance the ray should check for collisions.</param>
|
||||
/// <param name="layerMask">The layer mask used to filter the results.</param>
|
||||
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
|
||||
/// <returns>True if capsule hits an matching object, otherwise false.</returns>
|
||||
API_FUNCTION() static bool CapsuleCastAll(const Vector3& center, float radius, float height, const Vector3& direction, API_PARAM(Out) Array<RayCastHit, HeapAllocation>& results, const Quaternion& rotation = Quaternion::Identity, float maxDistance = MAX_float, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the given box overlaps with other colliders or not.
|
||||
/// </summary>
|
||||
@@ -289,6 +333,17 @@ public:
|
||||
/// <returns>True if sphere overlaps any matching object, otherwise false.</returns>
|
||||
API_FUNCTION() static bool CheckSphere(const Vector3& center, float radius, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the given capsule overlaps with other colliders or not.
|
||||
/// </summary>
|
||||
/// <param name="center">The capsule center.</param>
|
||||
/// <param name="radius">The radius of the capsule.</param>
|
||||
/// <param name="height">The height of the capsule, excluding the top and bottom spheres.</param>
|
||||
/// <param name="layerMask">The layer mask used to filter the results.</param>
|
||||
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
|
||||
/// <returns>True if capsule overlaps any matching object, otherwise false.</returns>
|
||||
API_FUNCTION() static bool CheckCapsule(const Vector3& center, float radius, float height, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
|
||||
|
||||
/// <summary>
|
||||
/// Finds all colliders touching or inside of the given box.
|
||||
/// </summary>
|
||||
@@ -312,6 +367,18 @@ public:
|
||||
/// <returns>True if sphere overlaps any matching object, otherwise false.</returns>
|
||||
API_FUNCTION() static bool OverlapSphere(const Vector3& center, float radius, API_PARAM(Out) Array<Collider*, HeapAllocation>& results, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
|
||||
|
||||
/// <summary>
|
||||
/// Finds all colliders touching or inside of the given sphere.
|
||||
/// </summary>
|
||||
/// <param name="center">The sphere center.</param>
|
||||
/// <param name="radius">The radius of the capsule.</param>
|
||||
/// <param name="height">The height of the capsule, excluding the top and bottom spheres.</param>
|
||||
/// <param name="results">The result colliders that overlap with the given sphere. Valid only when method returns true.</param>
|
||||
/// <param name="layerMask">The layer mask used to filter the results.</param>
|
||||
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
|
||||
/// <returns>True if capsule overlaps any matching object, otherwise false.</returns>
|
||||
API_FUNCTION() static bool OverlapCapsule(const Vector3& center, float radius, float height, API_PARAM(Out) Array<Collider*, HeapAllocation>& results, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
|
||||
|
||||
/// <summary>
|
||||
/// Finds all colliders touching or inside of the given box.
|
||||
/// </summary>
|
||||
@@ -335,6 +402,18 @@ public:
|
||||
/// <returns>True if sphere overlaps any matching object, otherwise false.</returns>
|
||||
API_FUNCTION() static bool OverlapSphere(const Vector3& center, float radius, API_PARAM(Out) Array<PhysicsColliderActor*, HeapAllocation>& results, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
|
||||
|
||||
/// <summary>
|
||||
/// Finds all colliders touching or inside of the given sphere.
|
||||
/// </summary>
|
||||
/// <param name="center">The capsule center.</param>
|
||||
/// <param name="radius">The radius of the capsule.</param>
|
||||
/// <param name="height">The height of the capsule, excluding the top and bottom spheres.</param>
|
||||
/// <param name="results">The result colliders that overlap with the given sphere. Valid only when method returns true.</param>
|
||||
/// <param name="layerMask">The layer mask used to filter the results.</param>
|
||||
/// <param name="hitTriggers">If set to <c>true</c> triggers will be hit, otherwise will skip them.</param>
|
||||
/// <returns>True if capsule overlaps any matching object, otherwise false.</returns>
|
||||
API_FUNCTION() static bool OverlapCapsule(const Vector3& center, float radius, float height, API_PARAM(Out) Array<PhysicsColliderActor*, HeapAllocation>& results, uint32 layerMask = MAX_uint32, bool hitTriggers = true);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -260,7 +260,7 @@ bool WindowsFileSystem::ShowSaveFileDialog(Window* parentWindow, const StringVie
|
||||
of.lpstrFilter = filter.HasChars() ? filter.Get() : nullptr;
|
||||
of.lpstrFile = fileNamesBuffer.Get();
|
||||
of.nMaxFile = maxFilenamesSize;
|
||||
of.Flags = OFN_EXPLORER | OFN_ENABLESIZING;
|
||||
of.Flags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_OVERWRITEPROMPT;
|
||||
of.lpstrTitle = title.HasChars() ? title.Get() : nullptr;
|
||||
of.lpstrInitialDir = initialDirectory.HasChars() ? initialDirectory.Get() : nullptr;
|
||||
if (parentWindow)
|
||||
|
||||
@@ -251,6 +251,7 @@ void ShadowsPass::Prepare(RenderContext& renderContext, GPUContext* context)
|
||||
auto& shadowView = _shadowContext.View;
|
||||
shadowView.Flags = view.Flags;
|
||||
shadowView.StaticFlagsMask = view.StaticFlagsMask;
|
||||
shadowView.RenderLayersMask = view.RenderLayersMask;
|
||||
shadowView.IsOfflinePass = view.IsOfflinePass;
|
||||
shadowView.ModelLODBias = view.ModelLODBias + view.ShadowModelLODBias;
|
||||
shadowView.ModelLODDistanceFactor = view.ModelLODDistanceFactor * view.ShadowModelLODDistanceFactor;
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace FlaxEngine.GUI
|
||||
/// <summary>
|
||||
/// Dropdown menu control allows to choose one item from the provided collection of options.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEngine.GUI.Control" />
|
||||
public class Dropdown : Control
|
||||
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
|
||||
public class Dropdown : ContainerControl
|
||||
{
|
||||
/// <summary>
|
||||
/// The root control used by the <see cref="Dropdown"/> to show the items collections and track item selecting event.
|
||||
@@ -18,7 +18,7 @@ namespace FlaxEngine.GUI
|
||||
[HideInEditor]
|
||||
protected class DropdownRoot : Panel
|
||||
{
|
||||
private bool isMouseDown;
|
||||
private bool _isMouseDown;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when item gets clicked. Argument is item index.
|
||||
@@ -38,9 +38,9 @@ namespace FlaxEngine.GUI
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Vector2 location, MouseButton button)
|
||||
{
|
||||
isMouseDown = true;
|
||||
_isMouseDown = true;
|
||||
var result = base.OnMouseDown(location, button);
|
||||
isMouseDown = false;
|
||||
_isMouseDown = false;
|
||||
|
||||
if (!result)
|
||||
return false;
|
||||
@@ -57,8 +57,10 @@ namespace FlaxEngine.GUI
|
||||
{
|
||||
base.OnLostFocus();
|
||||
|
||||
if (!isMouseDown)
|
||||
LostFocus();
|
||||
if (!_isMouseDown)
|
||||
{
|
||||
LostFocus?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -82,7 +84,7 @@ namespace FlaxEngine.GUI
|
||||
/// </summary>
|
||||
protected DropdownRoot _popup;
|
||||
|
||||
private bool _mouseDown;
|
||||
private bool _touchDown;
|
||||
|
||||
/// <summary>
|
||||
/// The selected index of the item (-1 for no selection).
|
||||
@@ -118,13 +120,9 @@ namespace FlaxEngine.GUI
|
||||
get => _selectedIndex;
|
||||
set
|
||||
{
|
||||
// Clamp index
|
||||
value = Mathf.Min(value, _items.Count - 1);
|
||||
|
||||
// Check if index will change
|
||||
if (value != _selectedIndex)
|
||||
{
|
||||
// Select
|
||||
_selectedIndex = value;
|
||||
OnSelectedIndexChanged();
|
||||
}
|
||||
@@ -225,6 +223,8 @@ namespace FlaxEngine.GUI
|
||||
public Dropdown()
|
||||
: base(0, 0, 120, 18.0f)
|
||||
{
|
||||
AutoFocus = false;
|
||||
|
||||
var style = Style.Current;
|
||||
Font = new FontReference(style.FontMedium);
|
||||
TextColor = style.Foreground;
|
||||
@@ -334,6 +334,7 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
*/
|
||||
var itemsWidth = Width;
|
||||
var height = container.Margin.Height;
|
||||
|
||||
for (int i = 0; i < _items.Count; i++)
|
||||
{
|
||||
@@ -347,35 +348,51 @@ namespace FlaxEngine.GUI
|
||||
var label = new Label
|
||||
{
|
||||
X = itemsMargin,
|
||||
Width = itemsWidth - itemsMargin,
|
||||
Size = new Vector2(itemsWidth - itemsMargin, itemsHeight),
|
||||
Font = Font,
|
||||
TextColor = Color.White * 0.9f,
|
||||
TextColorHighlighted = Color.White,
|
||||
HorizontalAlignment = TextAlignment.Near,
|
||||
AnchorPreset = AnchorPresets.VerticalStretchRight,
|
||||
Text = _items[i],
|
||||
Parent = item,
|
||||
};
|
||||
height += itemsHeight;
|
||||
if (i != 0)
|
||||
height += container.Spacing;
|
||||
|
||||
if (_selectedIndex == i)
|
||||
{
|
||||
var icon = new Image
|
||||
{
|
||||
Brush = CheckedImage,
|
||||
Width = itemsMargin,
|
||||
Size = new Vector2(itemsMargin, itemsHeight),
|
||||
Margin = new Margin(4.0f, 6.0f, 4.0f, 4.0f),
|
||||
AnchorPreset = AnchorPresets.VerticalStretchLeft,
|
||||
//AnchorPreset = AnchorPresets.VerticalStretchLeft,
|
||||
Parent = item,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
popup.Size = new Vector2(itemsWidth, (itemsHeight + container.Spacing) * _items.Count + container.Margin.Height);
|
||||
popup.Size = new Vector2(itemsWidth, height);
|
||||
popup.ItemsContainer = container;
|
||||
|
||||
return popup;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when popup menu gets shown.
|
||||
/// </summary>
|
||||
protected virtual void OnPopupShow()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when popup menu gets hidden.
|
||||
/// </summary>
|
||||
protected virtual void OnPopupHide()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the popup.
|
||||
/// </summary>
|
||||
@@ -383,11 +400,59 @@ namespace FlaxEngine.GUI
|
||||
{
|
||||
if (_popup != null)
|
||||
{
|
||||
OnPopupHide();
|
||||
_popup.Dispose();
|
||||
_popup = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the popup.
|
||||
/// </summary>
|
||||
public void ShowPopup()
|
||||
{
|
||||
var root = Root;
|
||||
if (_items.Count == 0 || root == null)
|
||||
return;
|
||||
|
||||
// Setup popup
|
||||
DestroyPopup();
|
||||
_popup = CreatePopup();
|
||||
|
||||
// Update layout
|
||||
_popup.UnlockChildrenRecursive();
|
||||
_popup.PerformLayout();
|
||||
|
||||
// Bind events
|
||||
_popup.ItemClicked += index =>
|
||||
{
|
||||
OnItemClicked(index);
|
||||
DestroyPopup();
|
||||
};
|
||||
_popup.LostFocus += DestroyPopup;
|
||||
|
||||
// Show dropdown popup
|
||||
Vector2 locationRootSpace = Location + new Vector2(0, Height);
|
||||
var parent = Parent;
|
||||
while (parent != null && parent != Root)
|
||||
{
|
||||
locationRootSpace = parent.PointToParent(ref locationRootSpace);
|
||||
parent = parent.Parent;
|
||||
}
|
||||
_popup.Location = locationRootSpace;
|
||||
_popup.Parent = root;
|
||||
_popup.Focus();
|
||||
OnPopupShow();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hides the popup.
|
||||
/// </summary>
|
||||
public void HidePopup()
|
||||
{
|
||||
DestroyPopup();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
@@ -397,7 +462,7 @@ namespace FlaxEngine.GUI
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
public override void DrawSelf()
|
||||
{
|
||||
// Cache data
|
||||
var clientRect = new Rectangle(Vector2.Zero, Size);
|
||||
@@ -413,7 +478,7 @@ namespace FlaxEngine.GUI
|
||||
backgroundColor *= 0.5f;
|
||||
arrowColor *= 0.7f;
|
||||
}
|
||||
else if (isOpened || _mouseDown)
|
||||
else if (isOpened || _touchDown)
|
||||
{
|
||||
backgroundColor = BackgroundColorSelected;
|
||||
borderColor = BorderColorSelected;
|
||||
@@ -448,17 +513,15 @@ namespace FlaxEngine.GUI
|
||||
/// <inheritdoc />
|
||||
public override void OnLostFocus()
|
||||
{
|
||||
base.OnLostFocus();
|
||||
_touchDown = false;
|
||||
|
||||
// Clear flags
|
||||
_mouseDown = false;
|
||||
base.OnLostFocus();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseLeave()
|
||||
{
|
||||
// Clear flags
|
||||
_mouseDown = false;
|
||||
_touchDown = false;
|
||||
|
||||
base.OnMouseLeave();
|
||||
}
|
||||
@@ -466,59 +529,60 @@ namespace FlaxEngine.GUI
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Vector2 location, MouseButton button)
|
||||
{
|
||||
// Check mouse buttons
|
||||
if (base.OnMouseDown(location, button))
|
||||
return true;
|
||||
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
// Set flag
|
||||
_mouseDown = true;
|
||||
_touchDown = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseDown(location, button);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Vector2 location, MouseButton button)
|
||||
{
|
||||
// Check flags
|
||||
if (_mouseDown)
|
||||
if (_touchDown && button == MouseButton.Left)
|
||||
{
|
||||
// Clear flag
|
||||
_mouseDown = false;
|
||||
|
||||
var root = Root;
|
||||
if (_items.Count > 0 && root != null)
|
||||
{
|
||||
// Setup popup
|
||||
DestroyPopup();
|
||||
_popup = CreatePopup();
|
||||
|
||||
// Update layout
|
||||
_popup.UnlockChildrenRecursive();
|
||||
_popup.PerformLayout();
|
||||
|
||||
// Bind events
|
||||
_popup.ItemClicked += (index) =>
|
||||
{
|
||||
OnItemClicked(index);
|
||||
DestroyPopup();
|
||||
};
|
||||
_popup.LostFocus += DestroyPopup;
|
||||
|
||||
// Show dropdown popup
|
||||
Vector2 locationRootSpace = Location + new Vector2(0, Height);
|
||||
var parent = Parent;
|
||||
while (parent != null && parent != Root)
|
||||
{
|
||||
locationRootSpace = parent.PointToParent(ref location);
|
||||
parent = parent.Parent;
|
||||
}
|
||||
_popup.Location = locationRootSpace;
|
||||
_popup.Parent = root;
|
||||
_popup.Focus();
|
||||
}
|
||||
_touchDown = false;
|
||||
ShowPopup();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnTouchDown(Vector2 location, int pointerId)
|
||||
{
|
||||
if (base.OnTouchDown(location, pointerId))
|
||||
return true;
|
||||
|
||||
_touchDown = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnTouchUp(Vector2 location, int pointerId)
|
||||
{
|
||||
if (base.OnTouchUp(location, pointerId))
|
||||
return true;
|
||||
|
||||
if (_touchDown)
|
||||
{
|
||||
ShowPopup();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnTouchLeave(int pointerId)
|
||||
{
|
||||
_touchDown = false;
|
||||
|
||||
base.OnTouchLeave(pointerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ namespace FlaxEngine.GUI
|
||||
/// <summary>
|
||||
/// Gets the control DPI scale factor (1 is default). Includes custom DPI scale.
|
||||
/// </summary>
|
||||
public float DpiScale => _root?.RootWindow?.Window.DpiScale ?? Platform.DpiScale;
|
||||
public float DpiScale => RootWindow?.Window.DpiScale ?? Platform.DpiScale;
|
||||
|
||||
/// <summary>
|
||||
/// Gets screen position of the control (upper left corner).
|
||||
@@ -456,9 +456,9 @@ namespace FlaxEngine.GUI
|
||||
#region Focus
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the control can receive automatic focus on user events (eg. mouse down.
|
||||
/// Gets a value indicating whether the control can receive automatic focus on user events (eg. mouse down).
|
||||
/// </summary>
|
||||
[HideInEditor]
|
||||
[HideInEditor, NoSerialize]
|
||||
public bool AutoFocus
|
||||
{
|
||||
get => _autoFocus;
|
||||
|
||||
@@ -211,6 +211,17 @@ namespace FlaxEngine.Utilities
|
||||
/// <returns>A <see cref="bool"/> thats either true or false.</returns>
|
||||
public static bool NextBool(this Random random, float weight = 0.5f) => random.NextDouble() < weight;
|
||||
|
||||
/// <summary>
|
||||
/// Generates a random <see cref="byte"/> value up until an exclusive maximum.
|
||||
/// </summary>
|
||||
/// <param name="random">An instance of <see cref="Random"/>.</param>
|
||||
/// <param name="max">The maximum value. If it's zero, a maximum of 256 is used</param>
|
||||
/// <returns>A random <see cref="byte"/> between min and max.</returns>
|
||||
public static byte NextByte(this Random random, byte max = 0)
|
||||
{
|
||||
return max == 0 ? (byte)(random.Next() % 256) : (byte)random.Next(max);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a random <see cref="byte"/> value between min and max.
|
||||
/// </summary>
|
||||
@@ -218,9 +229,9 @@ namespace FlaxEngine.Utilities
|
||||
/// <param name="min">The minimum value.</param>
|
||||
/// <param name="max">The maximum value.</param>
|
||||
/// <returns>A random <see cref="byte"/> between min and max.</returns>
|
||||
public static byte NextByte(this Random random, byte min = 0, byte max = byte.MaxValue)
|
||||
public static byte NextByte(this Random random, byte min, byte max)
|
||||
{
|
||||
return (byte)random.Next(min, max == byte.MaxValue ? byte.MaxValue + 1 : max);
|
||||
return (byte)random.Next(min, max);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libcurl.a
(Stored with Git LFS)
vendored
Normal file
BIN
Source/Platforms/Linux/Binaries/ThirdParty/x64/libcurl.a
(Stored with Git LFS)
vendored
Normal file
Binary file not shown.
8
Source/ThirdParty/OpenFBX/ofbx.cpp
vendored
8
Source/ThirdParty/OpenFBX/ofbx.cpp
vendored
@@ -3172,6 +3172,8 @@ static bool parseObjects(const Element& root, Scene* scene, u64 flags, Allocator
|
||||
node->bone_link_property = con.property;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (parent->getType())
|
||||
@@ -3190,6 +3192,8 @@ static bool parseObjects(const Element& root, Scene* scene, u64 flags, Allocator
|
||||
mesh->geometry = (Geometry*)child;
|
||||
break;
|
||||
case Object::Type::MATERIAL: mesh->materials.push_back((Material*)child); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -3323,6 +3327,8 @@ static bool parseObjects(const Element& root, Scene* scene, u64 flags, Allocator
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3350,6 +3356,8 @@ static bool parseObjects(const Element& root, Scene* scene, u64 flags, Allocator
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2
Source/ThirdParty/curl/curl.Build.cs
vendored
2
Source/ThirdParty/curl/curl.Build.cs
vendored
@@ -38,7 +38,7 @@ public class curl : DepsModule
|
||||
options.OutputFiles.Add("crypt32.lib");
|
||||
break;
|
||||
case TargetPlatform.Linux:
|
||||
options.Libraries.Add("curl");
|
||||
options.OutputFiles.Add(Path.Combine(depsRoot, "libcurl.a"));
|
||||
break;
|
||||
default: throw new InvalidPlatformException(options.Platform.Target);
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ namespace Flax.Build
|
||||
// Get all modules aggregated into all binary modules used in all configurations of this target
|
||||
foreach (var configurationData in mainProject.Configurations)
|
||||
{
|
||||
var configurationBinaryModules = GetBinaryModules(rootProject, configurationData.Target, configurationData.Modules);
|
||||
var configurationBinaryModules = GetBinaryModules(projectInfo, configurationData.Target, configurationData.Modules);
|
||||
foreach (var configurationBinaryModule in configurationBinaryModules)
|
||||
{
|
||||
// Skip if none of the included binary modules is inside the project workspace (eg. merged external binary modules from engine to game project)
|
||||
@@ -274,7 +274,7 @@ namespace Flax.Build
|
||||
{
|
||||
var referenceBuildOptions = GetBuildOptions(referenceTarget, configurationData.TargetBuildOptions.Platform, configurationData.TargetBuildOptions.Toolchain, configurationData.Architecture, configurationData.Configuration, reference.Project.ProjectFolderPath);
|
||||
var referenceModules = CollectModules(rules, referenceBuildOptions.Platform, referenceTarget, referenceBuildOptions, referenceBuildOptions.Toolchain, referenceBuildOptions.Architecture, referenceBuildOptions.Configuration);
|
||||
var referenceBinaryModules = GetBinaryModules(rootProject, referenceTarget, referenceModules);
|
||||
var referenceBinaryModules = GetBinaryModules(projectInfo, referenceTarget, referenceModules);
|
||||
foreach (var binaryModule in referenceBinaryModules)
|
||||
{
|
||||
project.Defines.Add(binaryModule.Key.ToUpperInvariant() + "_API=");
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
@@ -25,6 +26,11 @@ namespace Flax.Deps.Dependencies
|
||||
{
|
||||
TargetPlatform.Windows,
|
||||
};
|
||||
case TargetPlatform.Linux:
|
||||
return new[]
|
||||
{
|
||||
TargetPlatform.Linux,
|
||||
};
|
||||
default: return new TargetPlatform[0];
|
||||
}
|
||||
}
|
||||
@@ -76,7 +82,37 @@ namespace Flax.Deps.Dependencies
|
||||
foreach (var filename in binariesToCopyWin)
|
||||
Utilities.FileCopy(Path.Combine(root, "build", "Win64", vcVersion, configuration, filename), Path.Combine(depsFolder, Path.GetFileName(filename)));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case TargetPlatform.Linux:
|
||||
{
|
||||
// Build for Linux
|
||||
var settings = new []
|
||||
{
|
||||
"-without-librtmp",
|
||||
"--without-ssl",
|
||||
"--with-gnutls",
|
||||
"--disable-ipv6",
|
||||
"--disable-manual",
|
||||
"--disable-verbose",
|
||||
"--disable-shared",
|
||||
"--enable-static",
|
||||
"-disable-ldap --disable-sspi --disable-ftp --disable-file --disable-dict --disable-telnet --disable-tftp --disable-rtsp --disable-pop3 --disable-imap --disable-smtp --disable-gopher --disable-smb",
|
||||
};
|
||||
var envVars = new Dictionary<string, string>
|
||||
{
|
||||
{ "CC", "clang-7" },
|
||||
{ "CC_FOR_BUILD", "clang-7" }
|
||||
};
|
||||
var buildDir = Path.Combine(root, "build");
|
||||
SetupDirectory(buildDir, true);
|
||||
Utilities.Run("chmod", "+x configure", null, root, Utilities.RunOptions.None);
|
||||
Utilities.Run(Path.Combine(root, "configure"), string.Join(" ", settings) + " --prefix=\"" + buildDir + "\"", null, root, Utilities.RunOptions.None, envVars);
|
||||
Utilities.Run("make", null, null, root, Utilities.RunOptions.None);
|
||||
Utilities.Run("make", "install", null, root, Utilities.RunOptions.None);
|
||||
var depsFolder = GetThirdPartyFolder(options, TargetPlatform.Linux, TargetArchitecture.x64);
|
||||
var filename = "libcurl.a";
|
||||
Utilities.FileCopy(Path.Combine(buildDir, "lib", filename), Path.Combine(depsFolder, filename));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,9 +143,9 @@
|
||||
|
||||
<!-- StringBuilder -->
|
||||
<Type Name="StringBuilder">
|
||||
<DisplayString>{_data_allocation.._data,su}</DisplayString>
|
||||
<DisplayString>{_data._allocation._data,su}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[Raw]" ExcludeView="simple">_data._data</Item>
|
||||
<Item Name="[Raw]" ExcludeView="simple">_data._allocation._data</Item>
|
||||
<Item Name="[Size]" ExcludeView="simple">_data._count</Item>
|
||||
<ArrayItems>
|
||||
<Size>_data._count</Size>
|
||||
|
||||
Reference in New Issue
Block a user