Merge branch 'master' into lowlevel-networking
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Curve.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Animations/Curve.h"
|
||||
#include "Engine/Core/Math/Transform.h"
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
|
||||
Array<AnimatedModel*> UpdateList(256);
|
||||
Array<AnimatedModel*> UpdateList;
|
||||
Array<Matrix> UpdateBones;
|
||||
|
||||
class AnimationManagerService : public EngineService
|
||||
{
|
||||
@@ -67,10 +68,11 @@ void AnimationManagerService::Update()
|
||||
}
|
||||
animatedModel->GraphInstance.LastUpdateTime = t;
|
||||
|
||||
const auto bones = graph->GraphExecutor.Update(animatedModel->GraphInstance, dt);
|
||||
const bool usePrevFrameBones = animatedModel->PerBoneMotionBlur;
|
||||
animatedModel->_skinningData.SetData(bones, !usePrevFrameBones);
|
||||
animatedModel->OnAnimUpdate();
|
||||
// Evaluate animated nodes pose
|
||||
graph->GraphExecutor.Update(animatedModel->GraphInstance, dt);
|
||||
|
||||
// Update gameplay
|
||||
animatedModel->OnAnimationUpdated();
|
||||
}
|
||||
}
|
||||
UpdateList.Clear();
|
||||
@@ -79,6 +81,7 @@ void AnimationManagerService::Update()
|
||||
void AnimationManagerService::Dispose()
|
||||
{
|
||||
UpdateList.Resize(0);
|
||||
UpdateBones.Resize(0);
|
||||
}
|
||||
|
||||
void AnimationManager::AddToUpdate(AnimatedModel* obj)
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace AnimationUtils
|
||||
FORCE_INLINE void GetTangent<Quaternion>(const Quaternion& a, const Quaternion& b, float length, Quaternion& result)
|
||||
{
|
||||
const float oneThird = 1.0f / 3.0f;
|
||||
Quaternion::Slerp(a, b, length * oneThird, result);
|
||||
Quaternion::Slerp(a, b, oneThird, result);
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -79,7 +79,7 @@ namespace AnimationUtils
|
||||
const float oneThird = 1.0f / 3.0f;
|
||||
const float oneThirdLength = length * oneThird;
|
||||
result.Translation = a.Translation + b.Translation * oneThirdLength;
|
||||
Quaternion::Slerp(a.Orientation, b.Orientation, oneThirdLength, result.Orientation);
|
||||
Quaternion::Slerp(a.Orientation, b.Orientation, oneThird, result.Orientation);
|
||||
result.Scale = a.Scale + (b.Scale - a.Scale) * oneThirdLength;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/MException.h"
|
||||
#include "Engine/Content/Assets/SkinnedModel.h"
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||
|
||||
struct InternalInitData
|
||||
@@ -144,6 +145,17 @@ void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value&
|
||||
box->Cache = value;
|
||||
}
|
||||
|
||||
bool AnimGraph::IsReady() const
|
||||
{
|
||||
return BaseModel && BaseModel->IsLoaded();
|
||||
}
|
||||
|
||||
bool AnimGraph::CanUseWithSkeleton(SkinnedModel* other) const
|
||||
{
|
||||
// All data loaded and nodes count the same
|
||||
return IsReady() && other && other->IsLoaded() && other->Skeleton.Nodes.Count() == BaseModel->Skeleton.Nodes.Count();
|
||||
}
|
||||
|
||||
void AnimGraph::ClearCustomNode(Node* node)
|
||||
{
|
||||
// Clear data
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "AnimGraph.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Content/Assets/SkinnedModel.h"
|
||||
#include "Engine/Graphics/Models/SkeletonData.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
|
||||
RootMotionData RootMotionData::Identity = { Vector3(0.0f), Quaternion(0.0f, 0.0f, 0.0f, 1.0f) };
|
||||
|
||||
@@ -173,7 +175,7 @@ AnimGraphExecutor::AnimGraphExecutor(AnimGraph& graph)
|
||||
_perGroupProcessCall[16] = (ProcessBoxHandler)&AnimGraphExecutor::ProcessGroupFunction;
|
||||
}
|
||||
|
||||
const Matrix* AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
|
||||
void AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
|
||||
{
|
||||
ASSERT(data.Parameters.Count() == _graph.Parameters.Count());
|
||||
|
||||
@@ -183,7 +185,6 @@ const Matrix* AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
|
||||
ANIM_GRAPH_PROFILE_EVENT("Init");
|
||||
|
||||
// Prepare graph data for the evaluation
|
||||
_skeletonBonesCount = skeleton.Bones.Count();
|
||||
_skeletonNodesCount = skeleton.Nodes.Count();
|
||||
_graphStack.Clear();
|
||||
_graphStack.Push((Graph*)&_graph);
|
||||
@@ -263,23 +264,19 @@ const Matrix* AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
|
||||
_data->RootMotion = animResult->RootMotion;
|
||||
}
|
||||
|
||||
// Calculate the final bones transformations
|
||||
{
|
||||
ANIM_GRAPH_PROFILE_EVENT("Final Pose");
|
||||
|
||||
_bonesTransformations.Resize(_skeletonBonesCount, false);
|
||||
|
||||
for (int32 boneIndex = 0; boneIndex < _skeletonBonesCount; boneIndex++)
|
||||
{
|
||||
auto& bone = skeleton.Bones[boneIndex];
|
||||
_bonesTransformations[boneIndex] = bone.OffsetMatrix * _data->NodesPose[bone.NodeIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
return _bonesTransformations.Get();
|
||||
void AnimGraphExecutor::GetInputValue(Box* box, Value& result)
|
||||
{
|
||||
result = eatBox(box->GetParent<Node>(), box->FirstConnection());
|
||||
}
|
||||
|
||||
void AnimGraphExecutor::ResetBucket(int32 bucketIndex)
|
||||
{
|
||||
auto& stateBucket = _data->State[bucketIndex];
|
||||
_graph._bucketInitializerList[bucketIndex](stateBucket);
|
||||
}
|
||||
|
||||
void AnimGraphExecutor::ResetBuckets(AnimGraphBase* graph)
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Visject/VisjectGraph.h"
|
||||
#include "Engine/Content/Assets/SkinnedModel.h"
|
||||
#include "Engine/Content/Assets/Animation.h"
|
||||
#include "Engine/Animations/AlphaBlend.h"
|
||||
#include "Engine/Core/Math/Matrix.h"
|
||||
#include "../Config.h"
|
||||
|
||||
#define ANIM_GRAPH_PARAM_BASE_MODEL_ID Guid(1000, 0, 0, 0)
|
||||
@@ -21,6 +21,8 @@ class AnimSubGraph;
|
||||
class AnimGraphBase;
|
||||
class AnimGraphNode;
|
||||
class AnimGraphExecutor;
|
||||
class SkinnedModel;
|
||||
class SkeletonData;
|
||||
|
||||
/// <summary>
|
||||
/// The root motion data container. Supports displacement and rotation (no scale component).
|
||||
@@ -777,22 +779,14 @@ public:
|
||||
/// <summary>
|
||||
/// Determines whether this graph is ready for the animation evaluation.
|
||||
/// </summary>
|
||||
/// <returns>True if is ready and can be used for the animation evaluation, otherwise false.</returns>
|
||||
bool IsReady() const
|
||||
{
|
||||
return BaseModel && BaseModel->IsLoaded();
|
||||
}
|
||||
bool IsReady() const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this graph can be used with the specified skeleton.
|
||||
/// </summary>
|
||||
/// <param name="other">The other skinned model to check.</param>
|
||||
/// <returns>True if can perform the update, otherwise false.</returns>
|
||||
bool CanUseWithSkeleton(SkinnedModel* other) const
|
||||
{
|
||||
// All data loaded and bones count the same
|
||||
return IsReady() && other && other->IsLoaded() && other->Skeleton.Bones.Count() == BaseModel->Skeleton.Bones.Count();
|
||||
}
|
||||
bool CanUseWithSkeleton(SkinnedModel* other) const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -823,12 +817,10 @@ private:
|
||||
AnimGraph& _graph;
|
||||
float _deltaTime = 0.0f;
|
||||
uint64 _currentFrameIndex = 0;
|
||||
int32 _skeletonBonesCount = 0;
|
||||
int32 _skeletonNodesCount = 0;
|
||||
RootMotionMode _rootMotionMode = RootMotionMode::NoExtraction;
|
||||
AnimGraphInstanceData* _data = nullptr;
|
||||
AnimGraphImpulse _emptyNodes;
|
||||
Array<Matrix> _bonesTransformations;
|
||||
AnimGraphTransitionData _transitionData;
|
||||
Array<Node*, FixedAllocation<ANIM_GRAPH_MAX_CALL_STACK>> _callStack;
|
||||
Array<Graph*, FixedAllocation<32>> _graphStack;
|
||||
@@ -859,18 +851,13 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="data">The instance data.</param>
|
||||
/// <param name="dt">The delta time (in seconds).</param>
|
||||
/// <returns>The pointer to the final bones structure as a result of the animation evaluation.</returns>
|
||||
const Matrix* Update(AnimGraphInstanceData& data, float dt);
|
||||
void Update(AnimGraphInstanceData& data, float dt);
|
||||
|
||||
void GetInputValue(Box* box, Value& result)
|
||||
{
|
||||
result = eatBox(box->GetParent<Node>(), box->FirstConnection());
|
||||
}
|
||||
void GetInputValue(Box* box, Value& result);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the skeleton nodes transformations structure containing identity matrices.
|
||||
/// </summary>
|
||||
/// <returns>The data.</returns>
|
||||
FORCE_INLINE const AnimGraphImpulse* GetEmptyNodes() const
|
||||
{
|
||||
return &_emptyNodes;
|
||||
@@ -920,11 +907,7 @@ public:
|
||||
/// Resets the state bucket.
|
||||
/// </summary>
|
||||
/// <param name="bucketIndex">The zero-based index of the bucket.</param>
|
||||
FORCE_INLINE void ResetBucket(int32 bucketIndex)
|
||||
{
|
||||
auto& stateBucket = _data->State[bucketIndex];
|
||||
_graph._bucketInitializerList[bucketIndex](stateBucket);
|
||||
}
|
||||
void ResetBucket(int32 bucketIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Resets all the state bucket used by the given graph including sub-graphs (total). Can eb used to reset the animation state of the nested graph (including children).
|
||||
|
||||
@@ -451,7 +451,69 @@ void AnimGraphExecutor::ProcessGroupParameters(Box* box, Node* node, Value& valu
|
||||
// Get parameter
|
||||
int32 paramIndex;
|
||||
const auto param = _graph.GetParameter((Guid)node->Values[0], paramIndex);
|
||||
value = param ? _data->Parameters[paramIndex].Value : Value::Null;
|
||||
if (param)
|
||||
{
|
||||
value = _data->Parameters[paramIndex].Value;
|
||||
switch (param->Type.Type)
|
||||
{
|
||||
case VariantType::Vector2:
|
||||
switch (box->ID)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
value = value.AsVector2().Raw[box->ID - 1];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VariantType::Vector3:
|
||||
switch (box->ID)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
value = value.AsVector3().Raw[box->ID - 1];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VariantType::Vector4:
|
||||
case VariantType::Color:
|
||||
switch (box->ID)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
value = value.AsVector4().Raw[box->ID - 1];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case VariantType::Matrix:
|
||||
{
|
||||
auto& matrix = value.Type.Type == VariantType::Matrix && value.AsBlob.Data ? *(Matrix*)value.AsBlob.Data : Matrix::Identity;
|
||||
switch (box->ID)
|
||||
{
|
||||
case 0:
|
||||
value = matrix.GetRow1();
|
||||
break;
|
||||
case 1:
|
||||
value = matrix.GetRow2();
|
||||
break;
|
||||
case 2:
|
||||
value = matrix.GetRow3();
|
||||
break;
|
||||
case 3:
|
||||
value = matrix.GetRow4();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: add warning that no parameter selected
|
||||
value = Value::Zero;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -574,7 +636,8 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
transform.Scale = (Vector3)tryGetValue(node->GetBox(4), Vector3::One);
|
||||
|
||||
// Skip if no change will be performed
|
||||
if (boneIndex < 0 || boneIndex >= _skeletonBonesCount || transformMode == BoneTransformMode::None || transform.IsIdentity())
|
||||
auto& skeleton = _graph.BaseModel->Skeleton;
|
||||
if (boneIndex < 0 || boneIndex >= skeleton.Bones.Count() || transformMode == BoneTransformMode::None || (transformMode == BoneTransformMode::Add && transform.IsIdentity()))
|
||||
{
|
||||
// Pass through the input
|
||||
value = Value::Null;
|
||||
@@ -705,8 +768,9 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
const auto copyScale = (bool)node->Values[4];
|
||||
|
||||
// Skip if no change will be performed
|
||||
if (srcBoneIndex < 0 || srcBoneIndex >= _skeletonBonesCount ||
|
||||
dstBoneIndex < 0 || dstBoneIndex >= _skeletonBonesCount ||
|
||||
const auto& skeleton = _graph.BaseModel->Skeleton;
|
||||
if (srcBoneIndex < 0 || srcBoneIndex >= skeleton.Bones.Count() ||
|
||||
dstBoneIndex < 0 || dstBoneIndex >= skeleton.Bones.Count() ||
|
||||
!(copyTranslation || copyRotation || copyScale))
|
||||
{
|
||||
// Pass through the input
|
||||
@@ -714,7 +778,6 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
box->Cache = value;
|
||||
return;
|
||||
}
|
||||
const auto& skeleton = _graph.BaseModel->Skeleton;
|
||||
|
||||
// Copy bone data
|
||||
Transform srcTransform = nodes->Nodes[skeleton.Bones[srcBoneIndex].NodeIndex];
|
||||
@@ -738,7 +801,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
const auto boneIndex = (int32)node->Values[0];
|
||||
const auto& skeleton = _graph.BaseModel->Skeleton;
|
||||
const auto input = tryGetValue(node->GetBox(0), Value::Null);
|
||||
if (ANIM_GRAPH_IS_VALID_PTR(input) && boneIndex >= 0 && boneIndex < _skeletonBonesCount)
|
||||
if (ANIM_GRAPH_IS_VALID_PTR(input) && boneIndex >= 0 && boneIndex < skeleton.Bones.Count())
|
||||
value = Variant(((AnimGraphImpulse*)input.AsPointer)->Nodes[skeleton.Bones[boneIndex].NodeIndex]);
|
||||
else
|
||||
value = Variant(Transform::Identity);
|
||||
@@ -1566,7 +1629,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
transform.Scale = (Vector3)tryGetValue(node->GetBox(4), Vector3::One);
|
||||
|
||||
// Skip if no change will be performed
|
||||
if (nodeIndex < 0 || nodeIndex >= _skeletonNodesCount || transformMode == BoneTransformMode::None || transform.IsIdentity())
|
||||
if (nodeIndex < 0 || nodeIndex >= _skeletonNodesCount || transformMode == BoneTransformMode::None || (transformMode == BoneTransformMode::Add && transform.IsIdentity()))
|
||||
{
|
||||
// Pass through the input
|
||||
value = Value::Null;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "Engine/Audio/AudioClip.h"
|
||||
#include "Engine/Graphics/PostProcessSettings.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(SceneAnimation, "FlaxEngine.SceneAnimation", nullptr, false);
|
||||
REGISTER_BINARY_ASSET(SceneAnimation, "FlaxEngine.SceneAnimation", false);
|
||||
|
||||
SceneAnimation::SceneAnimation(const SpawnParams& params, const AssetInfo* info)
|
||||
: BinaryAsset(params, info)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Audio/AudioClip.h"
|
||||
#include "Engine/Audio/AudioSource.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Renderer/RenderList.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/Script.h"
|
||||
@@ -1132,6 +1133,6 @@ void SceneAnimationPlayer::OnTransformChanged()
|
||||
// Base
|
||||
Actor::OnTransformChanged();
|
||||
|
||||
_box = BoundingBox(_transform.Translation, _transform.Translation);
|
||||
_box = BoundingBox(_transform.Translation);
|
||||
_sphere = BoundingSphere(_transform.Translation, 0.0f);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Level/Actor.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Level/Actors/PostFxVolume.h"
|
||||
#include "SceneAnimation.h"
|
||||
|
||||
@@ -48,8 +48,7 @@ public class Audio : EngineModule
|
||||
break;
|
||||
case TargetPlatform.Switch:
|
||||
options.SourcePaths.Add(Path.Combine(Globals.EngineRoot, "Source", "Platforms", "Switch", "Engine", "Audio"));
|
||||
//options.CompileEnv.PreprocessorDefinitions.Add("AUDIO_API_SWITCH"); // TODO: impl audio on switch
|
||||
useNone = true;
|
||||
options.CompileEnv.PreprocessorDefinitions.Add("AUDIO_API_SWITCH");
|
||||
break;
|
||||
default: throw new InvalidPlatformException(options.Platform.Target);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Audio.h"
|
||||
#include "AudioSource.h"
|
||||
#include "AudioBackend.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Content/Upgraders/AudioClipUpgrader.h"
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
@@ -12,7 +13,7 @@
|
||||
#include "Engine/Tools/AudioTool/OggVorbisDecoder.h"
|
||||
#include "Engine/Tools/AudioTool/AudioTool.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(AudioClip, "FlaxEngine.AudioClip", ::New<AudioClipUpgrader>(), false);
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(AudioClip, "FlaxEngine.AudioClip", AudioClipUpgrader, false);
|
||||
|
||||
bool AudioClip::StreamingTask::Run()
|
||||
{
|
||||
|
||||
@@ -63,7 +63,7 @@ void AudioListener::OnTransformChanged()
|
||||
// Base
|
||||
Actor::OnTransformChanged();
|
||||
|
||||
_box = BoundingBox(_transform.Translation, _transform.Translation);
|
||||
_box = BoundingBox(_transform.Translation);
|
||||
_sphere = BoundingSphere(_transform.Translation, 0.0f);
|
||||
|
||||
if (IsActiveInHierarchy())
|
||||
|
||||
@@ -461,7 +461,7 @@ void AudioSource::OnTransformChanged()
|
||||
// Base
|
||||
Actor::OnTransformChanged();
|
||||
|
||||
_box = BoundingBox(_transform.Translation, _transform.Translation);
|
||||
_box = BoundingBox(_transform.Translation);
|
||||
_sphere = BoundingSphere(_transform.Translation, 0.0f);
|
||||
|
||||
if (IsActiveInHierarchy() && SourceIDs.HasItems())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Engine/Level/SceneQuery.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Graphics/Models/ModelData.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Assets/Model.h"
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/BaseTypes.h"
|
||||
|
||||
namespace CSG
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -38,9 +38,10 @@ void Asset::OnDeleteObject()
|
||||
if (!IsInternalType())
|
||||
Content::AssetDisposing(this);
|
||||
|
||||
// Cache data
|
||||
const bool wasMarkedToDelete = _deleteFileOnUnload != 0;
|
||||
#if USE_EDITOR
|
||||
const String path = wasMarkedToDelete ? GetPath() : String::Empty;
|
||||
#endif
|
||||
const Guid id = GetID();
|
||||
|
||||
// Fire unload event (every object referencing this asset or it's data should release reference so later actions are safe)
|
||||
@@ -66,7 +67,7 @@ void Asset::OnDeleteObject()
|
||||
// Base (after it `this` is invalid)
|
||||
ManagedScriptingObject::OnDeleteObject();
|
||||
|
||||
// Check if asset was marked to delete
|
||||
#if USE_EDITOR
|
||||
if (wasMarkedToDelete)
|
||||
{
|
||||
LOG(Info, "Deleting asset '{0}':{1}.", path, id.ToString());
|
||||
@@ -77,6 +78,7 @@ void Asset::OnDeleteObject()
|
||||
// Delete file
|
||||
Content::deleteFileSafety(path, id);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Asset::CreateManaged()
|
||||
@@ -131,6 +133,20 @@ void Asset::ChangeID(const Guid& newId)
|
||||
CRASH;
|
||||
}
|
||||
|
||||
bool Asset::LastLoadFailed() const
|
||||
{
|
||||
return _loadFailed != 0;
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
bool Asset::ShouldDeleteFileOnUnload() const
|
||||
{
|
||||
return _deleteFileOnUnload != 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Asset::Reload()
|
||||
{
|
||||
// It's better to call it from the main thread
|
||||
@@ -225,7 +241,7 @@ bool Asset::WaitForLoaded(double timeoutInMilliseconds)
|
||||
while (!Engine::ShouldExit())
|
||||
{
|
||||
// Try to execute content tasks
|
||||
while (task->IsQueued())
|
||||
while (task->IsQueued() && !Engine::ShouldExit())
|
||||
{
|
||||
// Pick this task from the queue
|
||||
ContentLoadTask* tmp;
|
||||
@@ -335,13 +351,21 @@ void Asset::startLoading()
|
||||
bool Asset::onLoad(LoadAssetTask* task)
|
||||
{
|
||||
// It may fail when task is cancelled and new one is created later (don't crash but just end with an error)
|
||||
if (task->GetAsset() != this || _loadingTask == nullptr)
|
||||
if (task->Asset.Get() != this || _loadingTask == nullptr)
|
||||
return true;
|
||||
|
||||
Locker.Lock();
|
||||
|
||||
// Load asset
|
||||
const LoadResult result = loadAsset();
|
||||
LoadResult result;
|
||||
{
|
||||
#if TRACY_ENABLE
|
||||
ZoneScoped;
|
||||
const StringView name(GetPath());
|
||||
ZoneName(*name, name.Length());
|
||||
#endif
|
||||
result = loadAsset();
|
||||
}
|
||||
const bool isLoaded = result == LoadResult::Ok;
|
||||
const bool failed = !isLoaded;
|
||||
_loadFailed = failed;
|
||||
|
||||
@@ -82,7 +82,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets asset's reference count. Asset will be automatically unloaded when this reaches zero.
|
||||
/// </summary>
|
||||
/// <returns>The amount of references to that asset.</returns>
|
||||
API_PROPERTY() int32 GetReferencesCount() const
|
||||
{
|
||||
return (int32)Platform::AtomicRead(const_cast<int64 volatile*>(&_refCount));
|
||||
@@ -107,21 +106,18 @@ public:
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the asset storage.
|
||||
/// Gets the path to the asset storage file. In Editor it reflects the actual file, in cooked Game, it fakes the Editor path to be informative for developers.
|
||||
/// </summary>
|
||||
/// <returns>The asset file.</returns>
|
||||
API_PROPERTY() virtual const String& GetPath() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the asset type name.
|
||||
/// </summary>
|
||||
/// <returns>The typename.</returns>
|
||||
virtual const String& GetTypeName() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if asset is loaded, otherwise false.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this asset is loaded; otherwise, <c>false</c>.</returns>
|
||||
API_PROPERTY() FORCE_INLINE bool IsLoaded() const
|
||||
{
|
||||
return _isLoaded != 0;
|
||||
@@ -130,16 +126,11 @@ public:
|
||||
/// <summary>
|
||||
/// Returns true if last asset loading failed, otherwise false.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if last asset loading failed; otherwise, <c>false</c>.</returns>
|
||||
API_PROPERTY() FORCE_INLINE bool LastLoadFailed() const
|
||||
{
|
||||
return _loadFailed != 0;
|
||||
}
|
||||
API_PROPERTY() bool LastLoadFailed() const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this asset is virtual (generated or temporary, has no storage so it won't be saved).
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this asset is virtual; otherwise, <c>false</c>.</returns>
|
||||
API_PROPERTY() FORCE_INLINE bool IsVirtual() const
|
||||
{
|
||||
return _isVirtual != 0;
|
||||
@@ -150,11 +141,7 @@ public:
|
||||
/// <summary>
|
||||
/// Determines whether this asset was marked to be deleted on unload.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if this asset file was marked to be deleted on asset unload; otherwise, <c>false</c>.</returns>
|
||||
API_PROPERTY() FORCE_INLINE bool ShouldDeleteFileOnUnload() const
|
||||
{
|
||||
return _deleteFileOnUnload != 0;
|
||||
}
|
||||
API_PROPERTY() bool ShouldDeleteFileOnUnload() const;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -274,3 +274,9 @@ public:
|
||||
OnSet(asset);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
uint32 GetHash(const AssetReference<T>& key)
|
||||
{
|
||||
return GetHash(key.GetID());
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||
#endif
|
||||
|
||||
REGISTER_BINARY_ASSET(Animation, "FlaxEngine.Animation", nullptr, false);
|
||||
REGISTER_BINARY_ASSET(Animation, "FlaxEngine.Animation", false);
|
||||
|
||||
Animation::Animation(const SpawnParams& params, const AssetInfo* info)
|
||||
: BinaryAsset(params, info)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(AnimationGraph, "FlaxEngine.AnimationGraph", nullptr, false);
|
||||
REGISTER_BINARY_ASSET(AnimationGraph, "FlaxEngine.AnimationGraph", false);
|
||||
|
||||
AnimationGraph::AnimationGraph(const SpawnParams& params, const AssetInfo* info)
|
||||
: BinaryAsset(params, info)
|
||||
@@ -74,7 +74,7 @@ BytesContainer AnimationGraph::LoadSurface()
|
||||
return result;
|
||||
}
|
||||
|
||||
LOG(Warning, "Animation Graph \'{0}\' surface data is missing.", GetPath());
|
||||
LOG(Warning, "Animation Graph \'{0}\' surface data is missing.", ToString());
|
||||
return BytesContainer();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(AnimationGraphFunction, "FlaxEngine.AnimationGraphFunction", nullptr, false);
|
||||
REGISTER_BINARY_ASSET(AnimationGraphFunction, "FlaxEngine.AnimationGraphFunction", false);
|
||||
|
||||
AnimationGraphFunction::AnimationGraphFunction(const SpawnParams& params, const AssetInfo* info)
|
||||
: BinaryAsset(params, info)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/Content/Upgraders/TextureAssetUpgrader.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(CubeTexture, "FlaxEngine.CubeTexture", ::New<TextureAssetUpgrader>(), true);
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(CubeTexture, "FlaxEngine.CubeTexture", TextureAssetUpgrader, true);
|
||||
|
||||
CubeTexture::CubeTexture(const SpawnParams& params, const AssetInfo* info)
|
||||
: TextureBase(params, info)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/Content/Upgraders/TextureAssetUpgrader.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(IESProfile, "FlaxEngine.IESProfile", ::New<TextureAssetUpgrader>(), false);
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(IESProfile, "FlaxEngine.IESProfile", TextureAssetUpgrader, false);
|
||||
|
||||
IESProfile::IESProfile(const SpawnParams& params, const AssetInfo* info)
|
||||
: TextureBase(params, info)
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include "Engine/Utilities/Encryption.h"
|
||||
#include "Engine/Tools/MaterialGenerator/MaterialGenerator.h"
|
||||
#include "Engine/ShadersCompilation/Config.h"
|
||||
#if BUILD_DEBUG
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
@@ -23,7 +26,7 @@
|
||||
/// </summary>
|
||||
#define MATERIAL_AUTO_GENERATE_MISSING_SOURCE (USE_EDITOR)
|
||||
|
||||
REGISTER_BINARY_ASSET(Material, "FlaxEngine.Material", ::New<ShaderAssetUpgrader>(), false);
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(Material, "FlaxEngine.Material", ShaderAssetUpgrader, false);
|
||||
|
||||
Material::Material(const SpawnParams& params, const AssetInfo* info)
|
||||
: ShaderAssetTypeBase<MaterialBase>(params, info)
|
||||
@@ -116,7 +119,7 @@ Asset::LoadResult Material::load()
|
||||
FlaxChunk* materialParamsChunk;
|
||||
|
||||
// Special case for Null renderer
|
||||
if (GPUDevice::Instance->GetRendererType() == RendererType::Null)
|
||||
if (IsNullRenderer())
|
||||
{
|
||||
// Hack loading
|
||||
MemoryReadStream shaderCacheStream(nullptr, 0);
|
||||
@@ -152,18 +155,16 @@ Asset::LoadResult Material::load()
|
||||
// - If material version is not supported then material cannot be loaded
|
||||
#if COMPILE_WITH_SHADER_COMPILER
|
||||
|
||||
#if BUILD_DEBUG
|
||||
// Materials force reload!
|
||||
Globals::ConvertLoadedMaterialsByForce = false;
|
||||
#endif
|
||||
|
||||
// Check if current engine has different materials version or convert it by force or has no source generated at all
|
||||
if (_shaderHeader.Material.GraphVersion != MATERIAL_GRAPH_VERSION
|
||||
|| Globals::ConvertLoadedMaterialsByForce
|
||||
#if MATERIAL_AUTO_GENERATE_MISSING_SOURCE
|
||||
|| !HasChunk(SHADER_FILE_CHUNK_SOURCE)
|
||||
#endif
|
||||
|| HasDependenciesModified()
|
||||
#if COMPILE_WITH_DEV_ENV
|
||||
// Set to true to enable force GPU shader regeneration (don't commit it)
|
||||
|| false
|
||||
#endif
|
||||
)
|
||||
{
|
||||
// Prepare
|
||||
@@ -310,7 +311,12 @@ Asset::LoadResult Material::load()
|
||||
{
|
||||
// Load material (load shader from cache, load params, setup pipeline stuff)
|
||||
MemoryReadStream shaderCacheStream(shaderCache.Data.Get(), shaderCache.Data.Length());
|
||||
_materialShader = MaterialShader::Create(GetPath(), shaderCacheStream, _shaderHeader.Material.Info);
|
||||
#if GPU_ENABLE_RESOURCE_NAMING
|
||||
const StringView name(GetPath());
|
||||
#else
|
||||
const StringView name;
|
||||
#endif
|
||||
_materialShader = MaterialShader::Create(name, shaderCacheStream, _shaderHeader.Material.Info);
|
||||
if (_materialShader == nullptr)
|
||||
{
|
||||
LOG(Warning, "Cannot load material.");
|
||||
@@ -482,7 +488,7 @@ BytesContainer Material::LoadSurface(bool createDefaultIfMissing)
|
||||
}
|
||||
}
|
||||
|
||||
LOG(Warning, "Material \'{0}\' surface data is missing.", GetPath());
|
||||
LOG(Warning, "Material \'{0}\' surface data is missing.", ToString());
|
||||
|
||||
#if COMPILE_WITH_MATERIAL_GRAPH
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#endif
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(MaterialFunction, "FlaxEngine.MaterialFunction", nullptr, false);
|
||||
REGISTER_BINARY_ASSET(MaterialFunction, "FlaxEngine.MaterialFunction", false);
|
||||
|
||||
MaterialFunction::MaterialFunction(const SpawnParams& params, const AssetInfo* info)
|
||||
: BinaryAsset(params, info)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(MaterialInstance, "FlaxEngine.MaterialInstance", ::New<MaterialInstanceUpgrader>(), true);
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(MaterialInstance, "FlaxEngine.MaterialInstance", MaterialInstanceUpgrader, true);
|
||||
|
||||
MaterialInstance::MaterialInstance(const SpawnParams& params, const AssetInfo* info)
|
||||
: MaterialBase(params, info)
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
#include "Engine/Content/Upgraders/ModelAssetUpgrader.h"
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/Graphics/RenderTools.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Graphics/Models/ModelInstanceEntry.h"
|
||||
#include "Engine/Streaming/StreamingGroup.h"
|
||||
#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
#if GPU_ENABLE_ASYNC_RESOURCES_CREATION
|
||||
#include "Engine/Threading/ThreadPoolTask.h"
|
||||
#define STREAM_TASK_BASE ThreadPoolTask
|
||||
@@ -113,7 +115,7 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_BINARY_ASSET(Model, "FlaxEngine.Model", ::New<ModelAssetUpgrader>(), true);
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(Model, "FlaxEngine.Model", ModelAssetUpgrader, true);
|
||||
|
||||
Model::Model(const SpawnParams& params, const AssetInfo* info)
|
||||
: ModelBase(params, info, StreamingGroups::Instance()->Models())
|
||||
@@ -396,21 +398,21 @@ bool Model::Save(bool withMeshDataFromGpu, const StringView& path)
|
||||
auto& meshData = meshesData[meshIndex];
|
||||
|
||||
// Vertex Buffer 0 (required)
|
||||
auto task = mesh.ExtractDataAsync(MeshBufferType::Vertex0, meshData.VB0);
|
||||
auto task = mesh.DownloadDataGPUAsync(MeshBufferType::Vertex0, meshData.VB0);
|
||||
if (task == nullptr)
|
||||
return true;
|
||||
task->Start();
|
||||
tasks.Add(task);
|
||||
|
||||
// Vertex Buffer 1 (required)
|
||||
task = mesh.ExtractDataAsync(MeshBufferType::Vertex1, meshData.VB1);
|
||||
task = mesh.DownloadDataGPUAsync(MeshBufferType::Vertex1, meshData.VB1);
|
||||
if (task == nullptr)
|
||||
return true;
|
||||
task->Start();
|
||||
tasks.Add(task);
|
||||
|
||||
// Vertex Buffer 2 (optional)
|
||||
task = mesh.ExtractDataAsync(MeshBufferType::Vertex2, meshData.VB2);
|
||||
task = mesh.DownloadDataGPUAsync(MeshBufferType::Vertex2, meshData.VB2);
|
||||
if (task)
|
||||
{
|
||||
task->Start();
|
||||
@@ -418,7 +420,7 @@ bool Model::Save(bool withMeshDataFromGpu, const StringView& path)
|
||||
}
|
||||
|
||||
// Index Buffer (required)
|
||||
task = mesh.ExtractDataAsync(MeshBufferType::Index, meshData.IB);
|
||||
task = mesh.DownloadDataGPUAsync(MeshBufferType::Index, meshData.IB);
|
||||
if (task == nullptr)
|
||||
return true;
|
||||
task->Start();
|
||||
@@ -618,6 +620,19 @@ void Model::SetupMaterialSlots(int32 slotsCount)
|
||||
}
|
||||
}
|
||||
|
||||
int32 Model::GetLODsCount() const
|
||||
{
|
||||
return LODs.Count();
|
||||
}
|
||||
|
||||
void Model::GetMeshes(Array<MeshBase*>& meshes, int32 lodIndex)
|
||||
{
|
||||
auto& lod = LODs[lodIndex];
|
||||
meshes.Resize(lod.Meshes.Count());
|
||||
for (int32 meshIndex = 0; meshIndex < lod.Meshes.Count(); meshIndex++)
|
||||
meshes[meshIndex] = &lod.Meshes[meshIndex];
|
||||
}
|
||||
|
||||
void Model::InitAsVirtual()
|
||||
{
|
||||
// Init with a single LOD and one mesh
|
||||
@@ -628,6 +643,21 @@ void Model::InitAsVirtual()
|
||||
BinaryAsset::InitAsVirtual();
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void Model::GetReferences(Array<Guid>& output) const
|
||||
{
|
||||
// Base
|
||||
BinaryAsset::GetReferences(output);
|
||||
|
||||
for (int32 i = 0; i < MaterialSlots.Count(); i++)
|
||||
{
|
||||
output.Add(MaterialSlots[i].Material.GetID());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int32 Model::GetMaxResidency() const
|
||||
{
|
||||
return LODs.Count();
|
||||
@@ -791,7 +821,7 @@ Asset::LoadResult Model::load()
|
||||
const auto thisSS = LODs[lodIndex].ScreenSize;
|
||||
if (prevSS <= thisSS)
|
||||
{
|
||||
LOG(Warning, "Model LOD {0} has invalid screen size compared to LOD {1} (asset: {2})", lodIndex, lodIndex - 1, GetPath());
|
||||
LOG(Warning, "Model LOD {0} has invalid screen size compared to LOD {1} (asset: {2})", lodIndex, lodIndex - 1, ToString());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -837,3 +867,33 @@ AssetChunksFlag Model::getChunksToPreload() const
|
||||
// Note: we don't preload any LODs here because it's done by the Streaming Manager
|
||||
return GET_CHUNK_FLAG(0);
|
||||
}
|
||||
|
||||
void ModelBase::SetupMaterialSlots(int32 slotsCount)
|
||||
{
|
||||
CHECK(slotsCount >= 0 && slotsCount < 4096);
|
||||
if (!IsVirtual() && WaitForLoaded())
|
||||
return;
|
||||
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
const int32 prevCount = MaterialSlots.Count();
|
||||
MaterialSlots.Resize(slotsCount, false);
|
||||
|
||||
// Initialize slot names
|
||||
for (int32 i = prevCount; i < slotsCount; i++)
|
||||
MaterialSlots[i].Name = String::Format(TEXT("Material {0}"), i + 1);
|
||||
}
|
||||
|
||||
MaterialSlot* ModelBase::GetSlot(const StringView& name)
|
||||
{
|
||||
MaterialSlot* result = nullptr;
|
||||
for (auto& slot : MaterialSlots)
|
||||
{
|
||||
if (slot.Name == name)
|
||||
{
|
||||
result = &slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -55,15 +55,6 @@ public:
|
||||
return LODs.HasItems();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets amount of the level of details in the model
|
||||
/// </summary>
|
||||
/// <returns>Amount of the level of details in the model</returns>
|
||||
FORCE_INLINE int32 GetLODsCount() const
|
||||
{
|
||||
return LODs.Count();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of loaded model LODs.
|
||||
/// </summary>
|
||||
@@ -237,18 +228,11 @@ public:
|
||||
|
||||
// [ModelBase]
|
||||
void SetupMaterialSlots(int32 slotsCount) override;
|
||||
int32 GetLODsCount() const override;
|
||||
void GetMeshes(Array<MeshBase*>& meshes, int32 lodIndex = 0) override;
|
||||
void InitAsVirtual() override;
|
||||
#if USE_EDITOR
|
||||
void GetReferences(Array<Guid>& output) const override
|
||||
{
|
||||
// Base
|
||||
BinaryAsset::GetReferences(output);
|
||||
|
||||
for (int32 i = 0; i < MaterialSlots.Count(); i++)
|
||||
{
|
||||
output.Add(MaterialSlots[i].Material.GetID());
|
||||
}
|
||||
}
|
||||
void GetReferences(Array<Guid>& output) const override;
|
||||
#endif
|
||||
|
||||
// [StreamableResource]
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include "Engine/Graphics/Models/MaterialSlot.h"
|
||||
#include "Engine/Streaming/StreamableResource.h"
|
||||
|
||||
class MeshBase;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for asset types that can contain a model resource.
|
||||
/// </summary>
|
||||
@@ -44,38 +46,23 @@ public:
|
||||
/// <summary>
|
||||
/// Resizes the material slots collection. Updates meshes that were using removed slots.
|
||||
/// </summary>
|
||||
API_FUNCTION() virtual void SetupMaterialSlots(int32 slotsCount)
|
||||
{
|
||||
CHECK(slotsCount >= 0 && slotsCount < 4096);
|
||||
if (!IsVirtual() && WaitForLoaded())
|
||||
return;
|
||||
|
||||
ScopeLock lock(Locker);
|
||||
|
||||
const int32 prevCount = MaterialSlots.Count();
|
||||
MaterialSlots.Resize(slotsCount, false);
|
||||
|
||||
// Initialize slot names
|
||||
for (int32 i = prevCount; i < slotsCount; i++)
|
||||
MaterialSlots[i].Name = String::Format(TEXT("Material {0}"), i + 1);
|
||||
}
|
||||
API_FUNCTION() virtual void SetupMaterialSlots(int32 slotsCount);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the material slot by the name.
|
||||
/// </summary>
|
||||
/// <param name="name">The slot name.</param>
|
||||
/// <returns>The material slot with the given name or null if cannot find it (asset may be not loaded yet).</returns>
|
||||
API_FUNCTION() MaterialSlot* GetSlot(const StringView& name)
|
||||
{
|
||||
MaterialSlot* result = nullptr;
|
||||
for (auto& slot : MaterialSlots)
|
||||
{
|
||||
if (slot.Name == name)
|
||||
{
|
||||
result = &slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
API_FUNCTION() MaterialSlot* GetSlot(const StringView& name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets amount of the level of details in the model.
|
||||
/// </summary>
|
||||
/// <returns>Amount of the level of details in the model.</returns>
|
||||
virtual int32 GetLODsCount() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the meshes for a particular LOD index.
|
||||
/// </summary>
|
||||
virtual void GetMeshes(Array<MeshBase*>& meshes, int32 lodIndex = 0) = 0;
|
||||
};
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(RawDataAsset, "FlaxEngine.RawDataAsset", nullptr, true);
|
||||
REGISTER_BINARY_ASSET(RawDataAsset, "FlaxEngine.RawDataAsset", true);
|
||||
|
||||
RawDataAsset::RawDataAsset(const SpawnParams& params, const AssetInfo* info)
|
||||
: BinaryAsset(params, info)
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
|
||||
#include "Shader.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||
#include "Engine/Content/Upgraders/ShaderAssetUpgrader.h"
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(Shader, "FlaxEngine.Shader", ::New<ShaderAssetUpgrader>(), false);
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(Shader, "FlaxEngine.Shader", ShaderAssetUpgrader, false);
|
||||
|
||||
Shader::Shader(const SpawnParams& params, const AssetInfo* info)
|
||||
: ShaderAssetTypeBase<BinaryAsset>(params, info)
|
||||
@@ -25,7 +27,7 @@ Shader::~Shader()
|
||||
Asset::LoadResult Shader::load()
|
||||
{
|
||||
// Special case for Null renderer that doesn't need shaders
|
||||
if (GPUDevice::Instance->GetRendererType() == RendererType::Null)
|
||||
if (IsNullRenderer())
|
||||
{
|
||||
return LoadResult::Ok;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "../BinaryAsset.h"
|
||||
#include "Engine/Graphics/Shaders/GPUShader.h"
|
||||
#include "Engine/Graphics/Shaders/Cache/ShaderAssetBase.h"
|
||||
|
||||
class GPUShader;
|
||||
|
||||
/// <summary>
|
||||
/// The shader asset. Contains a program that runs on the GPU and is able to perform rendering calculation using textures, vertices and other resources.
|
||||
/// </summary>
|
||||
@@ -33,7 +34,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the GPU shader object.
|
||||
/// </summary>
|
||||
/// <returns>The GPU shader object.</returns>
|
||||
FORCE_INLINE GPUShader* GetShader() const
|
||||
{
|
||||
return GPU;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/Content/Upgraders/SkeletonMaskUpgrader.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(SkeletonMask, "FlaxEngine.SkeletonMask", ::New<SkeletonMaskUpgrader>(), true);
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(SkeletonMask, "FlaxEngine.SkeletonMask", SkeletonMaskUpgrader, true);
|
||||
|
||||
SkeletonMask::SkeletonMask(const SpawnParams& params, const AssetInfo* info)
|
||||
: BinaryAsset(params, info)
|
||||
|
||||
@@ -7,12 +7,14 @@
|
||||
#include "Engine/Streaming/StreamingGroup.h"
|
||||
#include "Engine/Threading/ThreadPoolTask.h"
|
||||
#include "Engine/Graphics/RenderTools.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include "Engine/Graphics/Models/ModelInstanceEntry.h"
|
||||
#include "Engine/Graphics/Models/Config.h"
|
||||
#include "Engine/Content/WeakAssetReference.h"
|
||||
#include "Engine/Content/Factories/BinaryAssetFactory.h"
|
||||
#include "Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h"
|
||||
#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
|
||||
#include "Engine/Renderer/DrawCall.h"
|
||||
|
||||
#define CHECK_INVALID_BUFFER(buffer) \
|
||||
if (buffer->IsValidFor(this) == false) \
|
||||
@@ -106,7 +108,7 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_BINARY_ASSET(SkinnedModel, "FlaxEngine.SkinnedModel", ::New<SkinnedModelAssetUpgrader>(), true);
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(SkinnedModel, "FlaxEngine.SkinnedModel", SkinnedModelAssetUpgrader, true);
|
||||
|
||||
SkinnedModel::SkinnedModel(const SpawnParams& params, const AssetInfo* info)
|
||||
: ModelBase(params, info, StreamingGroups::Instance()->SkinnedModels())
|
||||
@@ -120,6 +122,11 @@ SkinnedModel::~SkinnedModel()
|
||||
ASSERT(_streamingTask == nullptr);
|
||||
}
|
||||
|
||||
bool SkinnedModel::HasAnyLODInitialized() const
|
||||
{
|
||||
return LODs.HasItems() && LODs.Last().HasAnyMeshInitialized();
|
||||
}
|
||||
|
||||
Array<String> SkinnedModel::GetBlendShapes()
|
||||
{
|
||||
Array<String> result;
|
||||
@@ -137,6 +144,18 @@ Array<String> SkinnedModel::GetBlendShapes()
|
||||
return result;
|
||||
}
|
||||
|
||||
ContentLoadTask* SkinnedModel::RequestLODDataAsync(int32 lodIndex)
|
||||
{
|
||||
const int32 chunkIndex = SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
|
||||
return RequestChunkDataAsync(chunkIndex);
|
||||
}
|
||||
|
||||
void SkinnedModel::GetLODData(int32 lodIndex, BytesContainer& data) const
|
||||
{
|
||||
const int32 chunkIndex = SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
|
||||
GetChunkData(chunkIndex, data);
|
||||
}
|
||||
|
||||
bool SkinnedModel::Intersects(const Ray& ray, const Matrix& world, float& distance, Vector3& normal, SkinnedMesh** mesh, int32 lodIndex)
|
||||
{
|
||||
return LODs[lodIndex].Intersects(ray, world, distance, normal, mesh);
|
||||
@@ -389,7 +408,7 @@ bool SkinnedModel::Save(bool withMeshDataFromGpu, const StringView& path)
|
||||
{
|
||||
auto& slot = MaterialSlots[materialSlotIndex];
|
||||
|
||||
const auto id =slot.Material.GetID();
|
||||
const auto id = slot.Material.GetID();
|
||||
stream->Write(&id);
|
||||
stream->WriteByte(static_cast<byte>(slot.ShadowsMode));
|
||||
stream->WriteString(slot.Name, 11);
|
||||
@@ -505,14 +524,14 @@ bool SkinnedModel::Save(bool withMeshDataFromGpu, const StringView& path)
|
||||
auto& meshData = meshesData[meshIndex];
|
||||
|
||||
// Vertex Buffer 0 (required)
|
||||
auto task = mesh.DownloadDataAsyncGPU(MeshBufferType::Vertex0, meshData.VB0);
|
||||
auto task = mesh.DownloadDataGPUAsync(MeshBufferType::Vertex0, meshData.VB0);
|
||||
if (task == nullptr)
|
||||
return true;
|
||||
task->Start();
|
||||
tasks.Add(task);
|
||||
|
||||
// Index Buffer (required)
|
||||
task = mesh.DownloadDataAsyncGPU(MeshBufferType::Index, meshData.IB);
|
||||
task = mesh.DownloadDataGPUAsync(MeshBufferType::Index, meshData.IB);
|
||||
if (task == nullptr)
|
||||
return true;
|
||||
task->Start();
|
||||
@@ -701,6 +720,19 @@ void SkinnedModel::SetupMaterialSlots(int32 slotsCount)
|
||||
}
|
||||
}
|
||||
|
||||
int32 SkinnedModel::GetLODsCount() const
|
||||
{
|
||||
return LODs.Count();
|
||||
}
|
||||
|
||||
void SkinnedModel::GetMeshes(Array<MeshBase*>& meshes, int32 lodIndex)
|
||||
{
|
||||
auto& lod = LODs[lodIndex];
|
||||
meshes.Resize(lod.Meshes.Count());
|
||||
for (int32 meshIndex = 0; meshIndex < lod.Meshes.Count(); meshIndex++)
|
||||
meshes[meshIndex] = &lod.Meshes[meshIndex];
|
||||
}
|
||||
|
||||
void SkinnedModel::InitAsVirtual()
|
||||
{
|
||||
// Init with one mesh and single bone
|
||||
@@ -723,6 +755,21 @@ void SkinnedModel::InitAsVirtual()
|
||||
BinaryAsset::InitAsVirtual();
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void SkinnedModel::GetReferences(Array<Guid>& output) const
|
||||
{
|
||||
// Base
|
||||
BinaryAsset::GetReferences(output);
|
||||
|
||||
for (int32 i = 0; i < MaterialSlots.Count(); i++)
|
||||
{
|
||||
output.Add(MaterialSlots[i].Material.GetID());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int32 SkinnedModel::GetMaxResidency() const
|
||||
{
|
||||
return LODs.Count();
|
||||
|
||||
@@ -61,19 +61,9 @@ public:
|
||||
return LODs.HasItems();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets amount of the level of details in the model
|
||||
/// </summary>
|
||||
/// <returns>Amount of the level of details in the model</returns>
|
||||
FORCE_INLINE int32 GetLODsCount() const
|
||||
{
|
||||
return LODs.Count();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of loaded model LODs.
|
||||
/// </summary>
|
||||
/// <returns>Loaded LODs count</returns>
|
||||
API_PROPERTY() FORCE_INLINE int32 GetLoadedLODs() const
|
||||
{
|
||||
return _loadedLODs;
|
||||
@@ -102,7 +92,6 @@ public:
|
||||
/// <summary>
|
||||
/// Gets index of the highest resident LOD (may be equal to LODs.Count if no LOD has been uploaded). Note: LOD=0 is the highest (top quality)
|
||||
/// </summary>
|
||||
/// <returns>LOD index</returns>
|
||||
FORCE_INLINE int32 HighestResidentLODIndex() const
|
||||
{
|
||||
return GetLODsCount() - _loadedLODs;
|
||||
@@ -112,10 +101,7 @@ public:
|
||||
/// Determines whether any LOD has been initialized.
|
||||
/// </summary>
|
||||
/// <returns>True if any LOD has been initialized, otherwise false.</returns>
|
||||
FORCE_INLINE bool HasAnyLODInitialized() const
|
||||
{
|
||||
return LODs.HasItems() && LODs.Last().HasAnyMeshInitialized();
|
||||
}
|
||||
bool HasAnyLODInitialized() const;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this model can be rendered.
|
||||
@@ -184,22 +170,14 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="lodIndex">Index of the LOD.</param>
|
||||
/// <returns>Task that will gather chunk data or null if already here.</returns>
|
||||
ContentLoadTask* RequestLODDataAsync(int32 lodIndex)
|
||||
{
|
||||
const int32 chunkIndex = SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
|
||||
return RequestChunkDataAsync(chunkIndex);
|
||||
}
|
||||
ContentLoadTask* RequestLODDataAsync(int32 lodIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model LOD data (links bytes).
|
||||
/// </summary>
|
||||
/// <param name="lodIndex">Index of the LOD.</param>
|
||||
/// <param name="data">The data (may be missing if failed to get it).</param>
|
||||
void GetLODData(int32 lodIndex, BytesContainer& data) const
|
||||
{
|
||||
const int32 chunkIndex = SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
|
||||
GetChunkData(chunkIndex, data);
|
||||
}
|
||||
void GetLODData(int32 lodIndex, BytesContainer& data) const;
|
||||
|
||||
public:
|
||||
|
||||
@@ -300,18 +278,11 @@ public:
|
||||
|
||||
// [ModelBase]
|
||||
void SetupMaterialSlots(int32 slotsCount) override;
|
||||
int32 GetLODsCount() const override;
|
||||
void GetMeshes(Array<MeshBase*>& meshes, int32 lodIndex = 0) override;
|
||||
void InitAsVirtual() override;
|
||||
#if USE_EDITOR
|
||||
void GetReferences(Array<Guid>& output) const override
|
||||
{
|
||||
// Base
|
||||
BinaryAsset::GetReferences(output);
|
||||
|
||||
for (int32 i = 0; i < MaterialSlots.Count(); i++)
|
||||
{
|
||||
output.Add(MaterialSlots[i].Material.GetID());
|
||||
}
|
||||
}
|
||||
void GetReferences(Array<Guid>& output) const override;
|
||||
#endif
|
||||
|
||||
// [StreamableResource]
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include "Engine/Scripting/MainThreadManagedInvokeAction.h"
|
||||
#include "Engine/Tools/TextureTool/TextureTool.h"
|
||||
|
||||
REGISTER_BINARY_ASSET(Texture, "FlaxEngine.Texture", ::New<TextureAssetUpgrader>(), true);
|
||||
REGISTER_BINARY_ASSET_WITH_UPGRADER(Texture, "FlaxEngine.Texture", TextureAssetUpgrader, true);
|
||||
|
||||
Texture::Texture(const SpawnParams& params, const AssetInfo* info)
|
||||
: TextureBase(params, info)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||
#include "Engine/Serialization/Serialization.h"
|
||||
#include "Engine/Serialization/JsonWriter.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Utilities/StringConverter.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
|
||||
@@ -1276,7 +1277,7 @@ void VisualScriptExecutor::ProcessGroupFlow(Box* boxBase, Node* node, Value& val
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_BINARY_ASSET(VisualScript, "FlaxEngine.VisualScript", nullptr, false);
|
||||
REGISTER_BINARY_ASSET(VisualScript, "FlaxEngine.VisualScript", false);
|
||||
|
||||
VisualScript::VisualScript(const SpawnParams& params, const AssetInfo* info)
|
||||
: BinaryAsset(params, info)
|
||||
@@ -1329,6 +1330,7 @@ Asset::LoadResult VisualScript::load()
|
||||
{
|
||||
case GRAPH_NODE_MAKE_TYPE(16, 3):
|
||||
{
|
||||
// Override method
|
||||
auto& method = _methods.AddOne();
|
||||
method.Script = this;
|
||||
method.Node = &node;
|
||||
@@ -1342,6 +1344,7 @@ Asset::LoadResult VisualScript::load()
|
||||
}
|
||||
case GRAPH_NODE_MAKE_TYPE(16, 6):
|
||||
{
|
||||
// Function
|
||||
auto& method = _methods.AddOne();
|
||||
method.Script = this;
|
||||
method.Node = &node;
|
||||
@@ -1380,6 +1383,17 @@ Asset::LoadResult VisualScript::load()
|
||||
}
|
||||
}
|
||||
}
|
||||
#if COMPILE_WITH_PROFILER
|
||||
for (auto& method : _methods)
|
||||
{
|
||||
const StringView assetName(StringUtils::GetFileNameWithoutExtension(GetPath()));
|
||||
method.ProfilerName.Resize(assetName.Length() + 2 + method.Name.Length());
|
||||
StringUtils::ConvertUTF162ANSI(assetName.Get(), method.ProfilerName.Get(), assetName.Length());
|
||||
method.ProfilerName.Get()[assetName.Length()] = ':';
|
||||
method.ProfilerName.Get()[assetName.Length() + 1] = ':';
|
||||
Platform::MemoryCopy(method.ProfilerName.Get() + assetName.Length() + 2, method.Name.Get(), method.Name.Length());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Setup fields list
|
||||
_fields.Resize(Graph.Parameters.Count());
|
||||
@@ -2132,7 +2146,7 @@ BytesContainer VisualScript::LoadSurface()
|
||||
return result;
|
||||
}
|
||||
|
||||
LOG(Warning, "\'{0}\' surface data is missing.", GetPath());
|
||||
LOG(Warning, "\'{0}\' surface data is missing.", ToString());
|
||||
return BytesContainer();
|
||||
}
|
||||
|
||||
@@ -2284,6 +2298,7 @@ VisualScriptingBinaryModule* VisualScripting::GetBinaryModule()
|
||||
Variant VisualScripting::Invoke(VisualScript::Method* method, ScriptingObject* instance, Span<Variant> parameters)
|
||||
{
|
||||
CHECK_RETURN(method && method->Script->IsLoaded(), Variant::Zero);
|
||||
PROFILE_CPU_NAMED(*method->ProfilerName);
|
||||
|
||||
// Add to the calling stack
|
||||
ScopeContext scope;
|
||||
|
||||
@@ -115,6 +115,9 @@ public:
|
||||
MethodFlags MethodFlags;
|
||||
ScriptingTypeMethodSignature Signature;
|
||||
Array<StringAnsi, InlinedAllocation<16>> ParamNames;
|
||||
#if COMPILE_WITH_PROFILER
|
||||
StringAnsi ProfilerName;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Field
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "BinaryAsset.h"
|
||||
#include "Cache/AssetsCache.h"
|
||||
#include "Storage/ContentStorageManager.h"
|
||||
#include "Loading/Tasks/LoadAssetDataTask.h"
|
||||
#include "Engine/ContentImporters/AssetsImportingManager.h"
|
||||
@@ -131,6 +132,13 @@ void BinaryAsset::GetImportMetadata(String& path, String& username) const
|
||||
}
|
||||
}
|
||||
|
||||
String BinaryAsset::GetImportPath() const
|
||||
{
|
||||
String path, username;
|
||||
GetImportMetadata(path, username);
|
||||
return path;
|
||||
}
|
||||
|
||||
void BinaryAsset::ClearDependencies()
|
||||
{
|
||||
for (auto& e : Dependencies)
|
||||
@@ -293,7 +301,12 @@ bool BinaryAsset::LoadChunks(AssetChunksFlag chunks)
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
bool BinaryAsset::SaveAsset(const StringView& path, AssetInitData& data, bool silentMode)
|
||||
bool BinaryAsset::SaveAsset(AssetInitData& data, bool silentMode) const
|
||||
{
|
||||
return SaveAsset(GetPath(), data, silentMode);
|
||||
}
|
||||
|
||||
bool BinaryAsset::SaveAsset(const StringView& path, AssetInitData& data, bool silentMode) const
|
||||
{
|
||||
data.Header = _header;
|
||||
data.Metadata.Link(Metadata);
|
||||
@@ -303,9 +316,13 @@ bool BinaryAsset::SaveAsset(const StringView& path, AssetInitData& data, bool si
|
||||
|
||||
bool BinaryAsset::SaveToAsset(const StringView& path, AssetInitData& data, bool silentMode)
|
||||
{
|
||||
// Ensure path is in a valid format
|
||||
String pathNorm(path);
|
||||
FileSystem::NormalizePath(pathNorm);
|
||||
|
||||
// Find target storage container and the asset
|
||||
auto storage = ContentStorageManager::TryGetStorage(path);
|
||||
auto asset = Content::GetAsset(path);
|
||||
auto storage = ContentStorageManager::TryGetStorage(pathNorm);
|
||||
auto asset = Content::GetAsset(pathNorm);
|
||||
auto binaryAsset = dynamic_cast<BinaryAsset*>(asset);
|
||||
if (asset && !binaryAsset)
|
||||
{
|
||||
@@ -351,8 +368,8 @@ bool BinaryAsset::SaveToAsset(const StringView& path, AssetInitData& data, bool
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(path.HasChars());
|
||||
result = FlaxStorage::Create(path, data, silentMode);
|
||||
ASSERT(pathNorm.HasChars());
|
||||
result = FlaxStorage::Create(pathNorm, data, silentMode);
|
||||
}
|
||||
if (binaryAsset)
|
||||
binaryAsset->_isSaving = false;
|
||||
@@ -429,7 +446,12 @@ void BinaryAsset::OnDeleteObject()
|
||||
|
||||
const String& BinaryAsset::GetPath() const
|
||||
{
|
||||
#if USE_EDITOR
|
||||
return Storage ? Storage->GetPath() : String::Empty;
|
||||
#else
|
||||
// In build all assets are packed into packages so use ID for original path lookup
|
||||
return Content::GetRegistry()->GetEditorAssetPath(_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -487,7 +509,6 @@ protected:
|
||||
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
void OnEnd() override
|
||||
{
|
||||
_dataLock.Release();
|
||||
|
||||
@@ -109,13 +109,7 @@ public:
|
||||
/// <summary>
|
||||
/// Gets the imported file path from the asset metadata (can be empty if not available).
|
||||
/// </summary>
|
||||
/// <returns>The imported source file path.</returns>
|
||||
API_PROPERTY() String GetImportPath() const
|
||||
{
|
||||
String path, username;
|
||||
GetImportMetadata(path, username);
|
||||
return path;
|
||||
}
|
||||
API_PROPERTY() String GetImportPath() const;
|
||||
|
||||
/// <summary>
|
||||
/// Clears the asset dependencies list and unregisters from tracking their changes.
|
||||
@@ -131,7 +125,6 @@ public:
|
||||
/// <summary>
|
||||
/// Determines whether any of the dependency assets was modified after last modification time of this asset (last file write time check).
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if one or more dependencies were modified; otherwise, <c>false</c>.</returns>
|
||||
bool HasDependenciesModified() const;
|
||||
|
||||
protected:
|
||||
@@ -277,10 +270,7 @@ public:
|
||||
/// <param name="data">Asset data.</param>
|
||||
/// <param name="silentMode">In silent mode don't reload opened storage container that is using target file.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
FORCE_INLINE bool SaveAsset(AssetInitData& data, bool silentMode = false)
|
||||
{
|
||||
return SaveAsset(GetPath(), data, silentMode);
|
||||
}
|
||||
bool SaveAsset(AssetInitData& data, bool silentMode = false) const;
|
||||
|
||||
/// <summary>
|
||||
/// Saves this asset to the file.
|
||||
@@ -289,7 +279,7 @@ public:
|
||||
/// <param name="path">Asset path (will be used to override the asset or create a new one).</param>
|
||||
/// <param name="silentMode">In silent mode don't reload opened storage container that is using target file.</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
bool SaveAsset(const StringView& path, AssetInitData& data, bool silentMode = false);
|
||||
bool SaveAsset(const StringView& path, AssetInitData& data, bool silentMode = false) const;
|
||||
|
||||
/// <summary>
|
||||
/// Saves asset data to the storage container. Asset unique ID is handled by auto.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "AssetsCache.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/DeleteMe.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Serialization/FileWriteStream.h"
|
||||
#include "Engine/Serialization/FileReadStream.h"
|
||||
@@ -10,12 +11,12 @@
|
||||
#include "Engine/Content/Storage/ContentStorageManager.h"
|
||||
#include "Engine/Content/Storage/JsonStorageProxy.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
|
||||
AssetsCache::AssetsCache()
|
||||
: _isDirty(false)
|
||||
, _registry(4096)
|
||||
, _pathsMapping(256)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -91,8 +92,8 @@ void AssetsCache::Init()
|
||||
#if ENABLE_ASSETS_DISCOVERY
|
||||
stream->Read(&e.FileModified);
|
||||
#else
|
||||
DateTime tmp1;
|
||||
stream->Read(&tmp1);
|
||||
DateTime tmp1;
|
||||
stream->Read(&tmp1);
|
||||
#endif
|
||||
|
||||
if (flags & AssetsCacheFlags::RelativePaths && e.Info.Path.HasChars())
|
||||
@@ -207,7 +208,7 @@ bool AssetsCache::Save(const StringView& path, const Registry& entries, const Pa
|
||||
#if ENABLE_ASSETS_DISCOVERY
|
||||
stream->Write(&e.FileModified);
|
||||
#else
|
||||
stream->WriteInt64(0);
|
||||
stream->WriteInt64(0);
|
||||
#endif
|
||||
|
||||
index++;
|
||||
@@ -231,6 +232,21 @@ bool AssetsCache::Save(const StringView& path, const Registry& entries, const Pa
|
||||
return false;
|
||||
}
|
||||
|
||||
const String& AssetsCache::GetEditorAssetPath(const Guid& id) const
|
||||
{
|
||||
#if USE_EDITOR
|
||||
auto e = _registry.TryGet(id);
|
||||
return e ? e->Info.Path : String::Empty;
|
||||
#else
|
||||
for (auto& e : _pathsMapping)
|
||||
{
|
||||
if (e.Value == id)
|
||||
return e.Key;
|
||||
}
|
||||
return String::Empty;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool AssetsCache::FindAsset(const StringView& path, AssetInfo& info)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
@@ -402,41 +418,55 @@ void AssetsCache::RegisterAssets(FlaxStorage* storage)
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
void AssetsCache::RegisterAsset(const AssetHeader& header, const StringView& path)
|
||||
{
|
||||
RegisterAsset(header.ID, header.TypeName, path);
|
||||
}
|
||||
|
||||
void AssetsCache::RegisterAssets(const FlaxStorageReference& storage)
|
||||
{
|
||||
RegisterAssets(storage.Get());
|
||||
}
|
||||
|
||||
void AssetsCache::RegisterAsset(const Guid& id, const String& typeName, const StringView& path)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
|
||||
ScopeLock lock(_locker);
|
||||
|
||||
// Mark registry as draft
|
||||
_isDirty = true;
|
||||
|
||||
// Check if asset has been already added to the registry
|
||||
bool isMissing = true;
|
||||
for (auto i = _registry.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
auto& e = i->Value;
|
||||
|
||||
// Compare IDs
|
||||
if (e.Info.ID == id)
|
||||
{
|
||||
// Update registry entry
|
||||
e.Info.Path = path;
|
||||
e.Info.TypeName = typeName;
|
||||
|
||||
// Back
|
||||
if (e.Info.Path != path)
|
||||
{
|
||||
e.Info.Path = path;
|
||||
_isDirty = true;
|
||||
}
|
||||
if (e.Info.TypeName != typeName)
|
||||
{
|
||||
e.Info.TypeName = typeName;
|
||||
_isDirty = true;
|
||||
}
|
||||
isMissing = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Compare paths
|
||||
if (e.Info.Path == path)
|
||||
{
|
||||
// Update registry entry
|
||||
e.Info.ID = id;
|
||||
e.Info.TypeName = typeName;
|
||||
|
||||
// Back
|
||||
if (e.Info.ID != id)
|
||||
{
|
||||
e.Info.Path = path;
|
||||
_isDirty = true;
|
||||
}
|
||||
if (e.Info.TypeName != typeName)
|
||||
{
|
||||
e.Info.TypeName = typeName;
|
||||
_isDirty = true;
|
||||
}
|
||||
isMissing = false;
|
||||
break;
|
||||
}
|
||||
@@ -445,9 +475,8 @@ void AssetsCache::RegisterAsset(const Guid& id, const String& typeName, const St
|
||||
if (isMissing)
|
||||
{
|
||||
LOG(Info, "Register asset {0}:{1} \'{2}\'", id, typeName, path);
|
||||
|
||||
// Add new asset entry
|
||||
_registry.Add(id, Entry(id, typeName, path));
|
||||
_isDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,8 +596,8 @@ bool AssetsCache::IsEntryValid(Entry& e)
|
||||
#else
|
||||
|
||||
// In game we don't care about it because all cached asset entries are valid (precached)
|
||||
// Skip only entries with missing file
|
||||
return e.Info.Path.HasChars();
|
||||
// Skip only entries with missing file
|
||||
return e.Info.Path.HasChars();
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2,13 +2,19 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../AssetInfo.h"
|
||||
#include "../Config.h"
|
||||
#include "Engine/Core/Types/Guid.h"
|
||||
#if ENABLE_ASSETS_DISCOVERY
|
||||
#include "Engine/Core/Types/DateTime.h"
|
||||
#endif
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Platform/CriticalSection.h"
|
||||
#include "Engine/Content/Storage/FlaxStorageReference.h"
|
||||
#include "../AssetInfo.h"
|
||||
#include "../Config.h"
|
||||
|
||||
struct AssetHeader;
|
||||
struct FlaxStorageReference;
|
||||
class FlaxStorage;
|
||||
|
||||
/// <summary>
|
||||
/// Assets cache flags.
|
||||
@@ -31,7 +37,7 @@ DECLARE_ENUM_OPERATORS(AssetsCacheFlags);
|
||||
/// <summary>
|
||||
/// Flax Game Engine assets cache container
|
||||
/// </summary>
|
||||
class AssetsCache
|
||||
class FLAXENGINE_API AssetsCache
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -46,19 +52,17 @@ public:
|
||||
AssetInfo Info;
|
||||
|
||||
#if ENABLE_ASSETS_DISCOVERY
|
||||
|
||||
/// <summary>
|
||||
/// The file modified date.
|
||||
/// </summary>
|
||||
DateTime FileModified;
|
||||
|
||||
#endif
|
||||
|
||||
Entry()
|
||||
{
|
||||
}
|
||||
|
||||
Entry(const Guid& id, const String& typeName, const StringView& path)
|
||||
Entry(const Guid& id, const StringView& typeName, const StringView& path)
|
||||
: Info(id, typeName, path)
|
||||
#if ENABLE_ASSETS_DISCOVERY
|
||||
, FileModified(DateTime::NowUTC())
|
||||
@@ -124,6 +128,13 @@ public:
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Finds the asset path by id. In editor it returns the actual asset path, at runtime it returns the mapped asset path.
|
||||
/// </summary>
|
||||
/// <param name="id">The asset id.</param>
|
||||
/// <returns>The asset path, or empty if failed to find.</returns>
|
||||
const String& GetEditorAssetPath(const Guid& id) const;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the asset info by path.
|
||||
/// </summary>
|
||||
@@ -167,16 +178,13 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="typeName">The asset typename.</param>
|
||||
/// <param name="result">The result array.</param>
|
||||
void GetAllByTypeName(const StringView& typeName, Array<Guid>& result) const;
|
||||
void GetAllByTypeName(const StringView& typeName, Array<Guid, HeapAllocation>& result) const;
|
||||
|
||||
/// <summary>
|
||||
/// Register assets in the cache
|
||||
/// </summary>
|
||||
/// <param name="storage">Flax assets container reference</param>
|
||||
FORCE_INLINE void RegisterAssets(const FlaxStorageReference& storage)
|
||||
{
|
||||
RegisterAssets(storage.Get());
|
||||
}
|
||||
void RegisterAssets(const FlaxStorageReference& storage);
|
||||
|
||||
/// <summary>
|
||||
/// Register assets in the cache
|
||||
@@ -189,10 +197,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="header">Flax asset file header</param>
|
||||
/// <param name="path">Asset path</param>
|
||||
FORCE_INLINE void RegisterAsset(const AssetHeader& header, const StringView& path)
|
||||
{
|
||||
RegisterAsset(header.ID, header.TypeName, path);
|
||||
}
|
||||
void RegisterAsset(const AssetHeader& header, const StringView& path);
|
||||
|
||||
/// <summary>
|
||||
/// Register asset in the cache
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Graphics/Graphics.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Level/Types.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
@@ -408,16 +409,20 @@ Asset* Content::LoadAsync(const StringView& path, MClass* type)
|
||||
|
||||
Asset* Content::LoadAsync(const StringView& path, const ScriptingTypeHandle& type)
|
||||
{
|
||||
// Ensure path is in a valid format
|
||||
String pathNorm(path);
|
||||
FileSystem::NormalizePath(pathNorm);
|
||||
|
||||
#if USE_EDITOR
|
||||
if (!FileSystem::FileExists(path))
|
||||
if (!FileSystem::FileExists(pathNorm))
|
||||
{
|
||||
LOG(Error, "Missing file \'{0}\'", path);
|
||||
LOG(Error, "Missing file \'{0}\'", pathNorm);
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
AssetInfo assetInfo;
|
||||
if (GetAssetInfo(path, assetInfo))
|
||||
if (GetAssetInfo(pathNorm, assetInfo))
|
||||
{
|
||||
return LoadAsync(assetInfo.ID, type);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "../BinaryAsset.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Content/Storage/ContentStorageManager.h"
|
||||
#if USE_EDITOR
|
||||
@@ -14,28 +15,23 @@
|
||||
bool BinaryAssetFactoryBase::Init(BinaryAsset* asset)
|
||||
{
|
||||
ASSERT(asset && asset->Storage);
|
||||
|
||||
// Prepare
|
||||
auto storage = asset->Storage;
|
||||
AssetInfo info;
|
||||
info.ID = asset->GetID();
|
||||
info.TypeName = asset->GetTypeName();
|
||||
info.Path = storage->GetPath();
|
||||
|
||||
// Load serialized asset data
|
||||
AssetInitData initData;
|
||||
if (storage->LoadAssetHeader(info.ID, initData))
|
||||
if (storage->LoadAssetHeader(asset->GetID(), initData))
|
||||
{
|
||||
LOG(Error, "Cannot load asset header.\nInfo: {0}", info.ToString());
|
||||
LOG(Error, "Cannot load asset header.\nInfo: {0}", AssetInfo(asset->GetID(), asset->GetTypeName(), storage->GetPath()).ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
#if COMPILE_WITH_ASSET_UPGRADERS
|
||||
#if USE_EDITOR
|
||||
// Check if need to perform data conversion to the newer version (only in Editor)
|
||||
const auto upgrader = GetUpgrader();
|
||||
if (storage->AllowDataModifications() && upgrader && upgrader->ShouldUpgrade(initData.SerializedVersion))
|
||||
{
|
||||
const auto startTime = DateTime::NowUTC();
|
||||
const AssetInfo info(asset->GetID(), asset->GetTypeName(), storage->GetPath());
|
||||
LOG(Info, "Starting asset \'{0}\' conversion", info.Path);
|
||||
|
||||
// Backup source file (in case of conversion failure)
|
||||
@@ -99,21 +95,21 @@ bool BinaryAssetFactoryBase::Init(BinaryAsset* asset)
|
||||
// Check if serialized asset version is supported
|
||||
if (!IsVersionSupported(initData.SerializedVersion))
|
||||
{
|
||||
LOG(Warning, "Asset version {1} is not supported.\nInfo: {0}", info.ToString(), initData.SerializedVersion);
|
||||
LOG(Warning, "Asset version {1} is not supported.\nInfo: {0}", AssetInfo(asset->GetID(), asset->GetTypeName(), storage->GetPath()).ToString(), initData.SerializedVersion);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initialize asset
|
||||
if (asset->Init(initData))
|
||||
{
|
||||
LOG(Error, "Cannot initialize asset.\nInfo: {0}", info.ToString());
|
||||
LOG(Error, "Cannot initialize asset.\nInfo: {0}", AssetInfo(asset->GetID(), asset->GetTypeName(), storage->GetPath()).ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#if COMPILE_WITH_ASSET_UPGRADERS
|
||||
#if USE_EDITOR
|
||||
|
||||
bool BinaryAssetFactoryBase::UpgradeAsset(const AssetInfo& info, FlaxStorage* storage, AssetMigrationContext& context)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "IAssetFactory.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Content/Upgraders/BinaryAssetUpgrader.h"
|
||||
#endif
|
||||
#include "Engine/Content/AssetInfo.h"
|
||||
#include "Engine/Scripting/ScriptingObject.h"
|
||||
|
||||
@@ -14,7 +16,7 @@ class FlaxStorage;
|
||||
/// The binary assets factory base class.
|
||||
/// </summary>
|
||||
/// <seealso cref="IAssetFactory" />
|
||||
class BinaryAssetFactoryBase : public IAssetFactory
|
||||
class FLAXENGINE_API BinaryAssetFactoryBase : public IAssetFactory
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -29,7 +31,7 @@ protected:
|
||||
|
||||
virtual BinaryAsset* Create(const AssetInfo& info) = 0;
|
||||
virtual bool IsVersionSupported(uint32 serializedVersion) const = 0;
|
||||
#if COMPILE_WITH_ASSET_UPGRADERS
|
||||
#if USE_EDITOR
|
||||
bool UpgradeAsset(const AssetInfo& info, FlaxStorage* storage, AssetMigrationContext& context);
|
||||
#endif
|
||||
|
||||
@@ -65,16 +67,31 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
#define REGISTER_BINARY_ASSET(type, typeName, upgrader, supportsVirtualAssets) \
|
||||
#define REGISTER_BINARY_ASSET(type, typeName, supportsVirtualAssets) \
|
||||
const String type::TypeName = TEXT(typeName); \
|
||||
class CONCAT_MACROS(Factory, type) : public BinaryAssetFactory<type> \
|
||||
{ \
|
||||
public: \
|
||||
CONCAT_MACROS(Factory, type)() { IAssetFactory::Get().Add(type::TypeName, this); } \
|
||||
~CONCAT_MACROS(Factory, type)() { IAssetFactory::Get().Remove(type::TypeName); } \
|
||||
bool SupportsVirtualAssets() const override { return supportsVirtualAssets; } \
|
||||
}; \
|
||||
static CONCAT_MACROS(Factory, type) CONCAT_MACROS(CFactory, type)
|
||||
|
||||
#if USE_EDITOR
|
||||
#define REGISTER_BINARY_ASSET_WITH_UPGRADER(type, typeName, upgrader, supportsVirtualAssets) \
|
||||
const String type::TypeName = TEXT(typeName); \
|
||||
class CONCAT_MACROS(Factory, type) : public BinaryAssetFactory<type> \
|
||||
{ \
|
||||
private: \
|
||||
IAssetUpgrader* _upgrader = upgrader; \
|
||||
IAssetUpgrader* _upgrader = ::New<upgrader>(); \
|
||||
public: \
|
||||
CONCAT_MACROS(Factory, type)() { IAssetFactory::Get().Add(type::TypeName, this); } \
|
||||
~CONCAT_MACROS(Factory, type)() { if (_upgrader) Delete(_upgrader); IAssetFactory::Get().Remove(type::TypeName); } \
|
||||
~CONCAT_MACROS(Factory, type)() { Delete(_upgrader); IAssetFactory::Get().Remove(type::TypeName); } \
|
||||
bool SupportsVirtualAssets() const override { return supportsVirtualAssets; } \
|
||||
IAssetUpgrader* GetUpgrader() const override { return _upgrader; } \
|
||||
}; \
|
||||
static CONCAT_MACROS(Factory, type) CONCAT_MACROS(CFactory, type)
|
||||
#else
|
||||
#define REGISTER_BINARY_ASSET_WITH_UPGRADER(type, typeName, upgrader, supportsVirtualAssets) REGISTER_BINARY_ASSET(type, typeName, supportsVirtualAssets)
|
||||
#endif
|
||||
|
||||
@@ -9,13 +9,10 @@ struct AssetInfo;
|
||||
class Asset;
|
||||
class IAssetUpgrader;
|
||||
|
||||
// Enables upgrading asset files from the older version format
|
||||
#define COMPILE_WITH_ASSET_UPGRADERS (USE_EDITOR)
|
||||
|
||||
/// <summary>
|
||||
/// The asset objects factory.
|
||||
/// </summary>
|
||||
class IAssetFactory
|
||||
class FLAXENGINE_API IAssetFactory
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
/// The Json assets factory base class.
|
||||
/// </summary>
|
||||
/// <seealso cref="IAssetFactory" />
|
||||
class JsonAssetFactoryBase : public IAssetFactory
|
||||
class FLAXENGINE_API JsonAssetFactoryBase : public IAssetFactory
|
||||
{
|
||||
protected:
|
||||
|
||||
@@ -23,7 +23,6 @@ public:
|
||||
{
|
||||
return Create(info);
|
||||
}
|
||||
|
||||
Asset* NewVirtual(const AssetInfo& info) override
|
||||
{
|
||||
return Create(info);
|
||||
@@ -47,12 +46,13 @@ protected:
|
||||
}
|
||||
};
|
||||
|
||||
#define REGISTER_JSON_ASSET(type, typeName) \
|
||||
#define REGISTER_JSON_ASSET(type, typeName, supportsVirtualAssets) \
|
||||
const String type::TypeName = TEXT(typeName); \
|
||||
class CONCAT_MACROS(Factory, type) : public JsonAssetFactory<type> \
|
||||
{ \
|
||||
public: \
|
||||
CONCAT_MACROS(Factory, type)() { IAssetFactory::Get().Add(type::TypeName, this); } \
|
||||
~CONCAT_MACROS(Factory, type)() { IAssetFactory::Get().Remove(type::TypeName); } \
|
||||
bool SupportsVirtualAssets() const override { return supportsVirtualAssets; } \
|
||||
}; \
|
||||
static CONCAT_MACROS(Factory, type) CONCAT_MACROS(CFactory, type)
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "JsonAsset.h"
|
||||
#include "Storage/ContentStorageManager.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Core/Types/DataContainer.h"
|
||||
#else
|
||||
#include "Storage/ContentStorageManager.h"
|
||||
#endif
|
||||
#include "Content.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include "Cache/AssetsCache.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Serialization/JsonTools.h"
|
||||
#include "Engine/Content/Factories/JsonAssetFactory.h"
|
||||
@@ -38,7 +42,12 @@ String JsonAssetBase::GetData() const
|
||||
|
||||
const String& JsonAssetBase::GetPath() const
|
||||
{
|
||||
#if USE_EDITOR
|
||||
return _path;
|
||||
#else
|
||||
// In build all assets are packed into packages so use ID for original path lookup
|
||||
return Content::GetRegistry()->GetEditorAssetPath(_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
@@ -93,9 +102,8 @@ Asset::LoadResult JsonAssetBase::loadAsset()
|
||||
{
|
||||
// Load data (raw json file in editor, cooked asset in build game)
|
||||
#if USE_EDITOR
|
||||
|
||||
BytesContainer data;
|
||||
if (File::ReadAllBytes(GetPath(), data))
|
||||
if (File::ReadAllBytes(_path, data))
|
||||
{
|
||||
LOG(Warning, "Filed to load json asset data. {0}", ToString());
|
||||
return LoadResult::CannotLoadData;
|
||||
@@ -104,11 +112,9 @@ Asset::LoadResult JsonAssetBase::loadAsset()
|
||||
{
|
||||
return LoadResult::MissingDataChunk;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// Get the asset storage container but don't load it now
|
||||
const auto storage = ContentStorageManager::GetStorage(GetPath(), true);
|
||||
const auto storage = ContentStorageManager::GetStorage(_path, true);
|
||||
if (!storage)
|
||||
return LoadResult::CannotLoadStorage;
|
||||
|
||||
@@ -124,7 +130,6 @@ Asset::LoadResult JsonAssetBase::loadAsset()
|
||||
if (storage->LoadAssetChunk(chunk))
|
||||
return LoadResult::CannotLoadData;
|
||||
auto& data = chunk->Data;
|
||||
|
||||
#endif
|
||||
|
||||
// Parse json document
|
||||
@@ -176,7 +181,7 @@ void JsonAssetBase::onRename(const StringView& newPath)
|
||||
|
||||
#endif
|
||||
|
||||
REGISTER_JSON_ASSET(JsonAsset, "FlaxEngine.JsonAsset");
|
||||
REGISTER_JSON_ASSET(JsonAsset, "FlaxEngine.JsonAsset", true);
|
||||
|
||||
JsonAsset::JsonAsset(const SpawnParams& params, const AssetInfo* info)
|
||||
: JsonAssetBase(params, info)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Threading/Task.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
|
||||
class Asset;
|
||||
class LoadingThread;
|
||||
|
||||
@@ -165,7 +165,7 @@ bool ContentLoadingManagerService::Init()
|
||||
|
||||
// Calculate amount of loading threads to use
|
||||
const CPUInfo cpuInfo = Platform::GetCPUInfo();
|
||||
const int32 count = static_cast<int32>(Math::Clamp(LOADING_THREAD_PER_PHYSICAL_CORE * cpuInfo.ProcessorCoreCount, 1.0f, 4.0f));
|
||||
const int32 count = Math::Clamp(static_cast<int32>(LOADING_THREAD_PER_PHYSICAL_CORE * (float)cpuInfo.ProcessorCoreCount), 1, 6);
|
||||
LOG(Info, "Creating {0} content loading threads...", count);
|
||||
|
||||
// Create loading threads
|
||||
|
||||
@@ -53,6 +53,9 @@ protected:
|
||||
AssetReference<BinaryAsset> ref = _asset.Get();
|
||||
if (ref == nullptr)
|
||||
return Result::MissingReferences;
|
||||
#if TRACY_ENABLE
|
||||
const StringView name(ref->GetPath());
|
||||
#endif
|
||||
|
||||
// Load chunks
|
||||
for (int32 i = 0; i < ASSET_FILE_DATA_CHUNKS; i++)
|
||||
@@ -62,11 +65,14 @@ protected:
|
||||
const auto chunk = ref->GetChunk(i);
|
||||
if (chunk != nullptr)
|
||||
{
|
||||
// Check for cancel
|
||||
if (IsCancelRequested())
|
||||
return Result::Ok;
|
||||
|
||||
// Load it
|
||||
#if TRACY_ENABLE
|
||||
ZoneScoped;
|
||||
ZoneName(*name, name.Length());
|
||||
#endif
|
||||
if (ref->Storage->LoadAssetChunk(chunk))
|
||||
{
|
||||
LOG(Warning, "Cannot load asset \'{0}\' chunk {1}.", ref->ToString(), i);
|
||||
|
||||
@@ -13,10 +13,6 @@
|
||||
/// </summary>
|
||||
class LoadAssetTask : public ContentLoadTask
|
||||
{
|
||||
private:
|
||||
|
||||
WeakAssetReference<Asset> _asset;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
@@ -25,27 +21,20 @@ public:
|
||||
/// <param name="asset">The asset to load.</param>
|
||||
LoadAssetTask(Asset* asset)
|
||||
: ContentLoadTask(Type::LoadAsset)
|
||||
, _asset(asset)
|
||||
, Asset(asset)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets the asset.
|
||||
/// </summary>
|
||||
/// <returns>The asset.</returns>
|
||||
FORCE_INLINE Asset* GetAsset() const
|
||||
{
|
||||
return _asset.Get();
|
||||
}
|
||||
WeakAssetReference<Asset> Asset;
|
||||
|
||||
public:
|
||||
|
||||
// [ContentLoadTask]
|
||||
bool HasReference(Object* obj) const override
|
||||
{
|
||||
return obj == _asset;
|
||||
return obj == Asset;
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -55,7 +44,8 @@ protected:
|
||||
{
|
||||
PROFILE_CPU();
|
||||
|
||||
AssetReference<Asset> ref = _asset.Get();
|
||||
// Keep valid ref to the asset
|
||||
AssetReference<::Asset> ref = Asset.Get();
|
||||
if (ref == nullptr)
|
||||
return Result::MissingReferences;
|
||||
|
||||
@@ -68,7 +58,7 @@ protected:
|
||||
|
||||
void OnEnd() override
|
||||
{
|
||||
_asset = nullptr;
|
||||
Asset = nullptr;
|
||||
|
||||
// Base
|
||||
ContentLoadTask::OnEnd();
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
#include "Engine/Core/Types/Guid.h"
|
||||
#include "Engine/Core/Types/Pair.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Types/DataContainer.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#endif
|
||||
#include "FlaxChunk.h"
|
||||
|
||||
/// <summary>
|
||||
@@ -54,7 +56,8 @@ public:
|
||||
/// Gets the chunks.
|
||||
/// </summary>
|
||||
/// <param name="output">The output data.</param>
|
||||
void GetChunks(Array<FlaxChunk*>& output) const
|
||||
template<typename AllocationType = HeapAllocation>
|
||||
void GetChunks(Array<FlaxChunk*, AllocationType>& output) const
|
||||
{
|
||||
for (int32 i = 0; i < ASSET_FILE_DATA_CHUNKS; i++)
|
||||
{
|
||||
@@ -67,7 +70,8 @@ public:
|
||||
/// Gets the chunks that are loaded.
|
||||
/// </summary>
|
||||
/// <param name="output">The output data.</param>
|
||||
void GetLoadedChunks(Array<FlaxChunk*>& output) const
|
||||
template<typename AllocationType = HeapAllocation>
|
||||
void GetLoadedChunks(Array<FlaxChunk*, AllocationType>& output) const
|
||||
{
|
||||
for (int32 i = 0; i < ASSET_FILE_DATA_CHUNKS; i++)
|
||||
{
|
||||
@@ -130,7 +134,7 @@ struct FLAXENGINE_API AssetInitData
|
||||
/// <summary>
|
||||
/// The serialized asset version
|
||||
/// </summary>
|
||||
uint32 SerializedVersion;
|
||||
uint32 SerializedVersion = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The custom asset data (should be small, for eg. texture description structure).
|
||||
@@ -138,7 +142,6 @@ struct FLAXENGINE_API AssetInitData
|
||||
BytesContainer CustomData;
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
/// <summary>
|
||||
/// The asset metadata information. Stored in a Json format.
|
||||
/// </summary>
|
||||
@@ -148,24 +151,16 @@ struct FLAXENGINE_API AssetInitData
|
||||
/// Asset dependencies list used by the asset for tracking (eg. material functions used by material asset). The pair of asset ID and cached file edit time (for tracking modification).
|
||||
/// </summary>
|
||||
Array<Pair<Guid, DateTime>> Dependencies;
|
||||
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
AssetInitData()
|
||||
: SerializedVersion(0)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hash code.
|
||||
/// </summary>
|
||||
/// <returns>Hash Code</returns>
|
||||
uint32 GetHashCode() const
|
||||
{
|
||||
// Note: do not use Metadata/Dependencies because it may not be loaded (it's optional)
|
||||
|
||||
uint32 hashCode = GetHash(Header.ID);
|
||||
hashCode = (hashCode * 397) ^ SerializedVersion;
|
||||
hashCode = (hashCode * 397) ^ CustomData.Length();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "FlaxStorageReference.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
|
||||
class FlaxFile;
|
||||
class FlaxPackage;
|
||||
|
||||
@@ -5,10 +5,16 @@
|
||||
#include "FlaxPackage.h"
|
||||
#include "ContentStorageManager.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Serialization/FileWriteStream.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Serialization/JsonWriter.h"
|
||||
#include "Engine/Serialization/JsonWriters.h"
|
||||
#else
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#endif
|
||||
#include <ThirdParty/LZ4/lz4.h>
|
||||
|
||||
String AssetHeader::ToString() const
|
||||
@@ -194,13 +200,13 @@ void FlaxStorage::AddRef()
|
||||
|
||||
void FlaxStorage::RemoveRef()
|
||||
{
|
||||
ASSERT(_refCount > 0);
|
||||
|
||||
_refCount--;
|
||||
|
||||
if (_refCount == 0)
|
||||
if (_refCount > 0)
|
||||
{
|
||||
_lastRefLostTime = DateTime::NowUTC();
|
||||
_refCount--;
|
||||
if (_refCount == 0)
|
||||
{
|
||||
_lastRefLostTime = DateTime::NowUTC();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,6 +629,7 @@ bool FlaxStorage::LoadAssetChunk(FlaxChunk* chunk)
|
||||
stream->ReadBytes(tmpBuf.Get(), size);
|
||||
|
||||
// Decompress data
|
||||
PROFILE_CPU_NAMED("DecompressLZ4");
|
||||
chunk->Data.Allocate(originalSize);
|
||||
const int32 res = LZ4_decompress_safe((const char*)tmpBuf.Get(), chunk->Data.Get<char>(), size, originalSize);
|
||||
if (res <= 0)
|
||||
@@ -823,6 +830,7 @@ bool FlaxStorage::Create(WriteStream* stream, const AssetInitData* data, int32 d
|
||||
const FlaxChunk* chunk = chunks[i];
|
||||
if (chunk->Flags & FlaxChunkFlags::CompressedLZ4)
|
||||
{
|
||||
PROFILE_CPU_NAMED("CompressLZ4");
|
||||
const int32 srcSize = chunk->Data.Length();
|
||||
const int32 maxSize = LZ4_compressBound(srcSize);
|
||||
auto& chunkCompressed = compressedChunks[i];
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "FlaxStorage.h"
|
||||
|
||||
/// <summary>
|
||||
/// Flax Storage Container Reference
|
||||
/// Flax Storage container reference.
|
||||
/// </summary>
|
||||
struct FLAXENGINE_API FlaxStorageReference
|
||||
{
|
||||
@@ -44,10 +44,8 @@ public:
|
||||
|
||||
public:
|
||||
|
||||
// Assignment operator
|
||||
FlaxStorageReference& operator=(const FlaxStorageReference& other)
|
||||
{
|
||||
// Protect against invalid self-assignment
|
||||
if (this != &other)
|
||||
{
|
||||
if (_storage)
|
||||
@@ -56,7 +54,6 @@ public:
|
||||
if (_storage)
|
||||
_storage->AddRef();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ bool JsonStorageProxy::GetAssetInfo(const StringView& path, Guid& resultId, Stri
|
||||
document.Parse((const char*)fileData.Get(), fileData.Count());
|
||||
if (document.HasParseError())
|
||||
{
|
||||
Log::JsonParseException(document.GetParseError(), document.GetErrorOffset(), String(path));
|
||||
Log::JsonParseException(document.GetParseError(), document.GetErrorOffset(), path);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ bool JsonStorageProxy::ChangeId(const StringView& path, const Guid& newId)
|
||||
document.Parse((const char*)fileData.Get(), fileData.Count());
|
||||
if (document.HasParseError())
|
||||
{
|
||||
Log::JsonParseException(document.GetParseError(), document.GetErrorOffset(), String(path));
|
||||
Log::JsonParseException(document.GetParseError(), document.GetErrorOffset(), path);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "BinaryAssetUpgrader.h"
|
||||
#include "Engine/Audio/AudioClip.h"
|
||||
#include "Engine/Tools/AudioTool/OggVorbisDecoder.h"
|
||||
@@ -130,3 +132,5 @@ private:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "IAssetUpgrader.h"
|
||||
#include "Engine/Content/Storage/AssetHeader.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
@@ -9,7 +11,7 @@
|
||||
/// <summary>
|
||||
/// Binary asset upgrading context structure.
|
||||
/// </summary>
|
||||
struct AssetMigrationContext
|
||||
struct FLAXENGINE_API AssetMigrationContext
|
||||
{
|
||||
/// <summary>
|
||||
/// The input data.
|
||||
@@ -63,7 +65,7 @@ typedef bool (*UpgradeHandler)(AssetMigrationContext& context);
|
||||
/// Binary Assets Upgrader base class
|
||||
/// </summary>
|
||||
/// <seealso cref="IAssetUpgrader" />
|
||||
class BinaryAssetUpgrader : public IAssetUpgrader
|
||||
class FLAXENGINE_API BinaryAssetUpgrader : public IAssetUpgrader
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -205,3 +207,5 @@ public:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "BinaryAssetUpgrader.h"
|
||||
#include "Engine/Render2D/FontAsset.h"
|
||||
|
||||
@@ -71,3 +73,5 @@ private:
|
||||
return CopyChunk(context, 0);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "Engine/Core/Types/BaseTypes.h"
|
||||
|
||||
/// <summary>
|
||||
/// The assets upgrading objects interface.
|
||||
/// </summary>
|
||||
class IAssetUpgrader
|
||||
class FLAXENGINE_API IAssetUpgrader
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -27,3 +29,5 @@ public:
|
||||
/// <returns>True if perform conversion, otherwise false.</returns>
|
||||
virtual bool ShouldUpgrade(uint32 serializedVersion) const = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "BinaryAssetUpgrader.h"
|
||||
#include "Engine/Core/Core.h"
|
||||
#include "Engine/Platform/Platform.h"
|
||||
@@ -105,3 +107,5 @@ private:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "BinaryAssetUpgrader.h"
|
||||
#include "Engine/Core/Core.h"
|
||||
#include "Engine/Platform/Platform.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||
#include "Engine/Graphics/Models/ModelData.h"
|
||||
#include "Engine/Content/Asset.h"
|
||||
|
||||
/// <summary>
|
||||
/// Model Asset Upgrader
|
||||
@@ -1222,3 +1225,5 @@ private:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "BinaryAssetUpgrader.h"
|
||||
#include "Engine/Platform/Platform.h"
|
||||
#include "Engine/Graphics/Shaders/Cache/ShaderStorage.h"
|
||||
|
||||
/// <summary>
|
||||
/// Material Asset and Shader Asset Upgrader
|
||||
@@ -85,3 +88,5 @@ private:
|
||||
return CopyChunks(context);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "BinaryAssetUpgrader.h"
|
||||
#include "Engine/Content/Assets/SkinnedModel.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
@@ -97,3 +99,5 @@ private:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,10 +2,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "BinaryAssetUpgrader.h"
|
||||
#include "Engine/Platform/Platform.h"
|
||||
#include "Engine/Serialization/MemoryReadStream.h"
|
||||
#include "Engine/Serialization/MemoryWriteStream.h"
|
||||
#include "Engine/Graphics/Models/Types.h"
|
||||
#include "Engine/Core/Math/BoundingBox.h"
|
||||
#include "Engine/Core/Math/BoundingSphere.h"
|
||||
#include "Engine/Core/Math/Matrix.h"
|
||||
#include "Engine/Core/Math/Transform.h"
|
||||
|
||||
/// <summary>
|
||||
/// Skinned Model Asset Upgrader
|
||||
@@ -418,3 +425,5 @@ private:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
#include "BinaryAssetUpgrader.h"
|
||||
#include "Engine/Core/Core.h"
|
||||
#include "Engine/Platform/Platform.h"
|
||||
@@ -825,3 +827,5 @@ private:
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -229,3 +229,9 @@ public:
|
||||
OnSet(asset);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
uint32 GetHash(const WeakAssetReference<T>& key)
|
||||
{
|
||||
return GetHash(key.GetID());
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "CreateParticleEmitterFunction.h"
|
||||
#include "CreateAnimationGraphFunction.h"
|
||||
#include "CreateVisualScript.h"
|
||||
#include "CreateJson.h"
|
||||
|
||||
// Tags used to detect asset creation mode
|
||||
const String AssetsImportingManager::CreateTextureTag(TEXT("Texture"));
|
||||
@@ -91,6 +92,10 @@ CreateAssetResult CreateAssetContext::Run(const CreateAssetFunction& callback)
|
||||
if (result != CreateAssetResult::Ok)
|
||||
return result;
|
||||
|
||||
// Skip for non-flax assets (eg. json resource or custom asset type)
|
||||
if (!TargetAssetPath.EndsWith(ASSET_FILES_EXTENSION))
|
||||
return CreateAssetResult::Ok;
|
||||
|
||||
// Validate assigned TypeID
|
||||
if (Data.Header.TypeName.IsEmpty())
|
||||
{
|
||||
@@ -112,8 +117,7 @@ CreateAssetResult CreateAssetContext::Run(const CreateAssetFunction& callback)
|
||||
}
|
||||
|
||||
// Save file
|
||||
result = Save();
|
||||
|
||||
result = FlaxStorage::Create(OutputPath, Data) ? CreateAssetResult::CannotSaveFile : CreateAssetResult::Ok;
|
||||
if (result == CreateAssetResult::Ok)
|
||||
{
|
||||
_applyChangesResult = CreateAssetResult::Abort;
|
||||
@@ -161,11 +165,6 @@ void CreateAssetContext::AddMeta(JsonWriter& writer) const
|
||||
writer.String(Platform::GetUserName());
|
||||
}
|
||||
|
||||
CreateAssetResult CreateAssetContext::Save()
|
||||
{
|
||||
return FlaxStorage::Create(OutputPath, Data) ? CreateAssetResult::CannotSaveFile : CreateAssetResult::Ok;
|
||||
}
|
||||
|
||||
void CreateAssetContext::ApplyChanges()
|
||||
{
|
||||
// Get access
|
||||
@@ -231,8 +230,6 @@ bool AssetsImportingManager::Create(const String& tag, const StringView& outputP
|
||||
|
||||
bool AssetsImportingManager::Import(const StringView& inputPath, const StringView& outputPath, Guid& assetId, void* arg)
|
||||
{
|
||||
ASSERT(outputPath.EndsWith(StringView(ASSET_FILES_EXTENSION)));
|
||||
|
||||
LOG(Info, "Importing file '{0}' to '{1}'...", inputPath, outputPath);
|
||||
|
||||
// Check if input file exists
|
||||
@@ -246,8 +243,7 @@ bool AssetsImportingManager::Import(const StringView& inputPath, const StringVie
|
||||
const String extension = FileSystem::GetExtension(inputPath).ToLower();
|
||||
|
||||
// Special case for raw assets
|
||||
const String assetExtension = ASSET_FILES_EXTENSION;
|
||||
if (assetExtension.Compare(extension, StringSearchCase::IgnoreCase) == 0)
|
||||
if (StringView(ASSET_FILES_EXTENSION).Compare(StringView(extension), StringSearchCase::IgnoreCase) == 0)
|
||||
{
|
||||
// Simply copy file (content layer will resolve duplicated IDs, etc.)
|
||||
return FileSystem::CopyFile(outputPath, inputPath);
|
||||
@@ -266,8 +262,6 @@ bool AssetsImportingManager::Import(const StringView& inputPath, const StringVie
|
||||
|
||||
bool AssetsImportingManager::ImportIfEdited(const StringView& inputPath, const StringView& outputPath, Guid& assetId, void* arg)
|
||||
{
|
||||
ASSERT(outputPath.EndsWith(StringView(ASSET_FILES_EXTENSION)));
|
||||
|
||||
// Check if asset not exists
|
||||
if (!FileSystem::FileExists(outputPath))
|
||||
{
|
||||
@@ -338,7 +332,7 @@ bool AssetsImportingManager::Create(const Function<CreateAssetResult(CreateAsset
|
||||
else
|
||||
{
|
||||
// Ensure that path exists
|
||||
const String outputDirectory = StringUtils::GetDirectoryName(*outputPath);
|
||||
const String outputDirectory = StringUtils::GetDirectoryName(outputPath);
|
||||
if (FileSystem::CreateDirectory(outputDirectory))
|
||||
{
|
||||
LOG(Warning, "Cannot create directory '{0}'", outputDirectory);
|
||||
@@ -383,64 +377,67 @@ bool AssetsImportingManagerService::Init()
|
||||
AssetImporter InBuildImporters[] =
|
||||
{
|
||||
// Textures and Cube Textures
|
||||
{ TEXT("tga"), ImportTexture::Import },
|
||||
{ TEXT("dds"), ImportTexture::Import },
|
||||
{ TEXT("png"), ImportTexture::Import },
|
||||
{ TEXT("bmp"), ImportTexture::Import },
|
||||
{ TEXT("gif"), ImportTexture::Import },
|
||||
{ TEXT("tiff"), ImportTexture::Import },
|
||||
{ TEXT("tif"), ImportTexture::Import },
|
||||
{ TEXT("jpeg"), ImportTexture::Import },
|
||||
{ TEXT("jpg"), ImportTexture::Import },
|
||||
{ TEXT("hdr"), ImportTexture::Import },
|
||||
{ TEXT("raw"), ImportTexture::Import },
|
||||
{ TEXT("tga"), ASSET_FILES_EXTENSION, ImportTexture::Import },
|
||||
{ TEXT("dds"), ASSET_FILES_EXTENSION, ImportTexture::Import },
|
||||
{ TEXT("png"), ASSET_FILES_EXTENSION, ImportTexture::Import },
|
||||
{ TEXT("bmp"), ASSET_FILES_EXTENSION, ImportTexture::Import },
|
||||
{ TEXT("gif"), ASSET_FILES_EXTENSION, ImportTexture::Import },
|
||||
{ TEXT("tiff"), ASSET_FILES_EXTENSION, ImportTexture::Import },
|
||||
{ TEXT("tif"), ASSET_FILES_EXTENSION, ImportTexture::Import },
|
||||
{ TEXT("jpeg"), ASSET_FILES_EXTENSION, ImportTexture::Import },
|
||||
{ TEXT("jpg"), ASSET_FILES_EXTENSION, ImportTexture::Import },
|
||||
{ TEXT("hdr"), ASSET_FILES_EXTENSION, ImportTexture::Import },
|
||||
{ TEXT("raw"), ASSET_FILES_EXTENSION, ImportTexture::Import },
|
||||
|
||||
// IES Profiles
|
||||
{ TEXT("ies"), ImportTexture::ImportIES },
|
||||
{ TEXT("ies"), ASSET_FILES_EXTENSION, ImportTexture::ImportIES },
|
||||
|
||||
// Shaders
|
||||
{ TEXT("shader"), ImportShader::Import },
|
||||
{ TEXT("shader"), ASSET_FILES_EXTENSION, ImportShader::Import },
|
||||
|
||||
// Audio
|
||||
{ TEXT("wav"), ImportAudio::ImportWav },
|
||||
{ TEXT("mp3"), ImportAudio::ImportMp3 },
|
||||
{ TEXT("wav"), ASSET_FILES_EXTENSION, ImportAudio::ImportWav },
|
||||
{ TEXT("mp3"), ASSET_FILES_EXTENSION, ImportAudio::ImportMp3 },
|
||||
#if COMPILE_WITH_OGG_VORBIS
|
||||
{ TEXT("ogg"), ImportAudio::ImportOgg },
|
||||
{ TEXT("ogg"), ASSET_FILES_EXTENSION, ImportAudio::ImportOgg },
|
||||
#endif
|
||||
|
||||
// Fonts
|
||||
{ TEXT("ttf"), ImportFont::Import },
|
||||
{ TEXT("otf"), ImportFont::Import },
|
||||
{ TEXT("ttf"), ASSET_FILES_EXTENSION, ImportFont::Import },
|
||||
{ TEXT("otf"), ASSET_FILES_EXTENSION, ImportFont::Import },
|
||||
|
||||
// Models
|
||||
{ TEXT("obj"), ImportModelFile::Import },
|
||||
{ TEXT("fbx"), ImportModelFile::Import },
|
||||
{ TEXT("x"), ImportModelFile::Import },
|
||||
{ TEXT("dae"), ImportModelFile::Import },
|
||||
{ TEXT("gltf"), ImportModelFile::Import },
|
||||
{ TEXT("glb"), ImportModelFile::Import },
|
||||
{ TEXT("obj"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("fbx"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("x"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("dae"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("gltf"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("glb"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
|
||||
// gettext PO files
|
||||
{ TEXT("po"), TEXT("json"), CreateJson::ImportPo },
|
||||
|
||||
// Models (untested formats - may fail :/)
|
||||
{ TEXT("blend"), ImportModelFile::Import },
|
||||
{ TEXT("bvh"), ImportModelFile::Import },
|
||||
{ TEXT("ase"), ImportModelFile::Import },
|
||||
{ TEXT("ply"), ImportModelFile::Import },
|
||||
{ TEXT("dxf"), ImportModelFile::Import },
|
||||
{ TEXT("ifc"), ImportModelFile::Import },
|
||||
{ TEXT("nff"), ImportModelFile::Import },
|
||||
{ TEXT("smd"), ImportModelFile::Import },
|
||||
{ TEXT("vta"), ImportModelFile::Import },
|
||||
{ TEXT("mdl"), ImportModelFile::Import },
|
||||
{ TEXT("md2"), ImportModelFile::Import },
|
||||
{ TEXT("md3"), ImportModelFile::Import },
|
||||
{ TEXT("md5mesh"), ImportModelFile::Import },
|
||||
{ TEXT("q3o"), ImportModelFile::Import },
|
||||
{ TEXT("q3s"), ImportModelFile::Import },
|
||||
{ TEXT("ac"), ImportModelFile::Import },
|
||||
{ TEXT("stl"), ImportModelFile::Import },
|
||||
{ TEXT("lwo"), ImportModelFile::Import },
|
||||
{ TEXT("lws"), ImportModelFile::Import },
|
||||
{ TEXT("lxo"), ImportModelFile::Import },
|
||||
{ TEXT("blend"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("bvh"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("ase"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("ply"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("dxf"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("ifc"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("nff"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("smd"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("vta"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("mdl"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("md2"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("md3"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("md5mesh"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("q3o"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("q3s"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("ac"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("stl"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("lwo"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("lws"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
{ TEXT("lxo"), ASSET_FILES_EXTENSION, ImportModelFile::Import },
|
||||
};
|
||||
AssetsImportingManager::Importers.Add(InBuildImporters, ARRAY_COUNT(InBuildImporters));
|
||||
|
||||
|
||||
@@ -5,11 +5,16 @@
|
||||
#if COMPILE_WITH_ASSETS_IMPORTER
|
||||
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/Storage/JsonStorageProxy.h"
|
||||
#include "Engine/Content/Cache/AssetsCache.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Serialization/JsonWriters.h"
|
||||
#include "Engine/Localization/LocalizedStringTable.h"
|
||||
#include "Engine/Utilities/TextProcessing.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
|
||||
bool CreateJson::Create(const StringView& path, rapidjson_flax::StringBuffer& data, const String& dataTypename)
|
||||
@@ -41,6 +46,18 @@ bool CreateJson::Create(const StringView& path, StringAnsiView& data, StringAnsi
|
||||
LOG(Warning, "Asset will have different type name {0} -> {1}", typeName, String(dataTypename.Get()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const String directory = StringUtils::GetDirectoryName(path);
|
||||
if (!FileSystem::DirectoryExists(directory))
|
||||
{
|
||||
if (FileSystem::CreateDirectory(directory))
|
||||
{
|
||||
LOG(Warning, "Failed to create directory");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rapidjson_flax::StringBuffer buffer;
|
||||
|
||||
@@ -76,8 +93,184 @@ bool CreateJson::Create(const StringView& path, StringAnsiView& data, StringAnsi
|
||||
{
|
||||
asset->Reload();
|
||||
}
|
||||
else
|
||||
{
|
||||
Content::GetRegistry()->RegisterAsset(id, String(dataTypename), path);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FormatPoValue(String& value)
|
||||
{
|
||||
value.Replace(TEXT("\\n"), TEXT("\n"));
|
||||
value.Replace(TEXT("%s"), TEXT("{}"));
|
||||
value.Replace(TEXT("%d"), TEXT("{}"));
|
||||
}
|
||||
|
||||
CreateAssetResult CreateJson::ImportPo(CreateAssetContext& context)
|
||||
{
|
||||
// Base
|
||||
IMPORT_SETUP(LocalizedStringTable, 1);
|
||||
|
||||
// Load file (UTF-16)
|
||||
String inputData;
|
||||
if (File::ReadAllText(context.InputPath, inputData))
|
||||
{
|
||||
return CreateAssetResult::InvalidPath;
|
||||
}
|
||||
|
||||
// Use virtual asset for data storage and serialization
|
||||
AssetReference<LocalizedStringTable> asset = Content::CreateVirtualAsset<LocalizedStringTable>();
|
||||
if (!asset)
|
||||
return CreateAssetResult::Error;
|
||||
|
||||
// Parse PO format
|
||||
int32 pos = 0;
|
||||
int32 pluralCount = 0;
|
||||
int32 lineNumber = 0;
|
||||
bool fuzzy = false, hasNewContext = false;
|
||||
StringView msgctxt, msgid;
|
||||
String idTmp;
|
||||
while (pos < inputData.Length())
|
||||
{
|
||||
// Read line
|
||||
const int32 startPos = pos;
|
||||
while (pos < inputData.Length() && inputData[pos] != '\n')
|
||||
pos++;
|
||||
const StringView line(&inputData[startPos], pos - startPos);
|
||||
lineNumber++;
|
||||
pos++;
|
||||
const int32 valueStart = line.Find('\"') + 1;
|
||||
const int32 valueEnd = line.FindLast('\"');
|
||||
const StringView value(line.Get() + valueStart, Math::Max(valueEnd - valueStart, 0));
|
||||
|
||||
if (line.StartsWith(StringView(TEXT("msgid_plural"))))
|
||||
{
|
||||
// Plural form
|
||||
}
|
||||
else if (line.StartsWith(StringView(TEXT("msgid"))))
|
||||
{
|
||||
// Id
|
||||
msgid = value;
|
||||
|
||||
// Reset context if already used
|
||||
if (!hasNewContext)
|
||||
msgctxt = StringView();
|
||||
hasNewContext = false;
|
||||
}
|
||||
else if (line.StartsWith(StringView(TEXT("msgstr"))))
|
||||
{
|
||||
// String
|
||||
if (msgid.HasChars())
|
||||
{
|
||||
// Format message
|
||||
String msgstr(value);
|
||||
FormatPoValue(msgstr);
|
||||
|
||||
// Get message id
|
||||
StringView id = msgid;
|
||||
if (msgctxt.HasChars())
|
||||
{
|
||||
idTmp = String(msgctxt) + TEXT(".") + String(msgid);
|
||||
id = idTmp;
|
||||
}
|
||||
|
||||
int32 indexStart = line.Find('[');
|
||||
if (indexStart != -1 && indexStart < valueStart)
|
||||
{
|
||||
indexStart++;
|
||||
while (indexStart < line.Length() && StringUtils::IsWhitespace(line[indexStart]))
|
||||
indexStart++;
|
||||
int32 indexEnd = line.Find(']');
|
||||
while (indexEnd > indexStart && StringUtils::IsWhitespace(line[indexEnd - 1]))
|
||||
indexEnd--;
|
||||
int32 index = -1;
|
||||
StringUtils::Parse(line.Get() + indexStart, (uint32)(indexEnd - indexStart), &index);
|
||||
if (pluralCount <= 0)
|
||||
{
|
||||
LOG(Error, "Missing 'nplurals'. Cannot use plural message at line {0}", lineNumber);
|
||||
return CreateAssetResult::Error;
|
||||
}
|
||||
if (index < 0 || index > pluralCount)
|
||||
{
|
||||
LOG(Error, "Invalid plural message index at line {0}", lineNumber);
|
||||
return CreateAssetResult::Error;
|
||||
}
|
||||
|
||||
// Plural message
|
||||
asset->AddPluralString(id, msgstr, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Message
|
||||
asset->AddString(id, msgstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (line.StartsWith(StringView(TEXT("msgctxt"))))
|
||||
{
|
||||
// Context
|
||||
msgctxt = value;
|
||||
hasNewContext = true;
|
||||
}
|
||||
else if (line.StartsWith('\"'))
|
||||
{
|
||||
// Config
|
||||
const Char* pluralForms = StringUtils::Find(line.Get(), TEXT("Plural-Forms"));
|
||||
if (pluralForms != nullptr && pluralForms < line.Get() + line.Length() - 1)
|
||||
{
|
||||
// Process plural forms rule
|
||||
const Char* nplurals = StringUtils::Find(pluralForms, TEXT("nplurals"));
|
||||
if (nplurals && nplurals < line.Get() + line.Length())
|
||||
{
|
||||
while (*nplurals && *nplurals != '=')
|
||||
nplurals++;
|
||||
while (*nplurals && (StringUtils::IsWhitespace(*nplurals) || *nplurals == '='))
|
||||
nplurals++;
|
||||
const Char* npluralsStart = nplurals;
|
||||
while (*nplurals && !StringUtils::IsWhitespace(*nplurals) && *nplurals != ';')
|
||||
nplurals++;
|
||||
StringUtils::Parse(npluralsStart, (uint32)(nplurals - npluralsStart), &pluralCount);
|
||||
if (pluralCount < 0 || pluralCount > 100)
|
||||
{
|
||||
LOG(Error, "Invalid 'nplurals' at line {0}", lineNumber);
|
||||
return CreateAssetResult::Error;
|
||||
}
|
||||
}
|
||||
// TODO: parse plural forms rule
|
||||
}
|
||||
const Char* language = StringUtils::Find(line.Get(), TEXT("Language"));
|
||||
if (language != nullptr && language < line.Get() + line.Length() - 1)
|
||||
{
|
||||
// Process language locale
|
||||
while (*language && *language != ':')
|
||||
language++;
|
||||
language++;
|
||||
while (*language && StringUtils::IsWhitespace(*language))
|
||||
language++;
|
||||
const Char* languageStart = language;
|
||||
while (*language && !StringUtils::IsWhitespace(*language) && *language != '\\' && *language != '\"')
|
||||
language++;
|
||||
asset->Locale.Set(languageStart, (int32)(language - languageStart));
|
||||
if (asset->Locale == TEXT("English"))
|
||||
asset->Locale = TEXT("en");
|
||||
if (asset->Locale.Length() > 5)
|
||||
LOG(Warning, "Imported .po file uses invalid locale '{0}'", asset->Locale);
|
||||
}
|
||||
}
|
||||
else if (line.StartsWith('#') || line.IsEmpty())
|
||||
{
|
||||
// Comment
|
||||
const Char* fuzzyPos = StringUtils::Find(line.Get(), TEXT("fuzzy"));
|
||||
fuzzy |= fuzzyPos != nullptr && fuzzyPos < line.Get() + line.Length() - 1;
|
||||
}
|
||||
}
|
||||
if (asset->Locale.IsEmpty())
|
||||
LOG(Warning, "Imported .po file has missing locale");
|
||||
|
||||
// Save asset
|
||||
return asset->Save(context.TargetAssetPath) ? CreateAssetResult::CannotSaveFile : CreateAssetResult::Ok;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
static bool Create(const StringView& path, rapidjson_flax::StringBuffer& data, const String& dataTypename);
|
||||
static bool Create(const StringView& path, rapidjson_flax::StringBuffer& data, const char* dataTypename);
|
||||
static bool Create(const StringView& path, StringAnsiView& data, StringAnsiView& dataTypename);
|
||||
static CreateAssetResult ImportPo(CreateAssetContext& context);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -115,7 +115,8 @@ CreateAssetResult ImportModelFile::Import(CreateAssetContext& context)
|
||||
// Import model file
|
||||
ModelData modelData;
|
||||
String errorMsg;
|
||||
if (ModelTool::ImportModel(context.InputPath, modelData, options, errorMsg, StringUtils::GetDirectoryName(context.TargetAssetPath) / StringUtils::GetFileNameWithoutExtension(context.InputPath)))
|
||||
String autoImportOutput = String(StringUtils::GetDirectoryName(context.TargetAssetPath)) / StringUtils::GetFileNameWithoutExtension(context.InputPath);
|
||||
if (ModelTool::ImportModel(context.InputPath, modelData, options, errorMsg, autoImportOutput))
|
||||
{
|
||||
LOG(Error, "Cannot import model file. {0}", errorMsg);
|
||||
return CreateAssetResult::Error;
|
||||
|
||||
@@ -111,12 +111,6 @@ public:
|
||||
/// <param name="writer">The json metadata writer.</param>
|
||||
void AddMeta(JsonWriter& writer) const;
|
||||
|
||||
/// <summary>
|
||||
/// Save asset file data to the hard drive
|
||||
/// </summary>
|
||||
/// <returns>Saving result</returns>
|
||||
CreateAssetResult Save();
|
||||
|
||||
private:
|
||||
|
||||
void ApplyChanges();
|
||||
@@ -130,12 +124,17 @@ struct AssetImporter
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Extension of the file to import with that importer
|
||||
/// Extension of the file to import with that importer (without leading dot).
|
||||
/// </summary>
|
||||
String FileExtension;
|
||||
|
||||
/// <summary>
|
||||
/// Call asset importing process
|
||||
/// Extension of the output file as output with that importer (without leading dot).
|
||||
/// </summary>
|
||||
String ResultExtension;
|
||||
|
||||
/// <summary>
|
||||
/// Callback for the asset importing process.
|
||||
/// </summary>
|
||||
CreateAssetFunction Callback;
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
#include "Engine/Platform/Platform.h"
|
||||
#include "Engine/Core/Memory/Memory.h"
|
||||
#include "Engine/Core/Memory/Allocation.h"
|
||||
@@ -47,6 +48,20 @@ public:
|
||||
_allocation.Allocate(capacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Array"/> class.
|
||||
/// </summary>
|
||||
/// <param name="initList">The initial values defined in the array.</param>
|
||||
Array(std::initializer_list<T> initList)
|
||||
{
|
||||
_count = _capacity = (int32)initList.size();
|
||||
if (_count > 0)
|
||||
{
|
||||
_allocation.Allocate(_count);
|
||||
Memory::ConstructItems(Get(), initList.begin(), _count);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Array"/> class.
|
||||
/// </summary>
|
||||
@@ -123,6 +138,24 @@ public:
|
||||
_allocation.Swap(other._allocation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The assignment operator that deletes the current collection of items and the copies items from the initializer list.
|
||||
/// </summary>
|
||||
/// <param name="initList">The other collection to copy.</param>
|
||||
/// <returns>The reference to this.</returns>
|
||||
Array& operator=(std::initializer_list<T> initList) noexcept
|
||||
{
|
||||
Memory::DestructItems(Get(), _count);
|
||||
|
||||
_count = _capacity = (int32)initList.size();
|
||||
if (_capacity > 0)
|
||||
{
|
||||
_allocation.Allocate(_capacity);
|
||||
Memory::ConstructItems(Get(), initList.begin(), _count);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The assignment operator that deletes the current collection of items and the copies items from the other array.
|
||||
/// </summary>
|
||||
@@ -725,7 +758,6 @@ public:
|
||||
/// <summary>
|
||||
/// Performs pop from stack operation (stack grows at the end of the collection).
|
||||
/// </summary>
|
||||
/// <returns>The item.</returns>
|
||||
T Pop()
|
||||
{
|
||||
T item(Last());
|
||||
@@ -736,19 +768,19 @@ public:
|
||||
/// <summary>
|
||||
/// Peeks items which is at the top of the stack (stack grows at the end of the collection).
|
||||
/// </summary>
|
||||
/// <returns>The item.</returns>
|
||||
FORCE_INLINE T& Peek()
|
||||
{
|
||||
return Last();
|
||||
ASSERT(_count > 0);
|
||||
return Get()[_count - 1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Peeks items which is at the top of the stack (stack grows at the end of the collection).
|
||||
/// </summary>
|
||||
/// <returns>The item.</returns>
|
||||
FORCE_INLINE const T& Peek() const
|
||||
{
|
||||
return Last();
|
||||
ASSERT(_count > 0);
|
||||
return Get()[_count - 1];
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Core/Memory/Memory.h"
|
||||
#include "Engine/Core/Collections/HashFunctions.h"
|
||||
#include "Engine/Core/Collections/Config.h"
|
||||
|
||||
@@ -781,7 +781,8 @@ public:
|
||||
/// Gets the keys collection to the output array (will contain unique items).
|
||||
/// </summary>
|
||||
/// <param name="result">The result.</param>
|
||||
void GetKeys(Array<KeyType>& result) const
|
||||
template<typename AllocationType>
|
||||
void GetKeys(Array<KeyType, AllocationType>& result) const
|
||||
{
|
||||
for (auto i = Begin(); i.IsNotEnd(); ++i)
|
||||
result.Add(i->Key);
|
||||
@@ -791,7 +792,8 @@ public:
|
||||
/// Gets the values collection to the output array (may contain duplicates).
|
||||
/// </summary>
|
||||
/// <param name="result">The result.</param>
|
||||
void GetValues(Array<ValueType>& result) const
|
||||
template<typename AllocationType>
|
||||
void GetValues(Array<ValueType, AllocationType>& result) const
|
||||
{
|
||||
for (auto i = Begin(); i.IsNotEnd(); ++i)
|
||||
result.Add(i->Value);
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "Engine/Input/InputSettings.h"
|
||||
#include "Engine/Audio/AudioSettings.h"
|
||||
#include "Engine/Navigation/NavigationSettings.h"
|
||||
#include "Engine/Localization/LocalizationSettings.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Content/JsonAsset.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
@@ -100,7 +101,12 @@ bool GameSettings::Load()
|
||||
auto settings = Get();
|
||||
if (!settings)
|
||||
{
|
||||
#if USE_EDITOR
|
||||
// Allow lack of Game Settings in Editor
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Preload all settings assets
|
||||
@@ -122,6 +128,7 @@ bool GameSettings::Load()
|
||||
PRELOAD_SETTINGS(Input);
|
||||
PRELOAD_SETTINGS(Graphics);
|
||||
PRELOAD_SETTINGS(Navigation);
|
||||
PRELOAD_SETTINGS(Localization);
|
||||
PRELOAD_SETTINGS(GameCooking);
|
||||
#undef PRELOAD_SETTINGS
|
||||
|
||||
@@ -153,6 +160,7 @@ void GameSettings::Apply()
|
||||
APPLY_SETTINGS(InputSettings);
|
||||
APPLY_SETTINGS(GraphicsSettings);
|
||||
APPLY_SETTINGS(NavigationSettings);
|
||||
APPLY_SETTINGS(LocalizationSettings);
|
||||
APPLY_SETTINGS(BuildSettings);
|
||||
APPLY_SETTINGS(PlatformSettings);
|
||||
#undef APPLY_SETTINGS
|
||||
@@ -192,6 +200,7 @@ void GameSettings::Deserialize(DeserializeStream& stream, ISerializeModifier* mo
|
||||
DESERIALIZE(Input);
|
||||
DESERIALIZE(Graphics);
|
||||
DESERIALIZE(Navigation);
|
||||
DESERIALIZE(Localization);
|
||||
DESERIALIZE(GameCooking);
|
||||
|
||||
// Per-platform settings containers
|
||||
|
||||
@@ -79,6 +79,12 @@ namespace FlaxEditor.Content.Settings
|
||||
[EditorOrder(1045), EditorDisplay("Other Settings"), AssetReference(typeof(NavigationSettings), true), Tooltip("Reference to Navigation Settings asset")]
|
||||
public JsonAsset Navigation;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to <see cref="LocalizationSettings"/> asset.
|
||||
/// </summary>
|
||||
[EditorOrder(1046), EditorDisplay("Other Settings"), AssetReference(typeof(LocalizationSettings), true), Tooltip("Reference to Localization Settings asset")]
|
||||
public JsonAsset Localization;
|
||||
|
||||
/// <summary>
|
||||
/// Reference to <see cref="BuildSettings"/> asset.
|
||||
/// </summary>
|
||||
@@ -219,6 +225,8 @@ namespace FlaxEditor.Content.Settings
|
||||
return LoadAsset<GraphicsSettings>(gameSettings.Graphics) as T;
|
||||
if (type == typeof(NavigationSettings))
|
||||
return LoadAsset<NavigationSettings>(gameSettings.Navigation) as T;
|
||||
if (type == typeof(LocalizationSettings))
|
||||
return LoadAsset<LocalizationSettings>(gameSettings.Localization) as T;
|
||||
if (type == typeof(BuildSettings))
|
||||
return LoadAsset<BuildSettings>(gameSettings.GameCooking) as T;
|
||||
if (type == typeof(InputSettings))
|
||||
@@ -321,6 +329,8 @@ namespace FlaxEditor.Content.Settings
|
||||
return SaveAsset(gameSettings, ref gameSettings.Graphics, obj);
|
||||
if (type == typeof(NavigationSettings))
|
||||
return SaveAsset(gameSettings, ref gameSettings.Navigation, obj);
|
||||
if (type == typeof(LocalizationSettings))
|
||||
return SaveAsset(gameSettings, ref gameSettings.Localization, obj);
|
||||
if (type == typeof(BuildSettings))
|
||||
return SaveAsset(gameSettings, ref gameSettings.GameCooking, obj);
|
||||
if (type == typeof(InputSettings))
|
||||
|
||||
@@ -68,6 +68,7 @@ public:
|
||||
Guid Input;
|
||||
Guid Graphics;
|
||||
Guid Navigation;
|
||||
Guid Localization;
|
||||
Guid GameCooking;
|
||||
|
||||
// Per-platform settings containers
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Config/Settings.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
|
||||
/// <summary>
|
||||
/// Layers and objects tags settings.
|
||||
|
||||
@@ -15,31 +15,31 @@ public:
|
||||
/// <summary>
|
||||
/// The target amount of the game logic updates per second (script updates frequency).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(1), DefaultValue(30.0f), Limit(0, 1000), EditorDisplay(\"General\", \"Update FPS\")")
|
||||
float UpdateFPS = 30.0f;
|
||||
API_FIELD(Attributes="EditorOrder(1), Limit(0, 1000), EditorDisplay(\"General\", \"Update FPS\")")
|
||||
float UpdateFPS = 60.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The target amount of the physics simulation updates per second (also fixed updates frequency).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(2), DefaultValue(60.0f), Limit(0, 1000), EditorDisplay(\"General\", \"Physics FPS\")")
|
||||
API_FIELD(Attributes="EditorOrder(2), Limit(0, 1000), EditorDisplay(\"General\", \"Physics FPS\")")
|
||||
float PhysicsFPS = 60.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The target amount of the frames rendered per second (actual game FPS).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(3), DefaultValue(60.0f), Limit(0, 1000), EditorDisplay(\"General\", \"Draw FPS\")")
|
||||
API_FIELD(Attributes="EditorOrder(3), Limit(0, 1000), EditorDisplay(\"General\", \"Draw FPS\")")
|
||||
float DrawFPS = 60.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The game time scale factor. Default is 1.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(10), DefaultValue(1.0f), Limit(0, 1000.0f, 0.1f), EditorDisplay(\"General\")")
|
||||
API_FIELD(Attributes="EditorOrder(10), Limit(0, 1000.0f, 0.1f), EditorDisplay(\"General\")")
|
||||
float TimeScale = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum allowed delta time (in seconds) for the game logic update step.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(20), DefaultValue(0.1f), Limit(0.1f, 1000.0f, 0.01f), EditorDisplay(\"General\")")
|
||||
API_FIELD(Attributes="EditorOrder(20), Limit(0.1f, 1000.0f, 0.01f), EditorDisplay(\"General\")")
|
||||
float MaxUpdateDeltaTime = 0.1f;
|
||||
|
||||
public:
|
||||
|
||||
@@ -4,11 +4,6 @@
|
||||
|
||||
#include "Engine/Core/Memory/Allocation.h"
|
||||
|
||||
template<typename>
|
||||
class Function;
|
||||
template<typename... Params>
|
||||
class Delegate;
|
||||
|
||||
/// <summary>
|
||||
/// The function object.
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Compiler.h"
|
||||
|
||||
/// <summary>
|
||||
/// Helper class used to delete another object.
|
||||
/// </summary>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -156,9 +156,9 @@ void Log::Logger::Dispose()
|
||||
WriteFloor();
|
||||
|
||||
// Close
|
||||
LogAfterInit = false;
|
||||
if (LogAfterInit)
|
||||
{
|
||||
LogAfterInit = false;
|
||||
LogFile->Close();
|
||||
Delete(LogFile);
|
||||
LogFile = nullptr;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "../Types/String.h"
|
||||
|
||||
const BoundingBox BoundingBox::Empty(Vector3(MAX_float), Vector3(MIN_float));
|
||||
const BoundingBox BoundingBox::Zero(Vector3(0.0f), Vector3(0.0f));
|
||||
const BoundingBox BoundingBox::Zero(Vector3(0.0f));
|
||||
|
||||
String BoundingBox::ToString() const
|
||||
{
|
||||
|
||||
@@ -45,6 +45,16 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BoundingBox"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="point">The location of the empty bounding box.</param>
|
||||
BoundingBox(const Vector3& point)
|
||||
: Minimum(point)
|
||||
, Maximum(point)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BoundingBox"/> struct.
|
||||
/// </summary>
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace FlaxEngine
|
||||
public static class CollisionsHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines the closest point between a point and a line.
|
||||
/// Determines the closest point between a point and a line segment.
|
||||
/// </summary>
|
||||
/// <param name="point">The point to test.</param>
|
||||
/// <param name="p0">The line first point.</param>
|
||||
|
||||
51
Source/Engine/Core/Math/Int2.cpp
Normal file
51
Source/Engine/Core/Math/Int2.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "Int2.h"
|
||||
#include "Int3.h"
|
||||
#include "Int4.h"
|
||||
#include "Vector2.h"
|
||||
#include "Vector3.h"
|
||||
#include "Vector4.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
|
||||
static_assert(sizeof(Int2) == 8, "Invalid Int2 type size.");
|
||||
|
||||
const Int2 Int2::Zero(0);
|
||||
const Int2 Int2::One(1);
|
||||
const Int2 Int2::Minimum(MIN_int32);
|
||||
const Int2 Int2::Maximum(MAX_int32);
|
||||
|
||||
Int2::Int2(const Int3& xyz)
|
||||
: X(xyz.X)
|
||||
, Y(xyz.Y)
|
||||
{
|
||||
}
|
||||
|
||||
Int2::Int2(const Int4& xyzw)
|
||||
: X(xyzw.X)
|
||||
, Y(xyzw.Y)
|
||||
{
|
||||
}
|
||||
|
||||
Int2::Int2(const Vector2& xy)
|
||||
: X(static_cast<int32>(xy.X))
|
||||
, Y(static_cast<int32>(xy.Y))
|
||||
{
|
||||
}
|
||||
|
||||
Int2::Int2(const Vector3& xyz)
|
||||
: X(static_cast<int32>(xyz.X))
|
||||
, Y(static_cast<int32>(xyz.Y))
|
||||
{
|
||||
}
|
||||
|
||||
Int2::Int2(const Vector4& xyzw)
|
||||
: X(static_cast<int32>(xyzw.X))
|
||||
, Y(static_cast<int32>(xyzw.Y))
|
||||
{
|
||||
}
|
||||
|
||||
String Int2::ToString() const
|
||||
{
|
||||
return String::Format(TEXT("{}"), *this);
|
||||
}
|
||||
@@ -12,9 +12,8 @@ namespace FlaxEngine
|
||||
/// Represents a two dimensional mathematical vector (signed integers).
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
[TypeConverter(typeof(TypeConverters.Int2Converter))]
|
||||
public struct Int2 : IEquatable<Int2>, IFormattable
|
||||
partial struct Int2 : IEquatable<Int2>, IFormattable
|
||||
{
|
||||
private static readonly string _formatString = "X:{0} Y:{1}";
|
||||
|
||||
@@ -53,16 +52,6 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
public static readonly Int2 Maximum = new Int2(int.MaxValue);
|
||||
|
||||
/// <summary>
|
||||
/// The X component of the vector.
|
||||
/// </summary>
|
||||
public int X;
|
||||
|
||||
/// <summary>
|
||||
/// The Y component of the vector.
|
||||
/// </summary>
|
||||
public int Y;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Int2" /> struct.
|
||||
/// </summary>
|
||||
|
||||
@@ -6,26 +6,27 @@
|
||||
#include "Engine/Core/Formatting.h"
|
||||
#include "Engine/Core/Templates.h"
|
||||
|
||||
struct Vector2;
|
||||
struct Vector3;
|
||||
struct Vector4;
|
||||
|
||||
/// <summary>
|
||||
/// Two-components vector (32 bit integer type).
|
||||
/// </summary>
|
||||
API_STRUCT(InBuild) struct FLAXENGINE_API Int2
|
||||
API_STRUCT() struct FLAXENGINE_API Int2
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(Int2);
|
||||
public:
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
// X component
|
||||
int32 X;
|
||||
/// <summary>
|
||||
/// The X component.
|
||||
/// </summary>
|
||||
API_FIELD() int32 X;
|
||||
|
||||
// Y component
|
||||
int32 Y;
|
||||
/// <summary>
|
||||
/// The Y component.
|
||||
/// </summary>
|
||||
API_FIELD() int32 Y;
|
||||
};
|
||||
|
||||
// Raw values
|
||||
@@ -40,6 +41,12 @@ public:
|
||||
// Vector with all components equal 1
|
||||
static const Int2 One;
|
||||
|
||||
// A minimum Int2
|
||||
static const Int2 Minimum;
|
||||
|
||||
// A maximum Int2
|
||||
static const Int2 Maximum;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
@@ -67,9 +74,25 @@ public:
|
||||
}
|
||||
|
||||
// Init
|
||||
// @param v Vector to use X and Y components
|
||||
explicit Int2(const Vector2& v);
|
||||
// @param xyz Int3 to use X and Y components
|
||||
Int2(const Int3& xyz);
|
||||
|
||||
// Init
|
||||
// @param xyzw Int4 to use X and Y components
|
||||
Int2(const Int4& xyzw);
|
||||
|
||||
// Init
|
||||
// @param xy Vector2 to use X and Y components
|
||||
explicit Int2(const Vector2& xy);
|
||||
|
||||
// Init
|
||||
// @param xyz Vector3 to use X and Y components
|
||||
explicit Int2(const Vector3& xyz);
|
||||
|
||||
// Init
|
||||
// @param xyzw Vector4 to use X and Y components
|
||||
explicit Int2(const Vector4& xyzw);
|
||||
|
||||
public:
|
||||
|
||||
String ToString() const;
|
||||
@@ -211,29 +234,29 @@ public:
|
||||
|
||||
public:
|
||||
|
||||
static void Add(const Int2& a, const Int2& b, Int2* result)
|
||||
static void Add(const Int2& a, const Int2& b, Int2& result)
|
||||
{
|
||||
result->X = a.X + b.X;
|
||||
result->Y = a.Y + b.Y;
|
||||
result.X = a.X + b.X;
|
||||
result.Y = a.Y + b.Y;
|
||||
}
|
||||
|
||||
static Int2 Add(const Int2& a, const Int2& b)
|
||||
{
|
||||
Int2 result;
|
||||
Add(a, b, &result);
|
||||
Add(a, b, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void Subtract(const Int2& a, const Int2& b, Int2* result)
|
||||
static void Subtract(const Int2& a, const Int2& b, Int2& result)
|
||||
{
|
||||
result->X = a.X - b.X;
|
||||
result->Y = a.Y - b.Y;
|
||||
result.X = a.X - b.X;
|
||||
result.Y = a.Y - b.Y;
|
||||
}
|
||||
|
||||
static Int2 Subtract(const Int2& a, const Int2& b)
|
||||
{
|
||||
Int2 result;
|
||||
Subtract(a, b, &result);
|
||||
Subtract(a, b, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -257,17 +280,112 @@ public:
|
||||
return Int2(a.X / b, a.Y / b);
|
||||
}
|
||||
|
||||
// Creates vector from minimum components of two vectors
|
||||
/// <summary>
|
||||
/// Gets a value indicting whether this vector is zero.
|
||||
/// </summary>
|
||||
/// <returns> True if the vector is zero, otherwise false.</returns>
|
||||
bool IsZero() const
|
||||
{
|
||||
return X == 0 && Y == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicting whether any vector component is zero.
|
||||
/// </summary>
|
||||
/// <returns> True if a component is zero, otherwise false.</returns>
|
||||
bool IsAnyZero() const
|
||||
{
|
||||
return X == 0 || Y == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicting whether this vector is one.
|
||||
/// </summary>
|
||||
/// <returns> True if the vector is one, otherwise false.</returns>
|
||||
bool IsOne() const
|
||||
{
|
||||
return X == 1 && Y == 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates a vector with values being opposite to values of that vector
|
||||
/// </summary>
|
||||
/// <returns>Negative vector</returns>
|
||||
Int2 GetNegative() const
|
||||
{
|
||||
return Int2(-X, -Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns average arithmetic of all the components
|
||||
/// </summary>
|
||||
/// <returns>Average arithmetic of all the components</returns>
|
||||
float AverageArithmetic() const
|
||||
{
|
||||
return (X + Y) * 0.5f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets sum of all vector components values
|
||||
/// </summary>
|
||||
/// <returns>Sum of X, Y, Z and W</returns>
|
||||
int32 SumValues() const
|
||||
{
|
||||
return X + Y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns minimum value of all the components
|
||||
/// </summary>
|
||||
/// <returns>Minimum value</returns>
|
||||
int32 MinValue() const
|
||||
{
|
||||
return Math::Min(X, Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns maximum value of all the components
|
||||
/// </summary>
|
||||
/// <returns>Maximum value</returns>
|
||||
int32 MaxValue() const
|
||||
{
|
||||
return Math::Max(X, Y);
|
||||
}
|
||||
|
||||
|
||||
// Returns a vector containing the smallest components of the specified vectors
|
||||
// @param a The first source vector
|
||||
// @param b The second source vector
|
||||
static Int2 Min(const Int2& a, const Int2& b)
|
||||
{
|
||||
return Int2(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y);
|
||||
}
|
||||
|
||||
// Creates vector from maximum components of two vectors
|
||||
// Returns a vector containing the largest components of the specified vectors
|
||||
// @param a The first source vector
|
||||
// @param b The second source vector
|
||||
static Int2 Max(const Int2& a, const Int2& b)
|
||||
{
|
||||
return Int2(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y);
|
||||
}
|
||||
|
||||
// Returns a vector containing the smallest components of the specified vectors
|
||||
// @param a The first source vector
|
||||
// @param b The second source vector
|
||||
// @param result When the method completes, contains an new vector composed of the smallest components of the source vectors
|
||||
static void Min(const Int2& a, const Int2& b, Int2& result)
|
||||
{
|
||||
result = Int2(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y);
|
||||
}
|
||||
|
||||
// Returns a vector containing the largest components of the specified vectors
|
||||
// @param a The first source vector
|
||||
// @param b The second source vector
|
||||
// @param result When the method completes, contains an new vector composed of the largest components of the source vectors
|
||||
static void Max(const Int2& a, const Int2& b, Int2& result)
|
||||
{
|
||||
result = Int2(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
56
Source/Engine/Core/Math/Int3.cpp
Normal file
56
Source/Engine/Core/Math/Int3.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "Int2.h"
|
||||
#include "Int3.h"
|
||||
#include "Int4.h"
|
||||
#include "Vector2.h"
|
||||
#include "Vector3.h"
|
||||
#include "Vector4.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
|
||||
static_assert(sizeof(Int3) == 12, "Invalid Int3 type size.");
|
||||
|
||||
const Int3 Int3::Zero(0);
|
||||
const Int3 Int3::One(1);
|
||||
const Int3 Int3::Minimum(MIN_int32);
|
||||
const Int3 Int3::Maximum(MAX_int32);
|
||||
|
||||
Int3::Int3(const Int2& xy, int32 z)
|
||||
: X(xy.X)
|
||||
, Y(xy.Y)
|
||||
, Z(z)
|
||||
{
|
||||
}
|
||||
|
||||
Int3::Int3(const Int4& xyzw)
|
||||
: X(xyzw.X)
|
||||
, Y(xyzw.Y)
|
||||
, Z(xyzw.Z)
|
||||
{
|
||||
}
|
||||
|
||||
Int3::Int3(const Vector2& xy, int32 z)
|
||||
: X(static_cast<int32>(xy.X))
|
||||
, Y(static_cast<int32>(xy.Y))
|
||||
, Z(z)
|
||||
{
|
||||
}
|
||||
|
||||
Int3::Int3(const Vector3& xyz)
|
||||
: X(static_cast<int32>(xyz.X))
|
||||
, Y(static_cast<int32>(xyz.Y))
|
||||
, Z(static_cast<int32>(xyz.Z))
|
||||
{
|
||||
}
|
||||
|
||||
Int3::Int3(const Vector4& xyzw)
|
||||
: X(static_cast<int32>(xyzw.X))
|
||||
, Y(static_cast<int32>(xyzw.Y))
|
||||
, Z(static_cast<int32>(xyzw.Z))
|
||||
{
|
||||
}
|
||||
|
||||
String Int3::ToString() const
|
||||
{
|
||||
return String::Format(TEXT("{}"), *this);
|
||||
}
|
||||
@@ -12,9 +12,8 @@ namespace FlaxEngine
|
||||
/// Represents a three dimensional mathematical vector (signed integers).
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
[TypeConverter(typeof(TypeConverters.Int3Converter))]
|
||||
public struct Int3 : IEquatable<Int3>, IFormattable
|
||||
partial struct Int3 : IEquatable<Int3>, IFormattable
|
||||
{
|
||||
private static readonly string _formatString = "X:{0} Y:{1} Z:{2}";
|
||||
|
||||
@@ -58,21 +57,6 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
public static readonly Int3 Maximum = new Int3(int.MaxValue);
|
||||
|
||||
/// <summary>
|
||||
/// The X component of the vector.
|
||||
/// </summary>
|
||||
public int X;
|
||||
|
||||
/// <summary>
|
||||
/// The Y component of the vector.
|
||||
/// </summary>
|
||||
public int Y;
|
||||
|
||||
/// <summary>
|
||||
/// The Z component of the vector.
|
||||
/// </summary>
|
||||
public int Z;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Int3" /> struct.
|
||||
/// </summary>
|
||||
|
||||
@@ -6,29 +6,33 @@
|
||||
#include "Engine/Core/Formatting.h"
|
||||
#include "Engine/Core/Templates.h"
|
||||
|
||||
struct Vector2;
|
||||
struct Vector3;
|
||||
struct Vector4;
|
||||
|
||||
/// <summary>
|
||||
/// Three-components vector (32 bit integer type).
|
||||
/// </summary>
|
||||
API_STRUCT(InBuild) struct FLAXENGINE_API Int3
|
||||
API_STRUCT() struct FLAXENGINE_API Int3
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(Int3);
|
||||
public:
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
// X component
|
||||
int32 X;
|
||||
/// <summary>
|
||||
/// The X component.
|
||||
/// </summary>
|
||||
API_FIELD() int32 X;
|
||||
|
||||
// Y component
|
||||
int32 Y;
|
||||
/// <summary>
|
||||
/// The Y component.
|
||||
/// </summary>
|
||||
API_FIELD() int32 Y;
|
||||
|
||||
// Y component
|
||||
int32 Z;
|
||||
/// <summary>
|
||||
/// The Z component.
|
||||
/// </summary>
|
||||
API_FIELD() int32 Z;
|
||||
};
|
||||
|
||||
// Raw values
|
||||
@@ -43,6 +47,12 @@ public:
|
||||
// Vector with all components equal 1
|
||||
static const Int3 One;
|
||||
|
||||
// A minimum Int3
|
||||
static const Int3 Minimum;
|
||||
|
||||
// A maximum Int3
|
||||
static const Int3 Maximum;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
@@ -73,19 +83,293 @@ public:
|
||||
}
|
||||
|
||||
// Init
|
||||
// @param v Vector to use X, Y and Z components
|
||||
explicit Int3(const Vector3& v);
|
||||
// @param v Int2 to use X and Y components
|
||||
// @param z Z component value
|
||||
Int3(const Int2& xy, int32 z);
|
||||
|
||||
// Init
|
||||
// @param v Int4 to use X and Y components
|
||||
Int3(const Int4& xyzw);
|
||||
|
||||
// Init
|
||||
// @param v Vector2 to use X and Y components
|
||||
// @param z Z component value
|
||||
explicit Int3(const Vector2& xy, int32 z);
|
||||
|
||||
// Init
|
||||
// @param v Vector3 to use X, Y and Z components
|
||||
explicit Int3(const Vector3& xyz);
|
||||
|
||||
// Init
|
||||
// @param v Vector4 to use X and Y components
|
||||
explicit Int3(const Vector4& xyzw);
|
||||
|
||||
public:
|
||||
|
||||
String ToString() const;
|
||||
|
||||
public:
|
||||
|
||||
// Arithmetic operators with Int2
|
||||
|
||||
Int3 operator+(const Int3& b) const
|
||||
{
|
||||
return Add(*this, b);
|
||||
}
|
||||
|
||||
Int3 operator-(const Int3& b) const
|
||||
{
|
||||
return Subtract(*this, b);
|
||||
}
|
||||
|
||||
Int3 operator*(const Int3& b) const
|
||||
{
|
||||
return Multiply(*this, b);
|
||||
}
|
||||
|
||||
Int3 operator/(const Int3& b) const
|
||||
{
|
||||
return Divide(*this, b);
|
||||
}
|
||||
|
||||
Int3 operator-() const
|
||||
{
|
||||
return Int3(-X, -Y, -Z);
|
||||
}
|
||||
|
||||
// op= operators with Int2
|
||||
|
||||
Int3& operator+=(const Int3& b)
|
||||
{
|
||||
*this = Add(*this, b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Int3& operator-=(const Int3& b)
|
||||
{
|
||||
*this = Subtract(*this, b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Int3& operator*=(const Int3& b)
|
||||
{
|
||||
*this = Multiply(*this, b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Int3& operator/=(const Int3& b)
|
||||
{
|
||||
*this = Divide(*this, b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Arithmetic operators with int32
|
||||
|
||||
Int3 operator+(int32 b) const
|
||||
{
|
||||
return Add(*this, b);
|
||||
}
|
||||
|
||||
Int3 operator-(int32 b) const
|
||||
{
|
||||
return Subtract(*this, b);
|
||||
}
|
||||
|
||||
Int3 operator*(int32 b) const
|
||||
{
|
||||
return Multiply(*this, b);
|
||||
}
|
||||
|
||||
Int3 operator/(int32 b) const
|
||||
{
|
||||
return Divide(*this, b);
|
||||
}
|
||||
|
||||
// op= operators with int32
|
||||
|
||||
Int3& operator+=(int32 b)
|
||||
{
|
||||
*this = Add(*this, b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Int3& operator-=(int32 b)
|
||||
{
|
||||
*this = Subtract(*this, b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Int3& operator*=(int32 b)
|
||||
{
|
||||
*this = Multiply(*this, b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Int3& operator/=(int32 b)
|
||||
{
|
||||
*this = Divide(*this, b);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Comparison operators
|
||||
|
||||
bool operator==(const Int3& b) const
|
||||
{
|
||||
return X == b.X && Y == b.Y;
|
||||
}
|
||||
|
||||
bool operator!=(const Int3& b) const
|
||||
{
|
||||
return X != b.X || Y != b.Y;
|
||||
}
|
||||
|
||||
bool operator>(const Int3& b) const
|
||||
{
|
||||
return X > b.X && Y > b.Y;
|
||||
}
|
||||
|
||||
bool operator>=(const Int3& b) const
|
||||
{
|
||||
return X >= b.X && Y >= b.Y;
|
||||
}
|
||||
|
||||
bool operator<(const Int3& b) const
|
||||
{
|
||||
return X < b.X && Y < b.Y;
|
||||
}
|
||||
|
||||
bool operator<=(const Int3& b) const
|
||||
{
|
||||
return X <= b.X && Y <= b.Y;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static void Add(const Int3& a, const Int3& b, Int3& result)
|
||||
{
|
||||
result.X = a.X + b.X;
|
||||
result.Y = a.Y + b.Y;
|
||||
result.Z = a.Z + b.Z;
|
||||
}
|
||||
|
||||
static Int3 Add(const Int3& a, const Int3& b)
|
||||
{
|
||||
Int3 result;
|
||||
Add(a, b, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void Subtract(const Int3& a, const Int3& b, Int3& result)
|
||||
{
|
||||
result.X = a.X - b.X;
|
||||
result.Y = a.Y - b.Y;
|
||||
result.Z = a.Z - b.Z;
|
||||
}
|
||||
|
||||
static Int3 Subtract(const Int3& a, const Int3& b)
|
||||
{
|
||||
Int3 result;
|
||||
Subtract(a, b, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static Int3 Multiply(const Int3& a, const Int3& b)
|
||||
{
|
||||
return Int3(a.X * b.X, a.Y * b.Y, a.Z * b.Z);
|
||||
}
|
||||
|
||||
static Int3 Multiply(const Int3& a, int32 b)
|
||||
{
|
||||
return Int3(a.X * b, a.Y * b, a.Z * b);
|
||||
}
|
||||
|
||||
static Int3 Divide(const Int3& a, const Int3& b)
|
||||
{
|
||||
return Int3(a.X / b.X, a.Y / b.Y, a.Z / b.Z);
|
||||
}
|
||||
|
||||
static Int3 Divide(const Int3& a, int32 b)
|
||||
{
|
||||
return Int3(a.X / b, a.Y / b, a.Z / b);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicting whether this vector is zero.
|
||||
/// </summary>
|
||||
/// <returns> True if the vector is zero, otherwise false.</returns>
|
||||
bool IsZero() const
|
||||
{
|
||||
return X == 0 && Y == 0 && Z == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicting whether any vector component is zero.
|
||||
/// </summary>
|
||||
/// <returns> True if a component is zero, otherwise false.</returns>
|
||||
bool IsAnyZero() const
|
||||
{
|
||||
return X == 0 || Y == 0 || Z == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicting whether this vector is one.
|
||||
/// </summary>
|
||||
/// <returns> True if the vector is one, otherwise false.</returns>
|
||||
bool IsOne() const
|
||||
{
|
||||
return X == 1 && Y == 1 && Z == 1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates a vector with values being opposite to values of that vector
|
||||
/// </summary>
|
||||
/// <returns>Negative vector</returns>
|
||||
Int3 GetNegative() const
|
||||
{
|
||||
return Int3(-X, -Y, -Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns average arithmetic of all the components
|
||||
/// </summary>
|
||||
/// <returns>Average arithmetic of all the components</returns>
|
||||
float AverageArithmetic() const
|
||||
{
|
||||
return (X + Y + Z) / 3.0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets sum of all vector components values
|
||||
/// </summary>
|
||||
/// <returns>Sum of X, Y, Z and W</returns>
|
||||
int32 SumValues() const
|
||||
{
|
||||
return X + Y + Z;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns minimum value of all the components
|
||||
/// </summary>
|
||||
/// <returns>Minimum value</returns>
|
||||
int32 MinValue() const
|
||||
{
|
||||
return Math::Min(X, Y, Z);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns maximum value of all the components
|
||||
/// </summary>
|
||||
/// <returns>Maximum value</returns>
|
||||
int32 MaxValue() const
|
||||
{
|
||||
return Math::Max(X, Y, Z);
|
||||
}
|
||||
|
||||
// Returns a vector containing the largest components of the specified vectors
|
||||
// @param a The first source vector
|
||||
// @param b The second source vector
|
||||
// @param result When the method completes, contains an new vector composed of the largest components of the source vectors
|
||||
static Int3 Max(const Int3& a, const Int3& b)
|
||||
{
|
||||
return Int3(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y, a.Z > b.Z ? a.Z : b.Z);
|
||||
@@ -94,7 +378,6 @@ public:
|
||||
// Returns a vector containing the smallest components of the specified vectors
|
||||
// @param a The first source vector
|
||||
// @param b The second source vector
|
||||
// @param result When the method completes, contains an new vector composed of the smallest components of the source vectors
|
||||
static Int3 Min(const Int3& a, const Int3& b)
|
||||
{
|
||||
return Int3(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y, a.Z < b.Z ? a.Z : b.Z);
|
||||
@@ -104,18 +387,18 @@ public:
|
||||
// @param a The first source vector
|
||||
// @param b The second source vector
|
||||
// @param result When the method completes, contains an new vector composed of the largest components of the source vectors
|
||||
static void Max(const Int3& a, const Int3& b, Int3* result)
|
||||
static void Max(const Int3& a, const Int3& b, Int3& result)
|
||||
{
|
||||
*result = Int3(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y, a.Z > b.Z ? a.Z : b.Z);
|
||||
result = Int3(a.X > b.X ? a.X : b.X, a.Y > b.Y ? a.Y : b.Y, a.Z > b.Z ? a.Z : b.Z);
|
||||
}
|
||||
|
||||
// Returns a vector containing the smallest components of the specified vectors
|
||||
// @param a The first source vector
|
||||
// @param b The second source vector
|
||||
// @param result When the method completes, contains an new vector composed of the smallest components of the source vectors
|
||||
static void Min(const Int3& a, const Int3& b, Int3* result)
|
||||
static void Min(const Int3& a, const Int3& b, Int3 result)
|
||||
{
|
||||
*result = Int3(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y, a.Z < b.Z ? a.Z : b.Z);
|
||||
result = Int3(a.X < b.X ? a.X : b.X, a.Y < b.Y ? a.Y : b.Y, a.Z < b.Z ? a.Z : b.Z);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,42 +1,51 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "VectorInt.h"
|
||||
#include "Int2.h"
|
||||
#include "Int3.h"
|
||||
#include "Int4.h"
|
||||
#include "Vector2.h"
|
||||
#include "Vector3.h"
|
||||
#include "Vector4.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
|
||||
const Int2 Int2::Zero(0);
|
||||
const Int2 Int2::One(1);
|
||||
|
||||
Int2::Int2(const Vector2& v)
|
||||
: X(static_cast<int32>(v.X))
|
||||
, Y(static_cast<int32>(v.Y))
|
||||
{
|
||||
}
|
||||
|
||||
String Int2::ToString() const
|
||||
{
|
||||
return String::Format(TEXT("{}"), *this);
|
||||
}
|
||||
|
||||
const Int3 Int3::Zero(0);
|
||||
const Int3 Int3::One(1);
|
||||
|
||||
Int3::Int3(const Vector3& v)
|
||||
: X(static_cast<int32>(v.X))
|
||||
, Y(static_cast<int32>(v.Y))
|
||||
, Z(static_cast<int32>(v.Z))
|
||||
{
|
||||
}
|
||||
|
||||
String Int3::ToString() const
|
||||
{
|
||||
return String::Format(TEXT("{}"), *this);
|
||||
}
|
||||
static_assert(sizeof(Int4) == 16, "Invalid Int4 type size.");
|
||||
|
||||
const Int4 Int4::Zero(0);
|
||||
const Int4 Int4::One(1);
|
||||
const Int4 Int4::Minimum(MIN_int32);
|
||||
const Int4 Int4::Maximum(MAX_int32);
|
||||
|
||||
Int4::Int4(const Int2& xy, int32 z, int32 w)
|
||||
: X(xy.X)
|
||||
, Y(xy.Y)
|
||||
, Z(z)
|
||||
, W(w)
|
||||
{
|
||||
}
|
||||
|
||||
Int4::Int4(const Int3& xyz, int32 w)
|
||||
: X(xyz.X)
|
||||
, Y(xyz.Y)
|
||||
, Z(xyz.Z)
|
||||
, W(w)
|
||||
{
|
||||
}
|
||||
|
||||
Int4::Int4(const Vector2& v, int32 z, int32 w)
|
||||
: X(static_cast<int32>(v.X))
|
||||
, Y(static_cast<int32>(v.Y))
|
||||
, Z(z)
|
||||
, W(w)
|
||||
{
|
||||
}
|
||||
|
||||
Int4::Int4(const Vector3& v, int32 w)
|
||||
: X(static_cast<int32>(v.X))
|
||||
, Y(static_cast<int32>(v.Y))
|
||||
, Z(static_cast<int32>(v.Z))
|
||||
, W(w)
|
||||
{
|
||||
}
|
||||
|
||||
Int4::Int4(const Vector4& v)
|
||||
: X(static_cast<int32>(v.X))
|
||||
@@ -12,9 +12,8 @@ namespace FlaxEngine
|
||||
/// Represents a four dimensional mathematical vector (signed integers).
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
[TypeConverter(typeof(TypeConverters.Int4Converter))]
|
||||
public struct Int4 : IEquatable<Int4>, IFormattable
|
||||
partial struct Int4 : IEquatable<Int4>, IFormattable
|
||||
{
|
||||
private static readonly string _formatString = "X:{0} Y:{1} Z:{2} W:{3}";
|
||||
|
||||
@@ -63,26 +62,6 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
public static readonly Int4 Maximum = new Int4(int.MaxValue);
|
||||
|
||||
/// <summary>
|
||||
/// The X component of the vector.
|
||||
/// </summary>
|
||||
public int X;
|
||||
|
||||
/// <summary>
|
||||
/// The Y component of the vector.
|
||||
/// </summary>
|
||||
public int Y;
|
||||
|
||||
/// <summary>
|
||||
/// The Z component of the vector.
|
||||
/// </summary>
|
||||
public int Z;
|
||||
|
||||
/// <summary>
|
||||
/// The W component of the vector.
|
||||
/// </summary>
|
||||
public int W;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Int4" /> struct.
|
||||
/// </summary>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user