Merge branch 'master' of https://github.com/FlaxEngine/FlaxEngine into dev
This commit is contained in:
@@ -241,7 +241,7 @@ namespace FlaxEditor.GUI.Docking
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void FocusOrShow()
|
public void FocusOrShow()
|
||||||
{
|
{
|
||||||
FocusOrShow((DockState)Editor.Instance.Options.Options.Interface.NewWindowMethod);
|
FocusOrShow((DockState)Editor.Instance.Options.Options.Interface.NewWindowLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using FlaxEditor.Content;
|
using FlaxEditor.Content;
|
||||||
|
using FlaxEditor.GUI.Docking;
|
||||||
using FlaxEditor.Windows;
|
using FlaxEditor.Windows;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using DockState = FlaxEditor.GUI.Docking.DockState;
|
|
||||||
|
|
||||||
namespace FlaxEditor.Modules
|
namespace FlaxEditor.Modules
|
||||||
{
|
{
|
||||||
@@ -42,7 +42,6 @@ namespace FlaxEditor.Modules
|
|||||||
var proxy = Editor.ContentDatabase.GetProxy(item);
|
var proxy = Editor.ContentDatabase.GetProxy(item);
|
||||||
if (proxy == null)
|
if (proxy == null)
|
||||||
{
|
{
|
||||||
// Error
|
|
||||||
Editor.Log("Missing content proxy object for " + item);
|
Editor.Log("Missing content proxy object for " + item);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -58,24 +57,31 @@ namespace FlaxEditor.Modules
|
|||||||
}
|
}
|
||||||
if (window != null && !disableAutoShow)
|
if (window != null && !disableAutoShow)
|
||||||
{
|
{
|
||||||
// Check if there is a floating window that has the same size
|
var newLocation = (DockState)Editor.Options.Options.Interface.NewWindowLocation;
|
||||||
Vector2 defaultSize = window.DefaultSize;
|
if (newLocation == DockState.Float)
|
||||||
for (var i = 0; i < Editor.UI.MasterPanel.FloatingPanels.Count; i++)
|
|
||||||
{
|
{
|
||||||
var win = Editor.UI.MasterPanel.FloatingPanels[i];
|
// Check if there is a floating window that has the same size
|
||||||
|
Vector2 defaultSize = window.DefaultSize;
|
||||||
// Check if size is similar
|
for (var i = 0; i < Editor.UI.MasterPanel.FloatingPanels.Count; i++)
|
||||||
if (Vector2.Abs(win.Size - defaultSize).LengthSquared < 100)
|
|
||||||
{
|
{
|
||||||
// Dock
|
var win = Editor.UI.MasterPanel.FloatingPanels[i];
|
||||||
window.Show(DockState.DockFill, win);
|
|
||||||
window.Focus();
|
|
||||||
return window;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show floating
|
// Check if size is similar
|
||||||
window.ShowFloating(defaultSize);
|
if (Vector2.Abs(win.Size - defaultSize).LengthSquared < 100)
|
||||||
|
{
|
||||||
|
// Dock
|
||||||
|
window.Show(DockState.DockFill, win);
|
||||||
|
window.Focus();
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.ShowFloating(defaultSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
window.Show(newLocation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return window;
|
return window;
|
||||||
@@ -122,7 +128,7 @@ namespace FlaxEditor.Modules
|
|||||||
if (item is NewItem ni)
|
if (item is NewItem ni)
|
||||||
{
|
{
|
||||||
if (!ni.Proxy.IsFileNameValid(shortName))
|
if (!ni.Proxy.IsFileNameValid(shortName))
|
||||||
{
|
{
|
||||||
hint = "Name does not follow " + ni.Proxy.Name + " name restrictions !";
|
hint = "Name does not follow " + ni.Proxy.Name + " name restrictions !";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -131,7 +137,7 @@ namespace FlaxEditor.Modules
|
|||||||
{
|
{
|
||||||
var proxy = Editor.ContentDatabase.GetProxy(item);
|
var proxy = Editor.ContentDatabase.GetProxy(item);
|
||||||
if (proxy != null && !proxy.IsFileNameValid(shortName))
|
if (proxy != null && !proxy.IsFileNameValid(shortName))
|
||||||
{
|
{
|
||||||
hint = "Name does not follow " + proxy.Name + " name restrictions !";
|
hint = "Name does not follow " + proxy.Name + " name restrictions !";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,8 +110,8 @@ namespace FlaxEditor.Options
|
|||||||
/// Gets or sets the method window opening.
|
/// Gets or sets the method window opening.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DefaultValue(DockStateProxy.Float)]
|
[DefaultValue(DockStateProxy.Float)]
|
||||||
[EditorDisplay("Interface", "Define The Opening Window Method"), EditorOrder(150), Tooltip("Define the opening method for new windows, open in a new tab by default.")]
|
[EditorDisplay("Interface", "New Window Location"), EditorOrder(150), Tooltip("Define the opening method for new windows, open in a new tab by default.")]
|
||||||
public DockStateProxy NewWindowMethod { get; set; } = DockStateProxy.Float;
|
public DockStateProxy NewWindowLocation { get; set; } = DockStateProxy.Float;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the timestamps prefix mode for debug log messages.
|
/// Gets or sets the timestamps prefix mode for debug log messages.
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ namespace FlaxEditor.Windows
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="parent">The parent control.</param>
|
/// <param name="parent">The parent control.</param>
|
||||||
/// <param name="location">The location (within a given control).</param>
|
/// <param name="location">The location (within a given control).</param>
|
||||||
private void ShowContextMenu(Control parent, ref Vector2 location)
|
private void ShowContextMenu(Control parent, Vector2 location)
|
||||||
{
|
{
|
||||||
var contextMenu = CreateContextMenu();
|
var contextMenu = CreateContextMenu();
|
||||||
|
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ namespace FlaxEditor.Windows
|
|||||||
if (!Editor.StateMachine.CurrentState.CanEditScene)
|
if (!Editor.StateMachine.CurrentState.CanEditScene)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ShowContextMenu(node, ref location);
|
ShowContextMenu(node, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -379,7 +379,7 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
// Show context menu
|
// Show context menu
|
||||||
Editor.SceneEditing.Deselect();
|
Editor.SceneEditing.Deselect();
|
||||||
ShowContextMenu(this, ref location);
|
ShowContextMenu(Parent, location + _searchBox.BottomLeft);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -5,16 +5,6 @@
|
|||||||
#include "ModelBase.h"
|
#include "ModelBase.h"
|
||||||
#include "Engine/Graphics/Models/ModelLOD.h"
|
#include "Engine/Graphics/Models/ModelLOD.h"
|
||||||
|
|
||||||
// Note: we use the first chunk as a header, next is the highest quality lod and then lower ones
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// Chunk 0: Header
|
|
||||||
// Chunk 1: LOD0
|
|
||||||
// Chunk 2: LOD1
|
|
||||||
// ..
|
|
||||||
//
|
|
||||||
#define MODEL_LOD_TO_CHUNK_INDEX(lod) (lod + 1)
|
|
||||||
|
|
||||||
class Mesh;
|
class Mesh;
|
||||||
class StreamModelLODTask;
|
class StreamModelLODTask;
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,16 @@
|
|||||||
#include "Engine/Graphics/Models/MaterialSlot.h"
|
#include "Engine/Graphics/Models/MaterialSlot.h"
|
||||||
#include "Engine/Streaming/StreamableResource.h"
|
#include "Engine/Streaming/StreamableResource.h"
|
||||||
|
|
||||||
|
// Note: we use the first chunk as a header, next is the highest quality lod and then lower ones
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
// Chunk 0: Header
|
||||||
|
// Chunk 1: LOD0
|
||||||
|
// Chunk 2: LOD1
|
||||||
|
// ..
|
||||||
|
//
|
||||||
|
#define MODEL_LOD_TO_CHUNK_INDEX(lod) (lod + 1)
|
||||||
|
|
||||||
class MeshBase;
|
class MeshBase;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -58,7 +68,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets amount of the level of details in the model.
|
/// Gets amount of the level of details in the model.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Amount of the level of details in the model.</returns>
|
|
||||||
virtual int32 GetLODsCount() const = 0;
|
virtual int32 GetLODsCount() const = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -147,13 +147,13 @@ Array<String> SkinnedModel::GetBlendShapes()
|
|||||||
|
|
||||||
ContentLoadTask* SkinnedModel::RequestLODDataAsync(int32 lodIndex)
|
ContentLoadTask* SkinnedModel::RequestLODDataAsync(int32 lodIndex)
|
||||||
{
|
{
|
||||||
const int32 chunkIndex = SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
|
const int32 chunkIndex = MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
|
||||||
return RequestChunkDataAsync(chunkIndex);
|
return RequestChunkDataAsync(chunkIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkinnedModel::GetLODData(int32 lodIndex, BytesContainer& data) const
|
void SkinnedModel::GetLODData(int32 lodIndex, BytesContainer& data) const
|
||||||
{
|
{
|
||||||
const int32 chunkIndex = SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
|
const int32 chunkIndex = MODEL_LOD_TO_CHUNK_INDEX(lodIndex);
|
||||||
GetChunkData(chunkIndex, data);
|
GetChunkData(chunkIndex, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,7 +617,7 @@ bool SkinnedModel::Save(bool withMeshDataFromGpu, const StringView& path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Override meshes data chunk with the fetched GPU meshes memory
|
// Override meshes data chunk with the fetched GPU meshes memory
|
||||||
auto lodChunk = GET_CHUNK(SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lodIndex));
|
auto lodChunk = GET_CHUNK(MODEL_LOD_TO_CHUNK_INDEX(lodIndex));
|
||||||
if (lodChunk == nullptr)
|
if (lodChunk == nullptr)
|
||||||
return true;
|
return true;
|
||||||
lodChunk->Data.Copy(meshesStream.GetHandle(), meshesStream.GetPosition());
|
lodChunk->Data.Copy(meshesStream.GetHandle(), meshesStream.GetPosition());
|
||||||
@@ -631,7 +631,7 @@ bool SkinnedModel::Save(bool withMeshDataFromGpu, const StringView& path)
|
|||||||
// Load all chunks with a mesh data
|
// Load all chunks with a mesh data
|
||||||
for (int32 lodIndex = 0; lodIndex < LODs.Count(); lodIndex++)
|
for (int32 lodIndex = 0; lodIndex < LODs.Count(); lodIndex++)
|
||||||
{
|
{
|
||||||
if (LoadChunk(SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lodIndex)))
|
if (LoadChunk(MODEL_LOD_TO_CHUNK_INDEX(lodIndex)))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,16 +9,6 @@
|
|||||||
|
|
||||||
class StreamSkinnedModelLODTask;
|
class StreamSkinnedModelLODTask;
|
||||||
|
|
||||||
// Note: we use the first chunk as a header, next is the highest quality lod and then lower ones
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// Chunk 0: Header
|
|
||||||
// Chunk 1: LOD0
|
|
||||||
// Chunk 2: LOD1
|
|
||||||
// ..
|
|
||||||
//
|
|
||||||
#define SKINNED_MODEL_LOD_TO_CHUNK_INDEX(lod) (lod + 1)
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Skinned model asset that contains model object made of meshes that can be rendered on the GPU using skeleton bones skinning.
|
/// Skinned model asset that contains model object made of meshes that can be rendered on the GPU using skeleton bones skinning.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -12,9 +12,8 @@ StringView StringBuilder::ToStringView() const
|
|||||||
StringView StringView::Empty;
|
StringView StringView::Empty;
|
||||||
|
|
||||||
StringView::StringView(const String& str)
|
StringView::StringView(const String& str)
|
||||||
|
: StringViewBase<Char>(str.Get(), str.Length())
|
||||||
{
|
{
|
||||||
_data = str.Get();
|
|
||||||
_length = str.Length();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StringView::operator==(const String& other) const
|
bool StringView::operator==(const String& other) const
|
||||||
@@ -74,9 +73,8 @@ bool operator!=(const String& a, const StringView& b)
|
|||||||
StringAnsiView StringAnsiView::Empty;
|
StringAnsiView StringAnsiView::Empty;
|
||||||
|
|
||||||
StringAnsiView::StringAnsiView(const StringAnsi& str)
|
StringAnsiView::StringAnsiView(const StringAnsi& str)
|
||||||
|
: StringViewBase<char>(str.Get(), str.Length())
|
||||||
{
|
{
|
||||||
_data = str.Get();
|
|
||||||
_length = str.Length();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StringAnsiView::operator==(const StringAnsi& other) const
|
bool StringAnsiView::operator==(const StringAnsi& other) const
|
||||||
|
|||||||
@@ -18,9 +18,15 @@ protected:
|
|||||||
int32 _length;
|
int32 _length;
|
||||||
|
|
||||||
constexpr StringViewBase()
|
constexpr StringViewBase()
|
||||||
|
: _data(nullptr)
|
||||||
|
, _length(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr StringViewBase(const T* data, int32 length)
|
||||||
|
: _data(data)
|
||||||
|
, _length(length)
|
||||||
{
|
{
|
||||||
_data = nullptr;
|
|
||||||
_length = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -35,6 +41,16 @@ public:
|
|||||||
ASSERT(index >= 0 && index <= _length);
|
ASSERT(index >= 0 && index <= _length);
|
||||||
return _data[index];
|
return _data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCE_INLINE StringViewBase& operator=(const StringViewBase& other)
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
_data = other._data;
|
||||||
|
_length = other._length;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lexicographically tests how this string compares to the other given string.
|
/// Lexicographically tests how this string compares to the other given string.
|
||||||
@@ -194,6 +210,7 @@ public:
|
|||||||
/// Initializes a new instance of the <see cref="StringView"/> class.
|
/// Initializes a new instance of the <see cref="StringView"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
constexpr StringView()
|
constexpr StringView()
|
||||||
|
: StringViewBase<Char>()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,9 +225,8 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="str">The reference to the static string.</param>
|
/// <param name="str">The reference to the static string.</param>
|
||||||
constexpr StringView(const StringView& str)
|
constexpr StringView(const StringView& str)
|
||||||
|
: StringViewBase<Char>(str._data, str._length)
|
||||||
{
|
{
|
||||||
_data = str._data;
|
|
||||||
_length = str._length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -229,9 +245,8 @@ public:
|
|||||||
/// <param name="str">The characters sequence.</param>
|
/// <param name="str">The characters sequence.</param>
|
||||||
/// <param name="length">The characters sequence length (excluding null-terminator character).</param>
|
/// <param name="length">The characters sequence length (excluding null-terminator character).</param>
|
||||||
constexpr StringView(const Char* str, int32 length)
|
constexpr StringView(const Char* str, int32 length)
|
||||||
|
: StringViewBase<Char>(str, length)
|
||||||
{
|
{
|
||||||
_data = str;
|
|
||||||
_length = length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -248,21 +263,6 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Assigns the static string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="other">The other object.</param>
|
|
||||||
/// <returns>The reference to this object.</returns>
|
|
||||||
FORCE_INLINE constexpr StringView& operator=(const StringView& other)
|
|
||||||
{
|
|
||||||
if (this != &other)
|
|
||||||
{
|
|
||||||
_data = other._data;
|
|
||||||
_length = other._length;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lexicographically test whether this string is equivalent to the other given string (case sensitive).
|
/// Lexicographically test whether this string is equivalent to the other given string (case sensitive).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -399,6 +399,7 @@ public:
|
|||||||
/// Initializes a new instance of the <see cref="StringView"/> class.
|
/// Initializes a new instance of the <see cref="StringView"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
constexpr StringAnsiView()
|
constexpr StringAnsiView()
|
||||||
|
: StringViewBase<char>()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,9 +414,8 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="str">The reference to the static string.</param>
|
/// <param name="str">The reference to the static string.</param>
|
||||||
constexpr StringAnsiView(const StringAnsiView& str)
|
constexpr StringAnsiView(const StringAnsiView& str)
|
||||||
|
: StringViewBase<char>(str._data, str._length)
|
||||||
{
|
{
|
||||||
_data = str._data;
|
|
||||||
_length = str._length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -434,9 +434,8 @@ public:
|
|||||||
/// <param name="str">The characters sequence.</param>
|
/// <param name="str">The characters sequence.</param>
|
||||||
/// <param name="length">The characters sequence length (excluding null-terminator character).</param>
|
/// <param name="length">The characters sequence length (excluding null-terminator character).</param>
|
||||||
constexpr StringAnsiView(const char* str, int32 length)
|
constexpr StringAnsiView(const char* str, int32 length)
|
||||||
|
: StringViewBase<char>(str, length)
|
||||||
{
|
{
|
||||||
_data = str;
|
|
||||||
_length = length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -453,21 +452,6 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Assigns the static string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="other">The other object.</param>
|
|
||||||
/// <returns>The reference to this object.</returns>
|
|
||||||
FORCE_INLINE constexpr StringAnsiView& operator=(const StringAnsiView& other)
|
|
||||||
{
|
|
||||||
if (this != &other)
|
|
||||||
{
|
|
||||||
_data = other._data;
|
|
||||||
_length = other._length;
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lexicographically test whether this string is equivalent to the other given string (case sensitive).
|
/// Lexicographically test whether this string is equivalent to the other given string (case sensitive).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -78,11 +78,11 @@ void BlendShapesInstance::Update(SkinnedModel* skinnedModel)
|
|||||||
if (!instance.IsUsed)
|
if (!instance.IsUsed)
|
||||||
continue;
|
continue;
|
||||||
const SkinnedMesh* mesh = e.Key;
|
const SkinnedMesh* mesh = e.Key;
|
||||||
const int32 vertexCount = mesh->GetVertexCount();
|
|
||||||
|
|
||||||
// Get skinned mesh vertex buffer data (original, cached on CPU)
|
// Get skinned mesh vertex buffer data (original, cached on CPU)
|
||||||
BytesContainer vertexBuffer;
|
BytesContainer vertexBuffer;
|
||||||
if (mesh->DownloadDataCPU(MeshBufferType::Vertex0, vertexBuffer))
|
int32 vertexCount;
|
||||||
|
if (mesh->DownloadDataCPU(MeshBufferType::Vertex0, vertexBuffer, vertexCount))
|
||||||
{
|
{
|
||||||
// Don't use this mesh if failed to get it's vertices data
|
// Don't use this mesh if failed to get it's vertices data
|
||||||
instance.IsUsed = false;
|
instance.IsUsed = false;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "Engine/Graphics/GPUContext.h"
|
#include "Engine/Graphics/GPUContext.h"
|
||||||
#include "Engine/Graphics/GPUDevice.h"
|
#include "Engine/Graphics/GPUDevice.h"
|
||||||
#include "Engine/Graphics/RenderTask.h"
|
#include "Engine/Graphics/RenderTask.h"
|
||||||
#include "Engine/Level/Scene/Scene.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
#include "Engine/Renderer/RenderList.h"
|
#include "Engine/Renderer/RenderList.h"
|
||||||
#include "Engine/Serialization/MemoryReadStream.h"
|
#include "Engine/Serialization/MemoryReadStream.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
@@ -293,6 +293,9 @@ bool Mesh::Load(uint32 vertices, uint32 triangles, void* vb0, void* vb1, void* v
|
|||||||
_triangles = triangles;
|
_triangles = triangles;
|
||||||
_vertices = vertices;
|
_vertices = vertices;
|
||||||
_use16BitIndexBuffer = use16BitIndexBuffer;
|
_use16BitIndexBuffer = use16BitIndexBuffer;
|
||||||
|
_cachedVertexBuffer[0].Clear();
|
||||||
|
_cachedVertexBuffer[1].Clear();
|
||||||
|
_cachedVertexBuffer[2].Clear();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -314,6 +317,10 @@ void Mesh::Unload()
|
|||||||
_triangles = 0;
|
_triangles = 0;
|
||||||
_vertices = 0;
|
_vertices = 0;
|
||||||
_use16BitIndexBuffer = false;
|
_use16BitIndexBuffer = false;
|
||||||
|
_cachedIndexBuffer.Resize(0);
|
||||||
|
_cachedVertexBuffer[0].Clear();
|
||||||
|
_cachedVertexBuffer[1].Clear();
|
||||||
|
_cachedVertexBuffer[2].Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mesh::Intersects(const Ray& ray, const Matrix& world, float& distance, Vector3& normal) const
|
bool Mesh::Intersects(const Ray& ray, const Matrix& world, float& distance, Vector3& normal) const
|
||||||
@@ -506,13 +513,94 @@ Task* Mesh::DownloadDataGPUAsync(MeshBufferType type, BytesContainer& result) co
|
|||||||
return buffer ? buffer->DownloadDataAsync(result) : nullptr;
|
return buffer ? buffer->DownloadDataAsync(result) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result) const
|
bool Mesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const
|
||||||
{
|
{
|
||||||
#if !BUILD_RELEASE
|
if (_cachedVertexBuffer[0].IsEmpty())
|
||||||
// TODO: implement this
|
{
|
||||||
LOG(Error, "Mesh::DownloadDataCPU not implemented.");
|
PROFILE_CPU();
|
||||||
#endif
|
auto model = GetModel();
|
||||||
return true;
|
ScopeLock lock(model->Locker);
|
||||||
|
if (model->IsVirtual())
|
||||||
|
{
|
||||||
|
LOG(Error, "Cannot access CPU data of virtual models. Use GPU data download");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch chunk with data from drive/memory
|
||||||
|
const auto chunkIndex = MODEL_LOD_TO_CHUNK_INDEX(GetLODIndex());
|
||||||
|
if (model->LoadChunk(chunkIndex))
|
||||||
|
return true;
|
||||||
|
const auto chunk = model->GetChunk(chunkIndex);
|
||||||
|
if (!chunk)
|
||||||
|
{
|
||||||
|
LOG(Error, "Missing chunk.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryReadStream stream(chunk->Get(), chunk->Size());
|
||||||
|
|
||||||
|
// Seek to find mesh location
|
||||||
|
for (int32 i = 0; i <= _index; i++)
|
||||||
|
{
|
||||||
|
// #MODEL_DATA_FORMAT_USAGE
|
||||||
|
uint32 vertices;
|
||||||
|
stream.ReadUint32(&vertices);
|
||||||
|
uint32 triangles;
|
||||||
|
stream.ReadUint32(&triangles);
|
||||||
|
uint32 indicesCount = triangles * 3;
|
||||||
|
bool use16BitIndexBuffer = indicesCount <= MAX_uint16;
|
||||||
|
uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
|
||||||
|
if (vertices == 0 || triangles == 0)
|
||||||
|
{
|
||||||
|
LOG(Error, "Invalid mesh data.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
auto vb0 = stream.Read<VB0ElementType>(vertices);
|
||||||
|
auto vb1 = stream.Read<VB1ElementType>(vertices);
|
||||||
|
bool hasColors = stream.ReadBool();
|
||||||
|
VB2ElementType18* vb2 = nullptr;
|
||||||
|
if (hasColors)
|
||||||
|
{
|
||||||
|
vb2 = stream.Read<VB2ElementType18>(vertices);
|
||||||
|
}
|
||||||
|
auto ib = stream.Read<byte>(indicesCount * ibStride);
|
||||||
|
|
||||||
|
if (i != _index)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Cache mesh data
|
||||||
|
_cachedIndexBufferCount = indicesCount;
|
||||||
|
_cachedIndexBuffer.Set(ib, indicesCount * ibStride);
|
||||||
|
_cachedVertexBuffer[0].Set((const byte*)vb0, vertices * sizeof(VB0ElementType));
|
||||||
|
_cachedVertexBuffer[1].Set((const byte*)vb1, vertices * sizeof(VB1ElementType));
|
||||||
|
if (hasColors)
|
||||||
|
_cachedVertexBuffer[2].Set((const byte*)vb2, vertices * sizeof(VB2ElementType));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case MeshBufferType::Index:
|
||||||
|
result.Link(_cachedIndexBuffer);
|
||||||
|
count = _cachedIndexBufferCount;
|
||||||
|
break;
|
||||||
|
case MeshBufferType::Vertex0:
|
||||||
|
result.Link(_cachedVertexBuffer[0]);
|
||||||
|
count = _cachedVertexBuffer[0].Count() / sizeof(VB0ElementType);
|
||||||
|
break;
|
||||||
|
case MeshBufferType::Vertex1:
|
||||||
|
result.Link(_cachedVertexBuffer[1]);
|
||||||
|
count = _cachedVertexBuffer[1].Count() / sizeof(VB1ElementType);
|
||||||
|
break;
|
||||||
|
case MeshBufferType::Vertex2:
|
||||||
|
result.Link(_cachedVertexBuffer[2]);
|
||||||
|
count = _cachedVertexBuffer[2].Count() / sizeof(VB2ElementType);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptingObject* Mesh::GetParentModel()
|
ScriptingObject* Mesh::GetParentModel()
|
||||||
@@ -645,145 +733,50 @@ bool Mesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 typeI)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if load data from GPU
|
MeshBufferType bufferType;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case InternalBufferType::VB0:
|
||||||
|
bufferType = MeshBufferType::Vertex0;
|
||||||
|
break;
|
||||||
|
case InternalBufferType::VB1:
|
||||||
|
bufferType = MeshBufferType::Vertex1;
|
||||||
|
break;
|
||||||
|
case InternalBufferType::VB2:
|
||||||
|
bufferType = MeshBufferType::Vertex2;
|
||||||
|
break;
|
||||||
|
case InternalBufferType::IB16:
|
||||||
|
case InternalBufferType::IB32:
|
||||||
|
bufferType = MeshBufferType::Index;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
BytesContainer data;
|
||||||
if (forceGpu)
|
if (forceGpu)
|
||||||
{
|
{
|
||||||
MeshBufferType bufferType;
|
// Get data from GPU
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case InternalBufferType::VB0:
|
|
||||||
bufferType = MeshBufferType::Vertex0;
|
|
||||||
break;
|
|
||||||
case InternalBufferType::VB1:
|
|
||||||
bufferType = MeshBufferType::Vertex1;
|
|
||||||
break;
|
|
||||||
case InternalBufferType::VB2:
|
|
||||||
bufferType = MeshBufferType::Vertex2;
|
|
||||||
break;
|
|
||||||
case InternalBufferType::IB16:
|
|
||||||
case InternalBufferType::IB32:
|
|
||||||
bufferType = MeshBufferType::Index;
|
|
||||||
break;
|
|
||||||
default: CRASH;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: support reusing the input memory buffer to perform a single copy from staging buffer to the input CPU buffer
|
// TODO: support reusing the input memory buffer to perform a single copy from staging buffer to the input CPU buffer
|
||||||
BytesContainer data;
|
|
||||||
auto task = mesh->DownloadDataGPUAsync(bufferType, data);
|
auto task = mesh->DownloadDataGPUAsync(bufferType, data);
|
||||||
if (task == nullptr)
|
if (task == nullptr)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
model->Locker.Unlock();
|
|
||||||
|
|
||||||
task->Start();
|
task->Start();
|
||||||
|
model->Locker.Unlock();
|
||||||
if (task->Wait())
|
if (task->Wait())
|
||||||
{
|
{
|
||||||
LOG(Error, "Task failed.");
|
LOG(Error, "Task failed.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvertMeshData(mesh, type, resultObj, data.Get());
|
|
||||||
|
|
||||||
model->Locker.Lock();
|
model->Locker.Lock();
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// Get data from drive/memory
|
|
||||||
{
|
{
|
||||||
// Fetch chunk with data
|
// Get data from CPU
|
||||||
const auto chunkIndex = MODEL_LOD_TO_CHUNK_INDEX(mesh->GetLODIndex());
|
int32 count;
|
||||||
if (model->LoadChunk(chunkIndex))
|
if (DownloadDataCPU(bufferType, data, count))
|
||||||
return true;
|
return true;
|
||||||
const auto chunk = model->GetChunk(chunkIndex);
|
|
||||||
if (!chunk)
|
|
||||||
{
|
|
||||||
LOG(Error, "Missing chunk.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
MemoryReadStream stream(chunk->Get(), chunk->Size());
|
|
||||||
|
|
||||||
// Seek to find mesh location
|
|
||||||
for (int32 i = 0; i < mesh->GetIndex(); i++)
|
|
||||||
{
|
|
||||||
// #MODEL_DATA_FORMAT_USAGE
|
|
||||||
uint32 vertices;
|
|
||||||
stream.ReadUint32(&vertices);
|
|
||||||
uint32 triangles;
|
|
||||||
stream.ReadUint32(&triangles);
|
|
||||||
uint32 indicesCount = triangles * 3;
|
|
||||||
bool use16BitIndexBuffer = indicesCount <= MAX_uint16;
|
|
||||||
uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
|
|
||||||
if (vertices == 0 || triangles == 0)
|
|
||||||
{
|
|
||||||
LOG(Error, "Invalid mesh data.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
auto vb0 = stream.Read<VB0ElementType>(vertices);
|
|
||||||
auto vb1 = stream.Read<VB1ElementType>(vertices);
|
|
||||||
bool hasColors = stream.ReadBool();
|
|
||||||
VB2ElementType18* vb2 = nullptr;
|
|
||||||
if (hasColors)
|
|
||||||
{
|
|
||||||
vb2 = stream.Read<VB2ElementType18>(vertices);
|
|
||||||
}
|
|
||||||
auto ib = stream.Read<byte>(indicesCount * ibStride);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get mesh data
|
|
||||||
void* data = nullptr;
|
|
||||||
{
|
|
||||||
// #MODEL_DATA_FORMAT_USAGE
|
|
||||||
uint32 vertices;
|
|
||||||
stream.ReadUint32(&vertices);
|
|
||||||
uint32 triangles;
|
|
||||||
stream.ReadUint32(&triangles);
|
|
||||||
uint32 indicesCount = triangles * 3;
|
|
||||||
bool use16BitIndexBuffer = indicesCount <= MAX_uint16;
|
|
||||||
uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32);
|
|
||||||
if (vertices == 0 || triangles == 0)
|
|
||||||
{
|
|
||||||
LOG(Error, "Invalid mesh data.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
auto vb0 = stream.Read<VB0ElementType>(vertices);
|
|
||||||
auto vb1 = stream.Read<VB1ElementType>(vertices);
|
|
||||||
bool hasColors = stream.ReadBool();
|
|
||||||
VB2ElementType18* vb2 = nullptr;
|
|
||||||
if (hasColors)
|
|
||||||
{
|
|
||||||
vb2 = stream.Read<VB2ElementType18>(vertices);
|
|
||||||
}
|
|
||||||
auto ib = stream.Read<byte>(indicesCount * ibStride);
|
|
||||||
|
|
||||||
if (mesh->HasVertexColors() != hasColors || mesh->Use16BitIndexBuffer() != use16BitIndexBuffer)
|
|
||||||
{
|
|
||||||
LOG(Error, "Invalid mesh data loaded from chunk.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case InternalBufferType::VB0:
|
|
||||||
data = vb0;
|
|
||||||
break;
|
|
||||||
case InternalBufferType::VB1:
|
|
||||||
data = vb1;
|
|
||||||
break;
|
|
||||||
case InternalBufferType::VB2:
|
|
||||||
data = vb2;
|
|
||||||
break;
|
|
||||||
case InternalBufferType::IB16:
|
|
||||||
case InternalBufferType::IB32:
|
|
||||||
data = ib;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ConvertMeshData(mesh, type, resultObj, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConvertMeshData(mesh, type, resultObj, data.Get());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ API_CLASS(NoSpawn) class FLAXENGINE_API Mesh : public MeshBase
|
|||||||
{
|
{
|
||||||
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(Mesh, MeshBase);
|
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(Mesh, MeshBase);
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
int32 _index;
|
int32 _index;
|
||||||
int32 _lodIndex;
|
int32 _lodIndex;
|
||||||
bool _hasLightmapUVs;
|
bool _hasLightmapUVs;
|
||||||
@@ -30,8 +31,12 @@ protected:
|
|||||||
#if USE_PRECISE_MESH_INTERSECTS
|
#if USE_PRECISE_MESH_INTERSECTS
|
||||||
CollisionProxy _collisionProxy;
|
CollisionProxy _collisionProxy;
|
||||||
#endif
|
#endif
|
||||||
|
mutable Array<byte> _cachedVertexBuffer[3];
|
||||||
|
mutable Array<byte> _cachedIndexBuffer;
|
||||||
|
mutable int32 _cachedIndexBufferCount;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Mesh(const Mesh& other)
|
Mesh(const Mesh& other)
|
||||||
: Mesh()
|
: Mesh()
|
||||||
{
|
{
|
||||||
@@ -46,6 +51,7 @@ public:
|
|||||||
~Mesh();
|
~Mesh();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the model owning this mesh.
|
/// Gets the model owning this mesh.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -92,7 +98,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether this mesh is initialized (has vertex and index buffers initialized).
|
/// Determines whether this mesh is initialized (has vertex and index buffers initialized).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if this instance is initialized, otherwise false.</returns>
|
|
||||||
FORCE_INLINE bool IsInitialized() const
|
FORCE_INLINE bool IsInitialized() const
|
||||||
{
|
{
|
||||||
return _vertexBuffers[0] != nullptr;
|
return _vertexBuffers[0] != nullptr;
|
||||||
@@ -101,13 +106,11 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether this mesh has a vertex colors buffer.
|
/// Determines whether this mesh has a vertex colors buffer.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if this mesh has a vertex colors buffers.</returns>
|
|
||||||
API_PROPERTY() bool HasVertexColors() const;
|
API_PROPERTY() bool HasVertexColors() const;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether this mesh contains valid lightmap texture coordinates data.
|
/// Determines whether this mesh contains valid lightmap texture coordinates data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if this mesh has a vertex colors buffers.</returns>
|
|
||||||
API_PROPERTY() FORCE_INLINE bool HasLightmapUVs() const
|
API_PROPERTY() FORCE_INLINE bool HasLightmapUVs() const
|
||||||
{
|
{
|
||||||
return _hasLightmapUVs;
|
return _hasLightmapUVs;
|
||||||
@@ -118,7 +121,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the collision proxy used by the mesh.
|
/// Gets the collision proxy used by the mesh.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The collisions proxy container object reference.</returns>
|
|
||||||
FORCE_INLINE const CollisionProxy& GetCollisionProxy() const
|
FORCE_INLINE const CollisionProxy& GetCollisionProxy() const
|
||||||
{
|
{
|
||||||
return _collisionProxy;
|
return _collisionProxy;
|
||||||
@@ -127,6 +129,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
|
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -205,6 +208,7 @@ public:
|
|||||||
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint32* triangles, Vector3* normals = nullptr, Vector3* tangents = nullptr, Vector2* uvs = nullptr, Color32* colors = nullptr);
|
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint32* triangles, Vector3* normals = nullptr, Vector3* tangents = nullptr, Vector2* uvs = nullptr, Color32* colors = nullptr);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the model mesh index buffer (used by the virtual models created with Init rather than Load).
|
/// Updates the model mesh index buffer (used by the virtual models created with Init rather than Load).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -237,6 +241,7 @@ public:
|
|||||||
bool UpdateTriangles(uint32 triangleCount, void* ib, bool use16BitIndices);
|
bool UpdateTriangles(uint32 triangleCount, void* ib, bool use16BitIndices);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes instance of the <see cref="Mesh"/> class.
|
/// Initializes instance of the <see cref="Mesh"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -268,6 +273,7 @@ public:
|
|||||||
void Unload();
|
void Unload();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines if there is an intersection between the mesh and a ray in given world
|
/// Determines if there is an intersection between the mesh and a ray in given world
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -288,6 +294,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the draw call geometry for this mesh. Sets the index and vertex buffers.
|
/// Gets the draw call geometry for this mesh. Sets the index and vertex buffers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -387,12 +394,14 @@ public:
|
|||||||
void Draw(const RenderContext& renderContext, const DrawInfo& info, float lodDitherFactor) const;
|
void Draw(const RenderContext& renderContext, const DrawInfo& info, float lodDitherFactor) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// [MeshBase]
|
// [MeshBase]
|
||||||
bool DownloadDataGPU(MeshBufferType type, BytesContainer& result) const override;
|
bool DownloadDataGPU(MeshBufferType type, BytesContainer& result) const override;
|
||||||
Task* DownloadDataGPUAsync(MeshBufferType type, BytesContainer& result) const override;
|
Task* DownloadDataGPUAsync(MeshBufferType type, BytesContainer& result) const override;
|
||||||
bool DownloadDataCPU(MeshBufferType type, BytesContainer& result) const override;
|
bool DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Internal bindings
|
// Internal bindings
|
||||||
API_FUNCTION(NoProxy) ScriptingObject* GetParentModel();
|
API_FUNCTION(NoProxy) ScriptingObject* GetParentModel();
|
||||||
API_FUNCTION(NoProxy) bool UpdateMeshInt(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj);
|
API_FUNCTION(NoProxy) bool UpdateMeshInt(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj);
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the triangle count.
|
/// Gets the triangle count.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The triangles</returns>
|
|
||||||
API_PROPERTY() FORCE_INLINE int32 GetTriangleCount() const
|
API_PROPERTY() FORCE_INLINE int32 GetTriangleCount() const
|
||||||
{
|
{
|
||||||
return _triangles;
|
return _triangles;
|
||||||
@@ -54,7 +53,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the vertex count.
|
/// Gets the vertex count.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The vertices</returns>
|
|
||||||
API_PROPERTY() FORCE_INLINE int32 GetVertexCount() const
|
API_PROPERTY() FORCE_INLINE int32 GetVertexCount() const
|
||||||
{
|
{
|
||||||
return _vertices;
|
return _vertices;
|
||||||
@@ -63,7 +61,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the box.
|
/// Gets the box.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The bounding box.</returns>
|
|
||||||
API_PROPERTY() FORCE_INLINE const BoundingBox& GetBox() const
|
API_PROPERTY() FORCE_INLINE const BoundingBox& GetBox() const
|
||||||
{
|
{
|
||||||
return _box;
|
return _box;
|
||||||
@@ -72,7 +69,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the sphere.
|
/// Gets the sphere.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The bounding sphere.</returns>
|
|
||||||
API_PROPERTY() FORCE_INLINE const BoundingSphere& GetSphere() const
|
API_PROPERTY() FORCE_INLINE const BoundingSphere& GetSphere() const
|
||||||
{
|
{
|
||||||
return _sphere;
|
return _sphere;
|
||||||
@@ -129,6 +125,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Buffer type</param>
|
/// <param name="type">Buffer type</param>
|
||||||
/// <param name="result">The result data</param>
|
/// <param name="result">The result data</param>
|
||||||
|
/// <param name="count">The amount of items inside the result buffer.</param>
|
||||||
/// <returns>True if failed, otherwise false</returns>
|
/// <returns>True if failed, otherwise false</returns>
|
||||||
virtual bool DownloadDataCPU(MeshBufferType type, BytesContainer& result) const = 0;
|
virtual bool DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -227,16 +227,21 @@ Task* SkinnedMesh::DownloadDataGPUAsync(MeshBufferType type, BytesContainer& res
|
|||||||
return buffer ? buffer->DownloadDataAsync(result) : nullptr;
|
return buffer ? buffer->DownloadDataAsync(result) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkinnedMesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result) const
|
bool SkinnedMesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const
|
||||||
{
|
{
|
||||||
if (_cachedVertexBuffer.IsEmpty())
|
if (_cachedVertexBuffer.IsEmpty())
|
||||||
{
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
auto model = GetSkinnedModel();
|
auto model = GetSkinnedModel();
|
||||||
ScopeLock lock(model->Locker);
|
ScopeLock lock(model->Locker);
|
||||||
|
if (model->IsVirtual())
|
||||||
|
{
|
||||||
|
LOG(Error, "Cannot access CPU data of virtual models. Use GPU data download");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch chunk with data from drive/memory
|
// Fetch chunk with data from drive/memory
|
||||||
const auto chunkIndex = _lodIndex + 1;
|
const auto chunkIndex = MODEL_LOD_TO_CHUNK_INDEX(_lodIndex);
|
||||||
if (model->LoadChunk(chunkIndex))
|
if (model->LoadChunk(chunkIndex))
|
||||||
return true;
|
return true;
|
||||||
const auto chunk = model->GetChunk(chunkIndex);
|
const auto chunk = model->GetChunk(chunkIndex);
|
||||||
@@ -283,6 +288,7 @@ bool SkinnedMesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result) c
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Cache mesh data
|
// Cache mesh data
|
||||||
|
_cachedIndexBufferCount = indicesCount;
|
||||||
_cachedIndexBuffer.Set(ib, indicesCount * ibStride);
|
_cachedIndexBuffer.Set(ib, indicesCount * ibStride);
|
||||||
_cachedVertexBuffer.Set((const byte*)vb0, vertices * sizeof(VB0SkinnedElementType));
|
_cachedVertexBuffer.Set((const byte*)vb0, vertices * sizeof(VB0SkinnedElementType));
|
||||||
break;
|
break;
|
||||||
@@ -293,9 +299,11 @@ bool SkinnedMesh::DownloadDataCPU(MeshBufferType type, BytesContainer& result) c
|
|||||||
{
|
{
|
||||||
case MeshBufferType::Index:
|
case MeshBufferType::Index:
|
||||||
result.Link(_cachedIndexBuffer);
|
result.Link(_cachedIndexBuffer);
|
||||||
|
count = _cachedIndexBufferCount;
|
||||||
break;
|
break;
|
||||||
case MeshBufferType::Vertex0:
|
case MeshBufferType::Vertex0:
|
||||||
result.Link(_cachedVertexBuffer);
|
result.Link(_cachedVertexBuffer);
|
||||||
|
count = _cachedVertexBuffer.Count() / sizeof(VB0SkinnedElementType);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return true;
|
return true;
|
||||||
@@ -533,16 +541,19 @@ bool SkinnedMesh::DownloadBuffer(bool forceGpu, MonoArray* resultObj, int32 type
|
|||||||
if (task == nullptr)
|
if (task == nullptr)
|
||||||
return true;
|
return true;
|
||||||
task->Start();
|
task->Start();
|
||||||
|
model->Locker.Unlock();
|
||||||
if (task->Wait())
|
if (task->Wait())
|
||||||
{
|
{
|
||||||
LOG(Error, "Task failed.");
|
LOG(Error, "Task failed.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
model->Locker.Lock();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Get data from CPU
|
// Get data from CPU
|
||||||
if (DownloadDataCPU(bufferType, data))
|
int32 count;
|
||||||
|
if (DownloadDataCPU(bufferType, data, count))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ protected:
|
|||||||
GPUBuffer* _indexBuffer;
|
GPUBuffer* _indexBuffer;
|
||||||
mutable Array<byte> _cachedIndexBuffer;
|
mutable Array<byte> _cachedIndexBuffer;
|
||||||
mutable Array<byte> _cachedVertexBuffer;
|
mutable Array<byte> _cachedVertexBuffer;
|
||||||
|
mutable int32 _cachedIndexBufferCount;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -46,7 +47,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the skinned model owning this mesh.
|
/// Gets the skinned model owning this mesh.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The skinned model</returns>
|
|
||||||
FORCE_INLINE SkinnedModel* GetSkinnedModel() const
|
FORCE_INLINE SkinnedModel* GetSkinnedModel() const
|
||||||
{
|
{
|
||||||
return (SkinnedModel*)_model;
|
return (SkinnedModel*)_model;
|
||||||
@@ -55,7 +55,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the mesh index.
|
/// Gets the mesh index.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The index</returns>
|
|
||||||
FORCE_INLINE int32 GetIndex() const
|
FORCE_INLINE int32 GetIndex() const
|
||||||
{
|
{
|
||||||
return _index;
|
return _index;
|
||||||
@@ -64,7 +63,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether this mesh is initialized (has vertex and index buffers initialized).
|
/// Determines whether this mesh is initialized (has vertex and index buffers initialized).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if this instance is initialized, otherwise false.</returns>
|
|
||||||
FORCE_INLINE bool IsInitialized() const
|
FORCE_INLINE bool IsInitialized() const
|
||||||
{
|
{
|
||||||
return _vertexBuffer != nullptr;
|
return _vertexBuffer != nullptr;
|
||||||
@@ -241,7 +239,7 @@ public:
|
|||||||
// [MeshBase]
|
// [MeshBase]
|
||||||
bool DownloadDataGPU(MeshBufferType type, BytesContainer& result) const override;
|
bool DownloadDataGPU(MeshBufferType type, BytesContainer& result) const override;
|
||||||
Task* DownloadDataGPUAsync(MeshBufferType type, BytesContainer& result) const override;
|
Task* DownloadDataGPUAsync(MeshBufferType type, BytesContainer& result) const override;
|
||||||
bool DownloadDataCPU(MeshBufferType type, BytesContainer& result) const override;
|
bool DownloadDataCPU(MeshBufferType type, BytesContainer& result, int32& count) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
@@ -425,16 +425,19 @@ class UnloadSceneAction : public SceneAction
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Scene* TargetScene;
|
Guid TargetScene;
|
||||||
|
|
||||||
UnloadSceneAction(Scene* scene)
|
UnloadSceneAction(Scene* scene)
|
||||||
{
|
{
|
||||||
TargetScene = scene;
|
TargetScene = scene->GetID();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Do() const override
|
bool Do() const override
|
||||||
{
|
{
|
||||||
return unloadScene(TargetScene);
|
auto scene = Scripting::FindObject<Scene>(TargetScene);
|
||||||
|
if (!scene)
|
||||||
|
return true;
|
||||||
|
return unloadScene(scene);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1344,6 +1347,7 @@ bool Level::UnloadScene(Scene* scene)
|
|||||||
|
|
||||||
void Level::UnloadSceneAsync(Scene* scene)
|
void Level::UnloadSceneAsync(Scene* scene)
|
||||||
{
|
{
|
||||||
|
CHECK(scene);
|
||||||
ScopeLock lock(_sceneActionsLocker);
|
ScopeLock lock(_sceneActionsLocker);
|
||||||
_sceneActions.Enqueue(New<UnloadSceneAction>(scene));
|
_sceneActions.Enqueue(New<UnloadSceneAction>(scene));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,14 +168,6 @@ bool CollisionCooking::CookCollision(const Argument& arg, CollisionData::Seriali
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Model data gather requires to use async tasks (main thread cannot stall)
|
|
||||||
// TODO: if asset is not virtual then maybe use the asset container and read raw bytes from file??
|
|
||||||
if (IsInMainThread())
|
|
||||||
{
|
|
||||||
LOG(Warning, "Cannot generate collision data on a main thread.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure model is loaded
|
// Ensure model is loaded
|
||||||
if (arg.Model == nullptr)
|
if (arg.Model == nullptr)
|
||||||
{
|
{
|
||||||
@@ -193,51 +185,100 @@ bool CollisionCooking::CookCollision(const Argument& arg, CollisionData::Seriali
|
|||||||
Array<MeshBase*> meshes;
|
Array<MeshBase*> meshes;
|
||||||
arg.Model->GetMeshes(meshes, lodIndex);
|
arg.Model->GetMeshes(meshes, lodIndex);
|
||||||
|
|
||||||
// Download model LOD data from the GPU.
|
// Get mesh data
|
||||||
// It's easier than reading internal, versioned mesh storage format.
|
|
||||||
// Also it works with virtual assets that have no dedicated storage.
|
|
||||||
// Note: request all meshes data at once and wait for the tasks to be done.
|
|
||||||
const int32 meshesCount = meshes.Count();
|
const int32 meshesCount = meshes.Count();
|
||||||
Array<BytesContainer> vertexBuffers;
|
Array<BytesContainer> vertexBuffers;
|
||||||
Array<BytesContainer> indexBuffers;
|
Array<BytesContainer> indexBuffers;
|
||||||
|
Array<int32> vertexCounts;
|
||||||
|
Array<int32> indexCounts;
|
||||||
vertexBuffers.Resize(meshesCount);
|
vertexBuffers.Resize(meshesCount);
|
||||||
|
vertexCounts.Resize(meshesCount);
|
||||||
indexBuffers.Resize(needIndexBuffer ? meshesCount : 0);
|
indexBuffers.Resize(needIndexBuffer ? meshesCount : 0);
|
||||||
|
indexCounts.Resize(needIndexBuffer ? meshesCount : 0);
|
||||||
// Start tasks
|
bool useCpuData = IsInMainThread() && !arg.Model->IsVirtual();
|
||||||
int32 vCount = 0;
|
if (!useCpuData)
|
||||||
int32 iCount = 0;
|
|
||||||
Array<Task*> tasks(meshesCount + meshesCount);
|
|
||||||
for (int32 i = 0; i < meshesCount; i++)
|
|
||||||
{
|
{
|
||||||
const auto& mesh = *meshes[i];
|
// If mesh data is already cached in memory then we could use it instead of GPU
|
||||||
if ((arg.MaterialSlotsMask & (1 << mesh.GetMaterialSlotIndex())) == 0)
|
useCpuData |= arg.Model->HasChunkLoaded(MODEL_LOD_TO_CHUNK_INDEX(lodIndex));
|
||||||
continue;
|
}
|
||||||
|
if (useCpuData)
|
||||||
auto task = mesh.DownloadDataGPUAsync(MeshBufferType::Vertex0, vertexBuffers[i]);
|
{
|
||||||
if (task == nullptr)
|
// Read directly from the asset storage
|
||||||
return true;
|
for (int32 i = 0; i < meshesCount; i++)
|
||||||
task->Start();
|
|
||||||
tasks.Add(task);
|
|
||||||
vCount += mesh.GetVertexCount();
|
|
||||||
|
|
||||||
if (needIndexBuffer)
|
|
||||||
{
|
{
|
||||||
task = mesh.DownloadDataGPUAsync(MeshBufferType::Index, indexBuffers[i]);
|
const auto& mesh = *meshes[i];
|
||||||
if (task == nullptr)
|
if ((arg.MaterialSlotsMask & (1 << mesh.GetMaterialSlotIndex())) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int32 count;
|
||||||
|
if (mesh.DownloadDataCPU(MeshBufferType::Vertex0, vertexBuffers[i], count))
|
||||||
|
{
|
||||||
|
LOG(Error, "Failed to download mesh {0} data from model {1} LOD{2}", i, arg.Model.ToString(), lodIndex);
|
||||||
return true;
|
return true;
|
||||||
task->Start();
|
}
|
||||||
tasks.Add(task);
|
vertexCounts[i] = count;
|
||||||
iCount += mesh.GetTriangleCount() * 3;
|
|
||||||
|
if (needIndexBuffer)
|
||||||
|
{
|
||||||
|
if (mesh.DownloadDataCPU(MeshBufferType::Index, indexBuffers[i], count))
|
||||||
|
{
|
||||||
|
LOG(Error, "Failed to download mesh {0} data from model {1} LOD{2}", i, arg.Model.ToString(), lodIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
indexCounts[i] = count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Download model LOD data from the GPU.
|
||||||
|
// It's easier than reading internal, versioned mesh storage format.
|
||||||
|
// Also it works with virtual assets that have no dedicated storage.
|
||||||
|
// Note: request all meshes data at once and wait for the tasks to be done.
|
||||||
|
Array<Task*> tasks(meshesCount + meshesCount);
|
||||||
|
for (int32 i = 0; i < meshesCount; i++)
|
||||||
|
{
|
||||||
|
const auto& mesh = *meshes[i];
|
||||||
|
if ((arg.MaterialSlotsMask & (1 << mesh.GetMaterialSlotIndex())) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Wait for tasks
|
auto task = mesh.DownloadDataGPUAsync(MeshBufferType::Vertex0, vertexBuffers[i]);
|
||||||
if (Task::WaitAll(tasks))
|
if (task == nullptr)
|
||||||
return true;
|
{
|
||||||
tasks.Resize(0);
|
LOG(Error, "Failed to download mesh {0} data from model {1} LOD{2}", i, arg.Model.ToString(), lodIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int32 count = mesh.GetVertexCount();
|
||||||
|
task->Start();
|
||||||
|
tasks.Add(task);
|
||||||
|
vertexCounts[i] = count;
|
||||||
|
|
||||||
|
if (needIndexBuffer)
|
||||||
|
{
|
||||||
|
task = mesh.DownloadDataGPUAsync(MeshBufferType::Index, indexBuffers[i]);
|
||||||
|
if (task == nullptr)
|
||||||
|
{
|
||||||
|
LOG(Error, "Failed to download mesh {0} data from model {1} LOD{2}", i, arg.Model.ToString(), lodIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
count = mesh.GetTriangleCount() * 3;
|
||||||
|
task->Start();
|
||||||
|
tasks.Add(task);
|
||||||
|
indexCounts[i] = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Task::WaitAll(tasks))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Combine meshes into one
|
// Combine meshes into one
|
||||||
|
int32 vCount = 0;
|
||||||
|
for (int32 i = 0; i < vertexCounts.Count(); i++)
|
||||||
|
vCount += vertexCounts[0];
|
||||||
finalVertexData.Allocate(vCount);
|
finalVertexData.Allocate(vCount);
|
||||||
|
int32 iCount = 0;
|
||||||
|
for (int32 i = 0; i < indexCounts.Count(); i++)
|
||||||
|
iCount += indexCounts[0];
|
||||||
finalIndexData.Allocate(iCount);
|
finalIndexData.Allocate(iCount);
|
||||||
int32 vertexCounter = 0, indexCounter = 0;
|
int32 vertexCounter = 0, indexCounter = 0;
|
||||||
for (int32 i = 0; i < meshesCount; i++)
|
for (int32 i = 0; i < meshesCount; i++)
|
||||||
@@ -248,15 +289,15 @@ bool CollisionCooking::CookCollision(const Argument& arg, CollisionData::Seriali
|
|||||||
const auto& vData = vertexBuffers[i];
|
const auto& vData = vertexBuffers[i];
|
||||||
|
|
||||||
const int32 firstVertexIndex = vertexCounter;
|
const int32 firstVertexIndex = vertexCounter;
|
||||||
const int32 vertexCount = mesh.GetVertexCount();
|
const int32 vertexCount = vertexCounts[i];
|
||||||
Platform::MemoryCopy(finalVertexData.Get() + firstVertexIndex, vData.Get(), vertexCount * sizeof(Vector3));
|
Platform::MemoryCopy(finalVertexData.Get() + firstVertexIndex, vData.Get(), vertexCount * sizeof(Vector3));
|
||||||
vertexCounter += vertexCount;
|
vertexCounter += vertexCount;
|
||||||
|
|
||||||
if (needIndexBuffer)
|
if (needIndexBuffer)
|
||||||
{
|
{
|
||||||
const auto& iData = indexBuffers[i];
|
const auto& iData = indexBuffers[i];
|
||||||
const int32 indexCount = mesh.GetTriangleCount() * 3;
|
const int32 indexCount = indexCounts[i];
|
||||||
if (mesh.Use16BitIndexBuffer())
|
if (iData.Length() / indexCount == sizeof(uint16))
|
||||||
{
|
{
|
||||||
auto dst = finalIndexData.Get() + indexCounter;
|
auto dst = finalIndexData.Get() + indexCounter;
|
||||||
auto src = iData.Get<uint16>();
|
auto src = iData.Get<uint16>();
|
||||||
|
|||||||
@@ -197,13 +197,13 @@ public:
|
|||||||
#if COMPILE_WITH_PHYSICS_COOKING
|
#if COMPILE_WITH_PHYSICS_COOKING
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cooks the mesh collision data and updates the virtual asset. action cannot be performed on a main thread.
|
/// Cooks the mesh collision data and updates the virtual asset.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Can be used only for virtual assets (see <see cref="Asset.IsVirtual"/> and <see cref="Content.CreateVirtualAsset{T}"/>).
|
/// Can be used only for virtual assets (see <see cref="Asset.IsVirtual"/> and <see cref="Content.CreateVirtualAsset{T}"/>).
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="type">The collision data type.</param>
|
/// <param name="type">The collision data type.</param>
|
||||||
/// <param name="model">The source model.</param>
|
/// <param name="model">The source model. If model is virtual then this method cannot be called from the main thread.</param>
|
||||||
/// <param name="modelLodIndex">The source model LOD index.</param>
|
/// <param name="modelLodIndex">The source model LOD index.</param>
|
||||||
/// <param name="materialSlotsMask">The source model material slots mask. One bit per-slot. Can be used to exclude particular material slots from collision cooking.</param>
|
/// <param name="materialSlotsMask">The source model material slots mask. One bit per-slot. Can be used to exclude particular material slots from collision cooking.</param>
|
||||||
/// <param name="convexFlags">The convex mesh generation flags.</param>
|
/// <param name="convexFlags">The convex mesh generation flags.</param>
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ void LightPass::RenderLight(RenderContext& renderContext, GPUTextureView* lightB
|
|||||||
|
|
||||||
// Bind output
|
// Bind output
|
||||||
GPUTexture* depthBuffer = renderContext.Buffers->DepthBuffer;
|
GPUTexture* depthBuffer = renderContext.Buffers->DepthBuffer;
|
||||||
const bool depthBufferReadOnly = depthBuffer->GetDescription().Flags & GPUTextureFlags::ReadOnlyDepthView;
|
const bool depthBufferReadOnly = (depthBuffer->GetDescription().Flags & GPUTextureFlags::ReadOnlyDepthView) != 0;
|
||||||
GPUTextureView* depthBufferRTV = depthBufferReadOnly ? depthBuffer->ViewReadOnlyDepth() : nullptr;
|
GPUTextureView* depthBufferRTV = depthBufferReadOnly ? depthBuffer->ViewReadOnlyDepth() : nullptr;
|
||||||
GPUTextureView* depthBufferSRV = depthBufferReadOnly ? depthBuffer->ViewReadOnlyDepth() : depthBuffer->View();
|
GPUTextureView* depthBufferSRV = depthBufferReadOnly ? depthBuffer->ViewReadOnlyDepth() : depthBuffer->View();
|
||||||
context->SetRenderTarget(depthBufferRTV, lightBuffer);
|
context->SetRenderTarget(depthBufferRTV, lightBuffer);
|
||||||
|
|||||||
@@ -18,7 +18,11 @@
|
|||||||
#include "../rapidjson.h"
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
#include <intrin0.h> // for _umul128
|
#if _MSC_VER <= 1900
|
||||||
|
#include <intrin.h>
|
||||||
|
#else
|
||||||
|
#include <intrin0.h>
|
||||||
|
#endif
|
||||||
#pragma intrinsic(_umul128)
|
#pragma intrinsic(_umul128)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
4
Source/ThirdParty/rapidjson/internal/diyfp.h
vendored
4
Source/ThirdParty/rapidjson/internal/diyfp.h
vendored
@@ -22,7 +22,11 @@
|
|||||||
#include "../rapidjson.h"
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined(_M_AMD64)
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
#if _MSC_VER <= 1900
|
||||||
|
#include <intrin.h>
|
||||||
|
#else
|
||||||
#include <intrin0.h>
|
#include <intrin0.h>
|
||||||
|
#endif
|
||||||
#pragma intrinsic(_BitScanReverse64)
|
#pragma intrinsic(_BitScanReverse64)
|
||||||
#pragma intrinsic(_umul128)
|
#pragma intrinsic(_umul128)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user