Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
add_subdirectory(XRenderD3D9)
add_subdirectory(XRenderNULL)
@@ -0,0 +1,22 @@
Advanced Micro Devices, Inc.
Software License Agreement Sample Source Code
IMPORTANT—READ CAREFULLY: Do not install, copy or use the enclosed software, documentation and/or materials until you have carefully read and agreed to the following terms and conditions. This is a legal agreement (“Agreement”) between you (either an individual or an entity) (“You”) and Advanced Micro Devices, Inc. (“AMD”).
If You do not agree to the terms of this Agreement, do not install, copy or use this software, documentation or materials or any portion thereof. By loading or using the software provided herewith, which may include binary code, source code, associated install scripts and online or electronic documentation, or materials or any portion thereof, that is made available by AMD to download from any media (collectively “Software”), You agree to all of the terms of this Agreement.
1. LICENSE:
a. Subject to the terms and conditions of this Agreement, AMD grants You the following non-exclusive, non-transferable, royalty-free, limited copyright license to (i) download, copy, use, modify, and create derivative works of the source code version of the Software and materials associated with this Agreement, including without limitation printed documentation, (collectively, “Materials”) for internal evaluation only with AMD processors or graphics products; and (ii) make and distribute copies of the Materials and derivative works thereof created by You in binary code form only for use only with Your products that support AMD processors and in computer systems including AMD processors or graphics products, provided that You agree to include all copyright legends and other legal notices that may appear in the Software. Additionally, You agree that any distribution of the Materials to a third party, must include a software license agreement with terms and conditions that are at least as restrictive and protective of AMDs intellectual property rights in the Materials as the terms and conditions set forth herein, including but not limited to the terms and conditions set forth in Sections 4 through 7 herein. Except for the limited license granted herein, You shall have no other rights in the Materials, whether express, implied, arising by estoppel or otherwise.
b. Except as expressly licensed herein, You do not have the right to (i) distribute, rent, lease, sell, sublicense, assign, or otherwise transfer the Materials, in whole or in part, to third parties for commercial or for non-commercial use; or (ii) modify, disassemble, reverse engineer, or decompile the Software, or otherwise reduce any part of the Software to any human readable form.
c. AMD is under no obligation to support or provide maintenance for the Materials or to provide any updates or enhancements to You.
2. FEEDBACK: You may provide AMD feedback, suggestions or opinions as to the Software, its features, and desired enhancements or changes. If You provide feedback, suggestions or opinions to AMD regarding any new features, use, functionality, or change to the Software or any materials related to the Software, You hereby agree to grant, and do grant, AMD all rights needed for AMD to incorporate and commercialize any new feature, use, functionality, or change at no charge or encumbrance to AMD. You agree that AMD may disclose such feedback, suggestions or opinions to any third party in any manner, and You agree that AMD has the ability to sublicense any of the foregoing rights in any feedback, suggestions or opinions or AMD products or services in any form to any third party without restriction.
3. OWNERSHIP AND COPYRIGHT OF MATERIALS: You agree that the Materials are owned by AMD and/or AMDs licensors (if any), and are protected by United States and foreign intellectual property laws (e.g. patent and copyright laws) and international treaty provisions. You will not remove the copyright notice from the Materials. You agree to prevent any unauthorized copying of the Materials. All title and copyrights in and to the Materials, all copies thereof (in whole or in part, and in any form), and all rights therein shall remain vested in AMD. Except as expressly provided herein, AMD does not grant any express or implied right to You under AMD patents, copyrights, trademarks, or trade secret information and such rights are reserved to AMD and/or its licensors.
4. WARRANTY DISCLAIMER: THE MATERIALS ARE PROVIDED “AS IS” WITHOUT ANY EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, TITLE, OR FITNESS FOR ANY PARTICULAR PURPOSE, OR THOSE ARISING FROM CUSTOM OF TRADE OR COURSE OF USAGE.
FOR CLARIFICATION, THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE MATERIALS REMAINS WITH YOU. AMD DOES NOT WARRANT, GUARANTEE, OR MAKE ANY REPRESENTATIONS AS TO THE CORRECTNESS, ACCURACY, COMPLETENESS, QUALITY, OR RELIABILITY OF THE MATERIALS. AMD DOES NOT WARRANT THAT OPERATION OF THE MATERIALS WILL BE UNINTERRUPTED OR ERROR-FREE. YOU ARE RESPONSIBLE FOR DETERMINING THE APPROPRIATENESS OF USING THE SOFTWARE AND ASSUME ALL RISKS ASSOCIATED WITH THE USE OF THE MATERIALS, INCLUDING BUT NOT LIMITED TO THE RISKS OF PROGRAM ERRORS, DAMAGE TO OR LOSS OF DATA, PROGRAMS OR EQUIPMENT, AND UNAVAILABILITY OR INTERRUPTION OF OPERATIONS. Some jurisdictions do not allow for the exclusion or limitation of implied warranties, so the above limitations or exclusions may not apply to You.
5. LIMITATION OF LIABILITY: IN NO EVENT SHALL AMD OR ITS DIRECTORS, OFFICERS, EMPLOYEES AND AGENTS, ITS SUPPLIERS OR ITS LICENSORS BE LIABLE TO YOUOR ANY THIRD PARTIES IN RECEIPT OF THE MATERIALS UNDER ANY THEORY OF LIABILITY, WHETHER EQUITABLE, LEGAL OR COMMON LAW ACTION ARISING HEREUNDER FOR CONTRACT, STRICT LIABILITY, INDEMNITY, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE FOR DAMAGES WHICH, IN THE AGGREGATE EXCEED TEN DOLLARS ($10.00). IN NO EVENT SHALL AMD BE LIABLE FOR ANY CONSEQUENTIAL, INCIDENTAL, PUNITIVE OR SPECIAL DAMAGES, INCLUDING, BUT NOT LIMITED TO LOSS OF PROFITS, BUSINESS INTERRUPTION, OR LOSS OF INFORMATION ARISING OUT OF THE USE OF OR INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. BY USING THE MATERIALS WITHOUT CHARGE, YOU ACCEPT THIS ALLOCATION OF RISK. Because some jurisdictions prohibit the exclusion or limitation of liability for consequential or incidental damages, the above limitation may not apply to You.
6. EXPORT RESTRICTIONS: You shall adhere to all applicable U.S., European, and other export laws, including but not limited to the U.S. Export Administration Regulations (“EAR”), (15 C.F.R. Sections 730 through 774), and E.U. Council Regulation (EC) No 1334/2000 of 22 June 2000. Further, pursuant to Section 740.6 of the EAR, You hereby certify that, except pursuant to a license granted by the United States Department of Commerce Bureau of Industry and Security or as otherwise permitted pursuant to a License Exception under the EAR, You will not (1) export, re-export or release to a national of a country in Country Groups D:1, E:1 or E:2 any restricted technology, software, or source code it receives from AMD, or (2) export to Country Groups D:1, E:1 or E:2 the direct product of such technology or software, if such foreign produced direct product is subject to national security controls as identified on the Commerce Control List (currently found in Supplement 1 to Part 774 of EAR). For the most current Country Group listings, or for additional information about the EAR or Your obligations under those regulations, please refer to the U.S. Bureau of Industry and Securitys website at http://www.bis.doc.gov/.
7. U.S. GOVERNMENT RESTRICTED RIGHTS: The Materials are provided with “RESTRICTED RIGHTS.” Use, duplication or disclosure by the Government is subject to restrictions as set forth in FAR52.227-14 and DFAR252.227-7013, et seq., or its successor. Use of the Materials by the Government constitutes acknowledgment of AMDs proprietary rights in them.
8. TERMINATION OF LICENSE: This Agreement will terminate immediately without notice from AMD or judicial resolution if You fail to comply with any provisions of this Agreement. Upon termination of this Agreement, You must delete or destroy all copies of the Materials.
9. SURVIVAL: Sections 1(b)-(c), 2, 3, 4, 5, 6, 7, 9, 10, 11, 12 and 13 shall survive any expiration or termination of this Agreement.
10. APPLICABLE LAWS: Any claim arising under or relating to this Agreement shall be governed by and construed in accordance with the substantive laws of the State of California, without regard to principles of conflict of laws. Each party hereto submits to the jurisdiction of the state and federal courts of Santa Clara County and the Northern District of California for the purposes of all legal proceedings arising out of or relating to this Agreement or the subject matter hereof. Each party waives any objection which it may have to contest such forum.
11. Severability: Should any term of this Agreement be declared void or unenforceable by any court of competent jurisdiction, such declaration shall have no effect on the remaining terms hereof.
12. No Waiver: The failure of either party to enforce any rights granted hereunder or to take action against the other party in the event of any breach hereunder shall not be deemed a waiver by that party as to subsequent enforcement of rights or subsequent actions in the event of future breaches.
13. ENTIRE AGREEMENT: This Agreement constitutes the entire agreement between the parties and supersedes any prior or contemporaneous oral or written agreements with respect to the subject matter of this Agreement.
@@ -0,0 +1,246 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Crytek Common render helper functions and structures declarations.
#include "RenderDll_precompiled.h"
// Resource manager internal variables.
ResourceClassMap CBaseResource::m_sResources;
CryCriticalSection CBaseResource::s_cResLock;
CBaseResource& CBaseResource::operator=([[maybe_unused]] const CBaseResource& Src)
{
return *this;
}
bool CBaseResource::IsValid()
{
AUTO_LOCK(s_cResLock); // Not thread safe without this
SResourceContainer* pContainer = GetResourcesForClass(m_ClassName);
if (!pContainer)
{
return false;
}
ResourceClassMapItor itRM = m_sResources.find(m_ClassName);
if (itRM == m_sResources.end())
{
return false;
}
if (itRM->second != pContainer)
{
return false;
}
ResourcesMapItor itRL = itRM->second->m_RMap.find(m_NameCRC);
if (itRL == itRM->second->m_RMap.end())
{
return false;
}
if (itRL->second != this)
{
return false;
}
return true;
}
SResourceContainer* CBaseResource::GetResourcesForClass(const CCryNameTSCRC& className)
{
ResourceClassMapItor itRM = m_sResources.find(className);
if (itRM == m_sResources.end())
{
return NULL;
}
return itRM->second;
}
CBaseResource* CBaseResource::GetResource(const CCryNameTSCRC& className, int nID, bool bAddRef)
{
FUNCTION_PROFILER_RENDER_FLAT
AUTO_LOCK(s_cResLock); // Not thread safe without this
SResourceContainer* pRL = GetResourcesForClass(className);
if (!pRL)
{
return NULL;
}
int nIndex = RListIndexFromId(nID);
//assert(pRL->m_RList.size() > nID);
if (nIndex >= (int)pRL->m_RList.size() || nIndex < 0)
{
return NULL;
}
CBaseResource* pBR = pRL->m_RList[nIndex];
if (pBR)
{
if (bAddRef)
{
pBR->AddRef();
}
return pBR;
}
return NULL;
}
CBaseResource* CBaseResource::GetResource(const CCryNameTSCRC& className, const CCryNameTSCRC& Name, bool bAddRef)
{
FUNCTION_PROFILER_RENDER_FLAT
AUTO_LOCK(s_cResLock); // Not thread safe without this
SResourceContainer* pRL = GetResourcesForClass(className);
if (!pRL)
{
return NULL;
}
CBaseResource* pBR = NULL;
ResourcesMapItor itRL = pRL->m_RMap.find(Name);
if (itRL != pRL->m_RMap.end())
{
pBR = itRL->second;
if (bAddRef)
{
pBR->AddRef();
}
return pBR;
}
return NULL;
}
bool CBaseResource::Register(const CCryNameTSCRC& className, const CCryNameTSCRC& Name)
{
AUTO_LOCK(s_cResLock); // Not thread safe without this
SResourceContainer* pRL = GetResourcesForClass(className);
if (!pRL)
{
pRL = new SResourceContainer;
m_sResources.insert(ResourceClassMapItor::value_type(className, pRL));
}
assert(pRL);
if (!pRL)
{
return false;
}
ResourcesMapItor itRL = pRL->m_RMap.find(Name);
if (itRL != pRL->m_RMap.end())
{
return false;
}
pRL->m_RMap.insert(ResourcesMapItor::value_type(Name, this));
int nIndex;
if (pRL->m_AvailableIDs.size())
{
ResourceIds::iterator it = pRL->m_AvailableIDs.end() - 1;
nIndex = RListIndexFromId(*it);
pRL->m_AvailableIDs.erase(it);
assert(nIndex < (int)pRL->m_RList.size());
pRL->m_RList[nIndex] = this;
}
else
{
nIndex = pRL->m_RList.size();
pRL->m_RList.push_back(this);
}
m_nID = IdFromRListIndex(nIndex);
m_NameCRC = Name;
m_ClassName = className;
m_nRefCount = 1;
return true;
}
bool CBaseResource::UnRegister()
{
AUTO_LOCK(s_cResLock); // Not thread safe without this
if (IsValid())
{
SResourceContainer* pContainer = GetResourcesForClass(m_ClassName);
assert(pContainer);
if (pContainer)
{
pContainer->m_RMap.erase(m_NameCRC);
pContainer->m_RList[RListIndexFromId(m_nID)] = NULL;
pContainer->m_AvailableIDs.push_back(m_nID);
}
return true;
}
return false;
}
int32 CBaseResource::Release()
{
IF (m_nRefCount > 0, 1)
{
int32 nRef = CryInterlockedDecrement(&m_nRefCount);
if (nRef < 0)
{
CryFatalError("CBaseResource::Release() called more than once!");
}
if (nRef <= 0)
{
UnRegister();
if (gRenDev && gRenDev->m_pRT)
{
gRenDev->m_pRT->RC_ReleaseBaseResource(this);
}
return 0;
}
return nRef;
}
return 0;
}
//=================================================================
SResourceContainer::~SResourceContainer()
{
for (ResourcesMapItor it = m_RMap.begin(); it != m_RMap.end(); )
{
CBaseResource* pRes = it->second;
if (pRes && CRenderer::CV_r_printmemoryleaks)
{
iLog->Log("Warning: ~SResourceContainer: Resource %d was not deleted (%d)", pRes->GetID(), pRes->GetRefCounter());
}
++it; // advance "it" here because the safe release below usually invalidates "it" (calls m_RMap.erase(it))
SAFE_RELEASE(pRes);
}
m_RMap.clear();
m_RList.clear();
m_AvailableIDs.clear();
}
void CBaseResource::ShutDown()
{
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_releaseallresourcesonexit)
{
ResourceClassMapItor it;
for (it = m_sResources.begin(); it != m_sResources.end(); it++)
{
SResourceContainer* pCN = it->second;
SAFE_DELETE(pCN);
}
m_sResources.clear();
}
}
@@ -0,0 +1,198 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include "Cry_Math.h"
#include "Defs.h"
#include "Cry_Color.h"
#include <Cry_Camera.h>
#include <MemoryAccess.h>
#include "STLGlobalAllocator.h"
#if defined(NULL_RENDERER)
#define VSCONST_INSTDATA 40
#define VSCONST_SKINMATRIX (40)
#define NUM_MAX_BONES_PER_GROUP (100)
#define NUM_MAX_BONES_PER_GROUP_WITH_MB (50)
#define VSCONST_NOISE_TABLE 64
#else
#define VSCONST_INSTDATA 0
#define VSCONST_SKINMATRIX 0
#define VSCONST_NOISE_TABLE 0
#define NUM_MAX_BONES_PER_GROUP (250)
#define NUM_MAX_BONES_PER_GROUP_WITH_MB (125)
#endif
//////////////////////////////////////////////////////////////////////
class CRenderer;
extern CRenderer* gRenDev;
class CBaseResource;
//====================================================================
#define CR_LITTLE_ENDIAN
struct SWaveForm;
extern bool gbRgb;
_inline DWORD COLCONV (DWORD clr)
{
return ((clr & 0xff00ff00) | ((clr & 0xff0000) >> 16) | ((clr & 0xff) << 16));
}
_inline void COLCONV (ColorF& col)
{
float v = col[0];
col[0] = col[2];
col[2] = v;
}
_inline void f2d(double* dst, float* src)
{
for (int i = 0; i < 16; i++)
{
dst[i] = src[i];
}
}
_inline void d2f(float* dst, double* src)
{
for (int i = 0; i < 16; i++)
{
dst[i] = (float)src[i];
}
}
//=================================================================
typedef std::map<CCryNameTSCRC, CBaseResource*> ResourcesMap;
typedef ResourcesMap::iterator ResourcesMapItor;
typedef std::vector<CBaseResource*, stl::STLGlobalAllocator<CBaseResource*> > ResourcesList;
typedef std::vector<int, stl::STLGlobalAllocator<int> > ResourceIds;
struct SResourceContainer
{
ResourcesList m_RList; // List of objects for access by Id's
ResourcesMap m_RMap; // Map of objects for fast searching
ResourceIds m_AvailableIDs; // Available object Id's for efficient ID's assigning after deleting
SResourceContainer()
{
m_RList.reserve(512);
}
~SResourceContainer();
void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
pSizer->AddObject(m_RList);
pSizer->AddObject(m_RMap);
pSizer->AddObject(m_AvailableIDs);
}
};
typedef AZStd::unordered_map<CCryNameTSCRC, SResourceContainer*, AZStd::hash<CCryNameTSCRC>, AZStd::equal_to<CCryNameTSCRC>, AZ::StdLegacyAllocator> ResourceClassMap;
typedef ResourceClassMap::iterator ResourceClassMapItor;
class CBaseResource
{
private:
// Per resource variables
volatile int32 m_nRefCount;
int m_nID;
CCryNameTSCRC m_ClassName;
CCryNameTSCRC m_NameCRC;
static ResourceClassMap m_sResources;
public:
static CryCriticalSection s_cResLock;
//! Dirty flags will indicate what kind of data was invalidated
enum EDirtyFlags
{
eDeviceResourceDirty = BIT(0),
eDeviceResourceViewDirty = BIT(1),
};
// CCryUnknown interface
inline void SetRefCounter(int nRefCounter) { m_nRefCount = nRefCounter; }
virtual int32 AddRef()
{
int32 nRef = CryInterlockedIncrement(&m_nRefCount);
return nRef;
}
virtual int32 Release();
virtual int GetRefCounter() const { return m_nRefCount; }
// Increment ref count, if not already scheduled for destruction.
int32 TryAddRef()
{
volatile int nOldRef, nNewRef;
do
{
nOldRef = m_nRefCount;
if (nOldRef == 0)
{
return 0;
}
nNewRef = nOldRef + 1;
}
while (CryInterlockedCompareExchange(alias_cast<volatile LONG*>(&m_nRefCount), nNewRef, nOldRef) != nOldRef);
return nNewRef;
}
// Constructors.
CBaseResource()
: m_nRefCount(1) {}
CBaseResource(const CBaseResource& Src);
CBaseResource& operator=(const CBaseResource& Src);
// Destructor.
virtual ~CBaseResource() {};
CCryNameTSCRC GetNameCRC() { return m_NameCRC; }
//inline const char *GetName() const { return m_Name.c_str(); }
//inline const char *GetClassName() const { return m_ClassName.c_str(); }
inline int GetID() const { return m_nID; }
inline void SetID(int nID) { m_nID = nID; }
virtual bool IsValid();
static ILINE int RListIndexFromId(int id) { return id - 1; }
static ILINE int IdFromRListIndex(int idx) { return idx + 1; }
static ResourceClassMap& GetMaps() { return m_sResources; }
static CBaseResource* GetResource(const CCryNameTSCRC& className, int nID, bool bAddRef);
static CBaseResource* GetResource(const CCryNameTSCRC& className, const CCryNameTSCRC& Name, bool bAddRef);
static SResourceContainer* GetResourcesForClass(const CCryNameTSCRC& className);
static void ShutDown();
bool Register(const CCryNameTSCRC& resName, const CCryNameTSCRC& Name);
bool UnRegister();
virtual void GetMemoryUsage(ICrySizer* pSizer) const = 0;
virtual void InvalidateDeviceResource([[maybe_unused]] uint32 dirtyFlags) {};
};
+506
View File
@@ -0,0 +1,506 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_CRYNAMER_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_CRYNAMER_H
#pragma once
#include "CryCrc32.h"
//#define CHECK_INVALID_ACCESS
//////////////////////////////////////////////////////////////////////////
class CNameTableR
{
public:
// Name entry header, immediately after this header in memory starts actual string data.
struct SNameEntryR
{
// Reference count of this string.
int nRefCount;
// Current length of string.
int nLength;
// Size of memory allocated at the end of this class.
int nAllocSize;
// Here in memory starts character buffer of size nAllocSize.
//char data[nAllocSize]
const char* GetStr() { return (char*)(this + 1); }
void AddRef() { CryInterlockedIncrement(&nRefCount); };
int Release() { return CryInterlockedDecrement(&nRefCount); };
int GetMemoryUsage() { return sizeof(SNameEntryR) + strlen(GetStr()); }
int GetLength(){return nLength; }
};
static threadID m_nRenderThread;
private:
typedef AZStd::unordered_map<const char*, SNameEntryR*, stl::hash_string_caseless<const char*>, stl::equality_string_caseless<const char*> > NameMap;
NameMap m_nameMap;
void CheckThread()
{
#ifdef CHECK_INVALID_ACCESS
DWORD d = ::GetCurrentThreadId();
if (m_nRenderThread != 0 && d != m_nRenderThread)
{
__debugbreak();
}
#endif
}
public:
CNameTableR() {}
~CNameTableR()
{
for (NameMap::iterator it = m_nameMap.begin(); it != m_nameMap.end(); ++it)
{
CryModuleFree(it->second);
}
}
// Only finds an existing name table entry, return 0 if not found.
SNameEntryR* FindEntry(const char* str)
{
CheckThread();
SNameEntryR* pEntry = stl::find_in_map(m_nameMap, str, 0);
return pEntry;
}
// Finds an existing name table entry, or creates a new one if not found.
SNameEntryR* GetEntry(const char* str)
{
CheckThread();
SNameEntryR* pEntry = stl::find_in_map(m_nameMap, str, 0);
if (!pEntry)
{
// Create a new entry.
unsigned int nLen = strlen(str);
unsigned int allocLen = sizeof(SNameEntryR) + (nLen + 1) * sizeof(char);
pEntry = (SNameEntryR*)CryModuleMalloc(allocLen);
assert(pEntry != NULL);
pEntry->nRefCount = 0;
pEntry->nLength = nLen;
pEntry->nAllocSize = allocLen;
// Copy string to the end of name entry.
char* pEntryStr = const_cast<char*>(pEntry->GetStr());
memcpy(pEntryStr, str, nLen + 1);
// put in map.
//m_nameMap.insert( NameMap::value_type(pEntry->GetStr(),pEntry) );
m_nameMap[pEntry->GetStr()] = pEntry;
}
return pEntry;
}
// Release existing name table entry.
void Release(SNameEntryR* pEntry)
{
CheckThread();
assert(pEntry);
m_nameMap.erase(pEntry->GetStr());
CryModuleFree(pEntry);
}
int GetMemoryUsage()
{
int nSize = 0;
NameMap::iterator it;
int n = 0;
for (it = m_nameMap.begin(); it != m_nameMap.end(); it++)
{
nSize += strlen(it->first);
nSize += it->second->GetMemoryUsage();
n++;
}
nSize += n * 8;
return nSize;
}
void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
pSizer->AddObject(m_nameMap);
}
int GetNumberOfEntries()
{
return m_nameMap.size();
}
// Log all names inside CryNameTS table.
void LogNames()
{
NameMap::iterator it;
for (it = m_nameMap.begin(); it != m_nameMap.end(); ++it)
{
SNameEntryR* pNameEntry = it->second;
CryLog("[%4d] %s", pNameEntry->nLength, pNameEntry->GetStr());
}
}
};
//////////////////////////////////////////////////////////////////////////
// Class CCryNameR
//////////////////////////////////////////////////////////////////////////
class CCryNameR
{
public:
CCryNameR();
CCryNameR(const CCryNameR& n);
// !!! do not allow implicit conversion as it can lead to subtle bugs when passing const char* values
// to stl algorithms (as operator < will create a CCryNameR and potentially insert into the name table
// while processing the algorithm)
explicit CCryNameR(const char* s);
~CCryNameR();
CCryNameR& operator=(const CCryNameR& n);
CCryNameR& operator=(const char* s);
bool operator==(const CCryNameR& n) const;
bool operator<(const CCryNameR& n) const;
operator size_t() const
{
return AZStd::hash_string(m_str, _length());
}
bool empty() const
{
return length() == 0;
}
void reset()
{
_release(m_str);
m_str = 0;
}
void addref()
{
_addref(m_str);
}
const char* c_str() const
{
return (m_str) ? m_str : "";
}
int length() const
{
return _length();
};
static bool find(const char* str)
{
if (ms_table)
{
return ms_table->FindEntry(str) != 0;
}
return false;
}
void GetMemoryUsage(ICrySizer* pSizer) const
{
//pSizer->AddObject(m_str);
pSizer->AddObject(ms_table);
}
static int GetMemoryUsage()
{
if (ms_table)
{
return ms_table->GetMemoryUsage();
}
return 0;
}
static int GetNumberOfEntries()
{
if (ms_table)
{
return ms_table->GetNumberOfEntries();
}
return 0;
}
static void CreateNameTable()
{
AZ_Assert(!ms_table, "CNameTableR was already created!\n");
ms_table = new CNameTableR();
}
static void ReleaseNameTable()
{
delete ms_table;
ms_table = nullptr;
}
private:
typedef CNameTableR::SNameEntryR SNameEntry;
static CNameTableR* ms_table;
SNameEntry* _entry(const char* pBuffer) const
{
assert(pBuffer);
return ((SNameEntry*)pBuffer) - 1;
}
void _release(const char* pBuffer)
{
if (pBuffer && _entry(pBuffer)->Release() <= 0)
{
if (ms_table)
{
ms_table->Release(_entry(pBuffer));
}
else
{
CryModuleFree(_entry(pBuffer));
}
}
}
int _length() const
{
return (m_str) ? _entry(m_str)->nLength : 0;
}
void _addref(const char* pBuffer)
{
if (pBuffer)
{
_entry(pBuffer)->AddRef();
}
}
const char* m_str;
};
inline CCryNameR::CCryNameR()
{
m_str = 0;
}
inline CCryNameR::CCryNameR(const CCryNameR& n)
{
_addref(n.m_str);
m_str = n.m_str;
}
inline CCryNameR::CCryNameR(const char* s)
{
if (!ms_table)
{
m_str = nullptr;
return;
}
const char* pBuf = 0;
if (s && *s)
{
pBuf = ms_table->GetEntry(s)->GetStr();
}
_addref(pBuf);
m_str = pBuf;
}
inline CCryNameR::~CCryNameR()
{
_release(m_str);
}
inline CCryNameR& CCryNameR::operator=(const CCryNameR& n)
{
_addref(n.m_str);
_release(m_str);
m_str = n.m_str;
return *this;
}
inline CCryNameR& CCryNameR::operator=(const char* s)
{
if (!ms_table)
{
return *this;
}
const char* pBuf = 0;
if (s && *s)
{
pBuf = ms_table->GetEntry(s)->GetStr();
}
_addref(pBuf);
_release(m_str);
m_str = pBuf;
return *this;
}
inline bool CCryNameR::operator==(const CCryNameR& n) const
{
return m_str == n.m_str;
}
inline bool CCryNameR::operator<(const CCryNameR& n) const
{
return m_str < n.m_str;
}
///////////////////////////////////////////////////////////////////////////////
// Class CCryNameTSCRC.
//////////////////////////////////////////////////////////////////////////
class CCryNameTSCRC
{
public:
CCryNameTSCRC();
CCryNameTSCRC(const CCryNameTSCRC& n);
CCryNameTSCRC(const char* s);
CCryNameTSCRC(const char* s, bool bOnlyFind);
CCryNameTSCRC(uint32 n) { m_nID = n; }
~CCryNameTSCRC();
CCryNameTSCRC& operator=(const CCryNameTSCRC& n);
CCryNameTSCRC& operator=(const char* s);
operator size_t() const
{
return m_nID;
}
bool operator==(const CCryNameTSCRC& n) const;
bool operator!=(const CCryNameTSCRC& n) const;
bool operator==(const char* s) const;
bool operator!=(const char* s) const;
bool operator<(const CCryNameTSCRC& n) const;
bool operator>(const CCryNameTSCRC& n) const;
bool empty() const { return m_nID == 0; }
void reset() { m_nID = 0; }
uint32 get() { return m_nID; }
void add(int nAdd) { m_nID += nAdd; }
AUTO_STRUCT_INFO
void GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const { /*nothing*/}
private:
uint32 m_nID;
};
//////////////////////////////////////////////////////////////////////////
// CCryNameTSCRC
//////////////////////////////////////////////////////////////////////////
inline CCryNameTSCRC::CCryNameTSCRC()
{
m_nID = 0;
}
//////////////////////////////////////////////////////////////////////////
inline CCryNameTSCRC::CCryNameTSCRC(const CCryNameTSCRC& n)
{
m_nID = n.m_nID;
}
//////////////////////////////////////////////////////////////////////////
inline CCryNameTSCRC::CCryNameTSCRC(const char* s)
{
m_nID = 0;
*this = s;
}
inline CCryNameTSCRC::~CCryNameTSCRC()
{
m_nID = 0;
}
//////////////////////////////////////////////////////////////////////////
inline CCryNameTSCRC& CCryNameTSCRC::operator=(const CCryNameTSCRC& n)
{
m_nID = n.m_nID;
return *this;
}
//////////////////////////////////////////////////////////////////////////
inline CCryNameTSCRC& CCryNameTSCRC::operator=(const char* s)
{
assert(s);
if (*s) // if not empty
{
m_nID = CCrc32::ComputeLowercase(s);
}
return *this;
}
//////////////////////////////////////////////////////////////////////////
inline bool CCryNameTSCRC::operator==(const CCryNameTSCRC& n) const
{
return m_nID == n.m_nID;
}
inline bool CCryNameTSCRC::operator!=(const CCryNameTSCRC& n) const
{
return !(*this == n);
}
inline bool CCryNameTSCRC::operator==(const char* str) const
{
assert(str);
if (*str) // if not empty
{
uint32 nID = CCrc32::ComputeLowercase(str);
return m_nID == nID;
}
return m_nID == 0;
}
inline bool CCryNameTSCRC::operator!=(const char* str) const
{
if (!m_nID)
{
return true;
}
if (*str) // if not empty
{
uint32 nID = CCrc32::ComputeLowercase(str);
return m_nID != nID;
}
return false;
}
inline bool CCryNameTSCRC::operator<(const CCryNameTSCRC& n) const
{
return m_nID < n.m_nID;
}
inline bool CCryNameTSCRC::operator>(const CCryNameTSCRC& n) const
{
return m_nID > n.m_nID;
}
inline bool operator==(const string& s, const CCryNameTSCRC& n)
{
return n == s;
}
inline bool operator!=(const string& s, const CCryNameTSCRC& n)
{
return n != s;
}
inline bool operator==(const char* s, const CCryNameTSCRC& n)
{
return n == s;
}
inline bool operator!=(const char* s, const CCryNameTSCRC& n)
{
return n != s;
}
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_CRYNAMER_H
@@ -0,0 +1,652 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "ShadowUtils.h"
#include "DeferredRenderUtils.h"
void CDeferredRenderUtils::CreateUnitFrustumMesh(int tessx, int tessy, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
//////////////////////////////////////////////////////////////////////////
// Geometry generating
//////////////////////////////////////////////////////////////////////////
int32 nBaseVertexIndex = 0;
indBuff.clear();
indBuff.reserve(indBuff.size() + (tessx * tessy - 1) * 6); //TOFIX: correct number of indices
vertBuff.clear();
vertBuff.reserve(nBaseVertexIndex + tessx * tessy);
float pViewport[4] = {0.0f, 0.0f, 1.0f, 1.0f};
float fViewportMinZ = 0.0f;
float fViewportMaxZ = 1.0f;
float szx = 1.0f;
float szy = 1.0f;
float hsizex = szx / 2;
float hsizey = szy / 2;
float deltax = szx / (tessx - 1.0f);
float deltay = szy / (tessy - 1.0f);
SVF_P3F_C4B_T2F vert;
Vec3 tri_vert;
Vec3 a;
Vec3 vPos;
//generate tessellation for far plane
a.z = 1.0f;
for (int i = 0; i < tessy; i++)
{
for (int j = 0; j < tessx; j++)
{
a.x = j * deltax;
a.y = i * deltay;
//pre-transform viewport transform vertices in static mesh
vPos.x = (a.x - pViewport[0]) * 2.0f / pViewport[2] - 1.0f;
vPos.y = 1.0f - ((a.y - pViewport[1]) * 2.0f / pViewport[3]); //flip coords for y axis
vPos.z = (a.z - fViewportMinZ) / (fViewportMaxZ - fViewportMinZ);
vert.xyz = vPos;
vert.st = Vec2(1.0f, 1.0f); //valid extraction
vertBuff.push_back(vert);
}
}
//push light origin
vert.xyz = Vec3(0, 0, 0);
vert.st = Vec2(0.0f, 0.0f); //do not extract
vertBuff.push_back(vert);
//init indices for triangles drawing
for (int i = 0; i < tessy - 1; i++)
{
for (int j = 0; j < tessx - 1; j++)
{
indBuff.push_back((uint16)(i * tessx + j + 1 + nBaseVertexIndex));
indBuff.push_back((uint16)(i * tessx + j + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + (j + 1) + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + j + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + (j + 1) + nBaseVertexIndex));
indBuff.push_back((uint16)(i * tessx + j + nBaseVertexIndex));
}
}
//Additional faces
for (int j = 0; j < tessx - 1; j++)
{
indBuff.push_back((uint16)((tessy - 1) * tessx + j + 1 + nBaseVertexIndex));
indBuff.push_back((uint16)((tessy - 1) * tessx + j + nBaseVertexIndex));
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex));//light origin - last vertex
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex)); //light origin - last vertex
indBuff.push_back((uint16)(j + nBaseVertexIndex));
indBuff.push_back((uint16)(j + 1 + nBaseVertexIndex));
}
for (int i = 0; i < tessy - 1; i++)
{
indBuff.push_back((uint16)((i + 1) * tessx + nBaseVertexIndex));
indBuff.push_back((uint16)(i * tessx + nBaseVertexIndex));
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex)); //light origin - last vertex
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex));//light origin - last vertex
indBuff.push_back((uint16)(i * tessx + (tessx - 1) + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + (tessx - 1) + nBaseVertexIndex));
}
}
//push rectangle mesh
void CDeferredRenderUtils::CreateUnitFrustumMeshTransformed(SRenderLight* pLight, ShadowMapFrustum* pFrustum, int nAxis, int tessx, int tessy, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
//assert(pFrustum!=NULL);
assert(pLight != NULL);
Vec3& vLightPos = pLight->m_Origin;
f32 fLightRadius = pLight->m_fRadius;
int32 pViewport[4] = {0, 0, 1, 1};
Matrix44A mProjection;
Matrix44A mView;
if (pFrustum == NULL)
{
//for light source
CShadowUtils::GetCubemapFrustumForLight(pLight, nAxis, g_fOmniLightFov /*pLight->m_fLightFrustumAngle*/ + 3.0f, &mProjection, &mView, false); // 3.0f - offset to make sure that frustums are intersected
}
else
{
if (!pFrustum->bOmniDirectionalShadow)
{
//temporarily disabled since mLightProjMatrix contains pre-multiplied matrix already
//pmProjection = &(pFrustum->mLightProjMatrix);
mProjection = gRenDev->m_IdentityMatrix;
mView = pFrustum->mLightViewMatrix;
}
else
{
//calc one of cubemap's frustums
Matrix33 mRot = (Matrix33(pLight->m_ObjMatrix));
//rotation for shadow frustums is disabled
CShadowUtils::GetCubemapFrustum(FTYP_OMNILIGHTVOLUME, pFrustum, nAxis, &mProjection, &mView /*, &mRot*/);
}
}
//////////////////////////////////////////////////////////////////////////
// Geometry generating
//////////////////////////////////////////////////////////////////////////
//add geometry to the existing one
int32 nBaseVertexIndex = vertBuff.size();
indBuff.clear();
indBuff.reserve(indBuff.size() + (tessx * tessy - 1) * 6); //TOFIX: correct number of indices
vertBuff.clear();
vertBuff.reserve(nBaseVertexIndex + tessx * tessy);
float szx = 1.0f;
float szy = 1.0f;
float hsizex = szx / 2;
float hsizey = szy / 2;
float deltax = szx / (tessx - 1);
float deltay = szy / (tessy - 1);
SVF_P3F_C4B_T2F vert;
Vec3 tri_vert;
Vec3 a;
//generate tessellation for far plane
a.z = 1.0f;
for (int i = 0; i < tessy; i++)
{
for (int j = 0; j < tessx; j++)
{
a.x = j * deltax;
a.y = i * deltay;
// A
mathVec3UnProject(&tri_vert, &a, pViewport, &mProjection, &mView, &gRenDev->m_IdentityMatrix, g_CpuFlags);
//calc vertex expansion in world space coords
Vec3 vLightDir = tri_vert - vLightPos;
vLightDir.Normalize();
vLightDir.SetLength(fLightRadius * 1.05f);
vert.xyz = vLightPos + vLightDir;
vert.st = Vec2(0.0f, 0.0f);
vertBuff.push_back(vert);
}
}
//push light origin
vert.xyz = vLightPos;
vert.st = Vec2(0.0f, 0.0f);
vertBuff.push_back(vert);
//init indices for triangles drawing
for (int i = 0; i < tessy - 1; i++)
{
for (int j = 0; j < tessx - 1; j++)
{
indBuff.push_back((uint16)(i * tessx + j + 1 + nBaseVertexIndex));
indBuff.push_back((uint16)(i * tessx + j + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + (j + 1) + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + j + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + (j + 1) + nBaseVertexIndex));
indBuff.push_back((uint16)(i * tessx + j + nBaseVertexIndex));
}
}
//Additional faces
for (int j = 0; j < tessx - 1; j++)
{
indBuff.push_back((uint16)((tessy - 1) * tessx + j + 1 + nBaseVertexIndex));
indBuff.push_back((uint16)((tessy - 1) * tessx + j + nBaseVertexIndex));
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex));//light origin - last vertex
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex)); //light origin - last vertex
indBuff.push_back((uint16)(j + nBaseVertexIndex));
indBuff.push_back((uint16)(j + 1 + nBaseVertexIndex));
}
for (int i = 0; i < tessy - 1; i++)
{
indBuff.push_back((uint16)((i + 1) * tessx + nBaseVertexIndex));
indBuff.push_back((uint16)(i * tessx + nBaseVertexIndex));
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex)); //light origin - last vertex
indBuff.push_back((uint16)(tessy * tessx + nBaseVertexIndex));//light origin - last vertex
indBuff.push_back((uint16)(i * tessx + (tessx - 1) + nBaseVertexIndex));
indBuff.push_back((uint16)((i + 1) * tessx + (tessx - 1) + nBaseVertexIndex));
}
}
//////////////////////////////////////////////////////////////////////////
// Approximate with 8 vertices
//////////////////////////////////////////////////////////////////////////
void CreateSimpleLightFrustumMeshTransformed(ShadowMapFrustum* pFrustum, int nFrustNum, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
//SVF_P3F_T2F_T3F
SVF_P3F_C4B_T2F vert;
Vec3 vNDC;
assert(pFrustum != NULL);
indBuff.clear();
indBuff.reserve(36);
vertBuff.clear();
vertBuff.reserve(8);
//first vertex for cone
//vert.xyz = Vec3(0.0f, 0.0f, 0.0f);
//vert.st = Vec2(0.0f, 0.0f);
//vertBuff.push_back(vert);
int32 pViewport[4] = {0, 0, 1, 1};
Matrix44A* pmProjection;
Matrix44A* pmView;
Matrix44A mProjectionCM;
Matrix44A mViewCM;
if (!pFrustum->bOmniDirectionalShadow)
{
//temporarily disabled since mLightProjMatrix contains pre-multiplied matrix already
//pmProjection = &(pFrustum->mLightProjMatrix);
pmProjection = &gRenDev->m_IdentityMatrix;
pmView = &(pFrustum->mLightViewMatrix);
}
else
{
//calc one of cubemap's frustums
CShadowUtils::GetCubemapFrustum(FTYP_OMNILIGHTVOLUME, pFrustum, nFrustNum, &mProjectionCM, &mViewCM);
pmProjection = &mProjectionCM;
pmView = &mViewCM;
}
//Create frustum
for (int i = 0; i < 8; i++)
{
//Generate screen space frustum (CCW faces)
vNDC = Vec3((i == 0 || i == 3 || i == 4 || i == 7) ? 0.0f : 1.0f,
(i == 0 || i == 1 || i == 4 || i == 5) ? 0.0f : 1.0f,
(i == 0 || i == 1 || i == 2 || i == 3) ? 0.0f : 1.0f
);
//TD: convert math functions to column ordered matrices
Vec3 pvObj(vert.xyz);
mathVec3UnProject(&pvObj, &vNDC, pViewport, pmProjection, pmView, &gRenDev->m_IdentityMatrix, g_CpuFlags);
vert.st = Vec2(0.0f, 0.0f);
vertBuff.push_back(vert);
}
//CCW faces
static uint16 nFaces[6][4] = {
{0, 1, 2, 3},
{4, 7, 6, 5},
{0, 3, 7, 4},
{1, 5, 6, 2},
{0, 4, 5, 1},
{3, 2, 6, 7}
};
//init indices for triangles drawing
for (int i = 0; i < 6; i++)
{
indBuff.push_back((uint16) nFaces[i][0]);
indBuff.push_back((uint16) nFaces[i][1]);
indBuff.push_back((uint16) nFaces[i][2]);
indBuff.push_back((uint16) nFaces[i][0]);
indBuff.push_back((uint16) nFaces[i][2]);
indBuff.push_back((uint16) nFaces[i][3]);
}
}
//////////////////////////////////////////////////////////////////////////
//Sphere light volumes
//////////////////////////////////////////////////////////////////////////
void CDeferredRenderUtils::SphereTessR(Vec3& v0, Vec3& v1, Vec3& v2, int depth, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
if (depth == 0)
{
SVF_P3F_C4B_T2F vert;
int nVertCount = vertBuff.size();
vert.st = Vec2(0.0f, 0.0f);
vert.xyz = v0;
vertBuff.push_back(vert);
indBuff.push_back(nVertCount++);
vert.xyz = v1;
vertBuff.push_back(vert);
indBuff.push_back(nVertCount++);
vert.xyz = v2;
vertBuff.push_back(vert);
indBuff.push_back(nVertCount++);
}
else
{
Vec3 v01, v12, v02;
v01 = (v0 + v1).GetNormalized();
v12 = (v1 + v2).GetNormalized();
v02 = (v0 + v2).GetNormalized();
SphereTessR(v0, v01, v02, depth - 1, indBuff, vertBuff);
SphereTessR(v01, v1, v12, depth - 1, indBuff, vertBuff);
SphereTessR(v12, v02, v01, depth - 1, indBuff, vertBuff);
SphereTessR(v12, v2, v02, depth - 1, indBuff, vertBuff);
}
}
void CDeferredRenderUtils::SphereTess(Vec3& v0, Vec3& v1, Vec3& v2, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
int depth;
Vec3 w0, w1, w2;
int i, j, k;
SVF_P3F_C4B_T2F vert;
vert.st = Vec2(0.0f, 0.0f);
int nVertCount = vertBuff.size();
depth = 2;
for (i = 0; i < depth; i++)
{
for (j = 0; i + j < depth; j++)
{
k = depth - i - j;
{
w0 = (i * v0 + j * v1 + k * v2) / depth;
w1 = ((i + 1) * v0 + j * v1 + (k - 1) * v2)
/ depth;
w2 = (i * v0 + (j + 1) * v1 + (k - 1) * v2)
/ depth;
}
w0.Normalize();
w1.Normalize();
w2.Normalize();
vert.xyz = w1;
vertBuff.push_back(vert);
indBuff.push_back(nVertCount++);
vert.xyz = w0;
vertBuff.push_back(vert);
indBuff.push_back(nVertCount++);
vert.xyz = w2;
vertBuff.push_back(vert);
indBuff.push_back(nVertCount++);
}
}
}
#define X .525731112119133606f
#define Z .850650808352039932f
void CDeferredRenderUtils::CreateUnitSphere(int rec, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
static Vec3 verts[12] =
{
Vec3(-X, 0, Z),
Vec3(X, 0, Z),
Vec3(-X, 0, -Z),
Vec3(X, 0, -Z),
Vec3(0, Z, X),
Vec3(0, Z, -X),
Vec3(0, -Z, X),
Vec3(0, -Z, -X),
Vec3(Z, X, 0),
Vec3(-Z, X, 0),
Vec3(Z, -X, 0),
Vec3(-Z, -X, 0)
};
static int indices[20][3] =
{
{0, 4, 1},
{0, 9, 4},
{9, 5, 4},
{4, 5, 8},
{4, 8, 1},
{8, 10, 1},
{8, 3, 10},
{5, 3, 8},
{5, 2, 3},
{2, 7, 3},
{7, 10, 3},
{7, 6, 10},
{7, 11, 6},
{11, 0, 6},
{0, 1, 6},
{6, 1, 10},
{9, 0, 11},
{9, 11, 2},
{9, 2, 5},
{7, 2, 11},
};
indBuff.clear();
vertBuff.clear();
SVF_P3F_C4B_T2F vert;
vert.st = Vec2(0.0f, 0.0f);
//debug
/*for(int i=0; i<12; i++)
{
vert.xyz = verts[i];
vertBuff.push_back(vert);
}
for (int i = 19; i >= 0; i--)
{
indBuff.push_back( (uint16)indices[i][2] );
indBuff.push_back( (uint16)indices[i][1] );
indBuff.push_back( (uint16)indices[i][0] );
}*/
for (int i = 19; i >= 0; i--)
{
Vec3& v0 = verts[indices[i][2]];
Vec3& v1 = verts[indices[i][1]];
Vec3& v2 = verts[indices[i][0]];
//SphereTess(v0, v1, v2, indBuff, vertBuff);
SphereTessR(v0, v1, v2, rec, indBuff, vertBuff);
}
}
#undef X
#undef Z
void CDeferredRenderUtils::CreateUnitBox(t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
SVF_P3F_C4B_T2F vert;
Vec3 vNDC;
indBuff.clear();
indBuff.reserve(36);
vertBuff.clear();
vertBuff.reserve(8);
//Create unit box
for (int i = 0; i < 8; i++)
{
//Generate screen space frustum (CCW faces)
vNDC = Vec3((i == 0 || i == 1 || i == 4 || i == 5) ? 0.0f : 1.0f,
(i == 0 || i == 3 || i == 4 || i == 7) ? 0.0f : 1.0f,
(i == 0 || i == 1 || i == 2 || i == 3) ? 0.0f : 1.0f
);
vert.xyz = vNDC;
vert.st = Vec2(0.0f, 0.0f);
vert.color.dcolor = -1;
vertBuff.push_back(vert);
}
//CCW faces
uint16 nFaces[6][4] = {
{0, 1, 2, 3},
{4, 7, 6, 5},
{0, 3, 7, 4},
{1, 5, 6, 2},
{0, 4, 5, 1},
{3, 2, 6, 7}
};
//init indices for triangles drawing
for (int i = 0; i < 6; i++)
{
indBuff.push_back((uint16) nFaces[i][0]);
indBuff.push_back((uint16) nFaces[i][1]);
indBuff.push_back((uint16) nFaces[i][2]);
indBuff.push_back((uint16) nFaces[i][0]);
indBuff.push_back((uint16) nFaces[i][2]);
indBuff.push_back((uint16) nFaces[i][3]);
}
}
//////////////////////////////////////////////////////////////////////////
// Approximate with 8 vertices
//////////////////////////////////////////////////////////////////////////
void CDeferredRenderUtils::CreateSimpleLightFrustumMesh(t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
//SVF_P3F_T2F_T3F
SVF_P3F_C4B_T2F vert;
Vec3 vNDC;
indBuff.clear();
indBuff.reserve(36);
vertBuff.clear();
vertBuff.reserve(8);
int32 pViewport[4] = {0, 0, 1, 1};
float fViewportMinZ = 0.0f, fViewportMaxZ = 1.0f;
Matrix44A mProjectionCM;
Matrix44A mViewCM;
Vec3 vPos;
//Create frustum
for (int i = 0; i < 8; i++)
{
//Generate screen space frustum (CCW faces)
//vNDC = Vec3((i==0 || i==3 || i==4 || i==7) ? 0.0f : 1.0f,
// (i==0 || i==1 || i==4 || i==5) ? 0.0f : 1.0f,
// (i==0 || i==1 || i==2 || i==3) ? 0.0f : 1.0f
// );
vNDC = Vec3((i == 0 || i == 1 || i == 4 || i == 5) ? 0.0f : 1.0f,
(i == 0 || i == 3 || i == 4 || i == 7) ? 0.0f : 1.0f,
(i == 0 || i == 1 || i == 2 || i == 3) ? 0.0f : 1.0f);
//pre-transform viewport transform vertices in static mesh
vPos.x = (vNDC.x - pViewport[0]) * 2.0f / pViewport[2] - 1.0f;
vPos.y = 1.0f - ((vNDC.y - pViewport[1]) * 2.0f / pViewport[3]); //flip coords for y axis
vPos.z = (vNDC.z - fViewportMinZ) / (fViewportMaxZ - fViewportMinZ);
vert.xyz = vPos;
vert.st = Vec2(1.0f, 1.0f); //valid extraction
vertBuff.push_back(vert);
}
//CCW faces
static uint16 nFaces[6][4] = {
{0, 1, 2, 3},
{4, 7, 6, 5},
{0, 3, 7, 4},
{1, 5, 6, 2},
{0, 4, 5, 1},
{3, 2, 6, 7}
};
//init indices for triangles drawing
for (int i = 0; i < 6; i++)
{
indBuff.push_back((uint16) nFaces[i][0]);
indBuff.push_back((uint16) nFaces[i][1]);
indBuff.push_back((uint16) nFaces[i][2]);
indBuff.push_back((uint16) nFaces[i][0]);
indBuff.push_back((uint16) nFaces[i][2]);
indBuff.push_back((uint16) nFaces[i][3]);
}
}
//////////////////////////////////////////////////////////////////////////
//FS quad
//////////////////////////////////////////////////////////////////////////
void CDeferredRenderUtils::CreateQuad(t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff)
{
SVF_P3F_C4B_T2F pScreenQuad[] =
{
{ Vec3(0, 0, 0), {
{0}
}, Vec2(0, 0) },
{ Vec3(0, 1, 0), {
{0}
}, Vec2(0, 1) },
{ Vec3(1, 0, 0), {
{0}
}, Vec2(1, 0) },
{ Vec3(1, 1, 0), {
{0}
}, Vec2(1, 1) },
};
vertBuff.clear();
vertBuff.reserve(4);
vertBuff.push_back(pScreenQuad[0]);
vertBuff.push_back(pScreenQuad[1]);
vertBuff.push_back(pScreenQuad[2]);
vertBuff.push_back(pScreenQuad[3]);
indBuff.clear();
}
@@ -0,0 +1,42 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef __DEFERRED_RENDER_UTILS_H__
#define __DEFERRED_RENDER_UTILS_H__
#define SDeferMeshVert SVF_P3F_C4B_T2F
typedef std::vector<SVF_P3F_C4B_T2F> t_arrDeferredMeshVertBuff;
typedef std::vector<uint16> t_arrDeferredMeshIndBuff;
class CDeferredRenderUtils
{
public:
static void CreateUnitFrustumMesh(int tessx, int tessy, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff);
static void CreateUnitFrustumMeshTransformed(SRenderLight* pLight, ShadowMapFrustum* pFrustum, int nAxis, int tessx, int tessy, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff);
static void CreateUnitSphere(int rec, /*SRenderLight* pLight, int depth, */ t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff);
static void CreateSimpleLightFrustumMesh(t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff);
static void CreateSimpleLightFrustumMeshTransformed(ShadowMapFrustum* pFrustum, int nFrustNum, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff);
static void CreateUnitBox(t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff);
static void CreateQuad(t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff);
CDeferredRenderUtils();
~CDeferredRenderUtils();
private:
static void SphereTess(Vec3& v0, Vec3& v1, Vec3& v2, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff);
static void SphereTessR(Vec3& v0, Vec3& v1, Vec3& v2, int depth, t_arrDeferredMeshIndBuff& indBuff, t_arrDeferredMeshVertBuff& vertBuff);
};
#endif
+165
View File
@@ -0,0 +1,165 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(Defs_h)
#endif
#if defined(DEFS_H_NO_SIGNAL_H)
#undef DEFS_H_NO_SIGNAL_H
#else
#include <signal.h>
#endif
#include <errno.h>
#include <string.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#ifndef ABS
#define ABS(x) ((x) < 0 ? -(x) : (x))
#endif
#if !defined(SIGN) && !defined(DO_AMIGAOS)
#define SIGN(x) ((x) < 0 ? -1 : ((x) > 0 ? 1 : 0))
#endif
#define EPSILON 0.001f /* Small value */
#define SMALL_EPSILON 0.000001f /* Very small value */
#ifndef _WIN32
//#define INFINITE 999999000 /* Very large number */
#endif
#ifndef PI
#define PI 3.14159265358979323f /* You know this number, don't you? */
#endif
#ifndef M_PI
#define M_PI PI
#endif
#ifndef M_PI_2
#define M_PI_2 (PI / 2)
#endif //M_PI_2
#if !defined(LINUX) && !defined(MAC)
#if defined(COMP_WCC)
#define strcasecmp _stricmp
#define strncasecmp strnicmp
#endif
#if defined(_MSC_VER)
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#endif
#endif // !defined(LINUX) && !defined(MAC)
#ifdef _CPU_X86
// This is 'stolen' from someone (I don't remember who anymore). It
// is a nice and fast way to convert a floating point number to int
// (only works on a i386 type processor).
// It is equivalent to 'i=(int)(f+.5)'.
#define FIST_MAGIC ((float)((((65536.0 * 65536.0 * 16) + (65536.0 * 0.5)) * 65536.0)))
_inline long QuickRound (float inval)
{
double dtemp = FIST_MAGIC + inval;
return ((*(long*)&dtemp) - 0x80000000);
}
_inline long QuickInt (float inval)
{
double dtemp = FIST_MAGIC + (inval - .4999f);
return ((*(long*)&dtemp) - 0x80000000);
}
// This is my own invention derived from the previous one. This converts
// a floating point number to a 16.16 fixed point integer. It is
// equivalent to 'i=(int)(f*65536.)'.
#define FIST_MAGIC2 ((float)((((65536.0 * 16) + (0.5)) * 65536.0)))
inline long QuickInt16 (float inval)
{
double dtemp = FIST_MAGIC2 + inval;
return ((*(long*)&dtemp) - 0x80000000);
}
#endif //_CPU_X86
#ifdef PROC_M68K
#define FIST_MAGIC ((((65536.0 * 65536.0 * 16) + (65536.0 * 0.5)) * 65536.0))
inline long QuickRound (float inval)
{
double dtemp = FIST_MAGIC + inval;
return (*(((long*)&dtemp) + 1)) - 0x80000000;
}
inline long QuickInt (float inval)
{
double dtemp = FIST_MAGIC + (inval - .4999);
return (*(((long*)&dtemp) + 1)) - 0x80000000;
}
#define FIST_MAGIC2 ((((65536.0 * 16) + (0.5)) * 65536.0))
inline long QuickInt16 (float inval)
{
double dtemp = FIST_MAGIC2 + inval;
return (*(((long*)&dtemp) + 1)) - 0x80000000;
}
#endif
#if defined(_CPU_X86) || defined(PROC_M68K)
# define QRound(x) QuickRound(x)
# define QInt(x) QuickInt(x)
# define QInt16(x) QuickInt16(x)
#else
# define QRound(x) ((int)((x) + .5))
# define QInt(x) ((int)(x))
# define QInt16(x) ((int)((x) * 65536.))
#endif
// @@@ I don't know if there is a better way to convert
// a floating point to 8:24 fixed point (one with constants
// like the tricks above instead of the multiplication).
#define QInt24(x) (QInt16(((x) * 256.0f)))
#if STATS
#define STAT(x) x
#else
#define STAT(x)
#endif
//#define SMALL_Z .01
#define SMALL_Z 0.1f
#define USE_OCCLUSION 0 // Experimental feature, will not work in this version.
// Some useful macros: these should be true at least for 32-bit processors
#define LONGFROM2SHORT(s1, s2) (((short)s1) << 16 | (((short)s2) & 0xffff))
#define SHORT1FROMLONG(l) (short)(((int)l) >> 16)
#define SHORT2FROMLONG(l) (short)(((int)l) & 0xffff)
+523
View File
@@ -0,0 +1,523 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include <XRenderD3D9/DeviceManager/Base.h>
#include <XRenderD3D9/DeviceManager/Enums.h>
////////////////////////////////////////////////////////////////////////////////////////
// Usage hints
enum BUFFER_USAGE
{
BU_IMMUTABLE = 0, // For data that never, ever changes
BU_STATIC, // For long-lived data that changes infrequently (every n-frames)
BU_DYNAMIC, // For short-lived data that changes frequently (every frame)
BU_TRANSIENT, // For very short-lived data that can be considered garbage after first usage
BU_TRANSIENT_RT, // For very short-lived data that can be considered garbage after first usage
BU_WHEN_LOADINGTHREAD_ACTIVE, // yes we can ... because renderloadingthread frames not synced with mainthread frames
BU_MAX
};
////////////////////////////////////////////////////////////////////////////////////////
// Binding flags
enum BUFFER_BIND_TYPE
{
BBT_VERTEX_BUFFER = 0,
BBT_INDEX_BUFFER,
BBT_MAX
};
typedef uintptr_t buffer_handle_t;
typedef uint32 item_handle_t;
// CRY DX12
////////////////////////////////////////////////////////////////////////////////////////
struct SDescriptorBlock
{
SDescriptorBlock(uint32 id)
: blockID(id)
, pBuffer(NULL)
, size(0)
, offset(~0u)
{}
const uint32 blockID;
void* pBuffer;
uint32 size;
uint32 offset;
};
class CDeviceBufferManager;
struct ConstantBufferAllocator;
namespace AzRHI
{
enum class ConstantBufferUsage : AZ::u8
{
Static,
Dynamic
};
enum class ConstantBufferFlags : AZ::u8
{
None = 0,
DenyStreaming = BIT(1), // Used by OpenGL for constant buffer streaming
};
AZ_DEFINE_ENUM_BITWISE_OPERATORS(ConstantBufferFlags)
class ConstantBuffer
{
public:
ConstantBuffer(uint32 handle);
virtual ~ConstantBuffer();
inline D3DBuffer* GetPlatformBuffer() const
{
return m_buffer;
}
inline AzRHI::ConstantBufferUsage GetUsage() const
{
return m_usage;
}
inline AzRHI::ConstantBufferFlags GetFlags() const
{
return m_flags;
}
inline AZ::u32 GetByteOffset() const
{
return m_offset;
}
inline AZ::u32 GetByteCount() const
{
return m_size;
}
#if !defined(NULL_RENDERER)
inline AZ::u64 GetCode() const
{
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(DevBuffer_h)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
return reinterpret_cast<AZ::u64>(m_buffer) | ((AZ::u64)m_offset << 40);
#endif
}
#endif // !NULL_RENDERER
void AddRef();
AZ::u32 Release();
void* BeginWrite();
void EndWrite();
void UpdateBuffer(const void* data, AZ::u32 size);
private:
friend class ::CDeviceBufferManager;
friend struct ::ConstantBufferAllocator;
const char* m_name;
D3DBuffer* m_buffer;
item_handle_t m_handle;
void* m_allocator;
void* m_base_ptr;
AZ::u32 m_offset;
AZ::u32 m_size;
ConstantBufferUsage m_usage;
ConstantBufferFlags m_flags;
AZ::u8 m_used : 1;
AZ::u8 m_dynamic : 1;
AZStd::atomic_uint m_refCount;
int m_nHeapOffset;
SDescriptorBlock* m_pDescriptorBlock;
};
using ConstantBufferPtr = _smart_ptr<AzRHI::ConstantBuffer>;
AZ::u32 GetConstantRegisterCountMax(EHWShaderClass shaderClass);
}
////////////////////////////////////////////////////////////////////////////////////////
// Pool statistics
struct SDeviceBufferPoolStats
: private NoCopy
{
string buffer_descr;
size_t bank_size; // size of a pool bank in bytes
size_t num_banks; // number of banks currently allocated
size_t num_allocs; // number of allocs present in the device pool
IDefragAllocatorStats allocator_stats; // backing allocator statistics
SDeviceBufferPoolStats()
: buffer_descr()
, bank_size()
, num_banks()
, num_allocs()
, allocator_stats()
{ memset(&allocator_stats, 0x0, sizeof(allocator_stats)); }
~SDeviceBufferPoolStats() {}
};
class CVertexBuffer;
class CIndexBuffer;
class IDeviceBufferManager
{
friend class CGuardedDeviceBufferManager;
friend class CDeviceManager;
public:
# ifndef NULL_RENDERER
virtual D3DBuffer* GetD3D(buffer_handle_t handle, size_t* outOffset) = 0;
#endif
virtual void LockDevMan() = 0;
virtual void UnlockDevMan() = 0;
private:
virtual buffer_handle_t Create_Locked(BUFFER_BIND_TYPE, BUFFER_USAGE, size_t) = 0;
virtual void Destroy_Locked(buffer_handle_t) = 0;
virtual void* BeginRead_Locked(buffer_handle_t handle) = 0;
virtual void* BeginWrite_Locked(buffer_handle_t handle) = 0;
virtual void EndReadWrite_Locked(buffer_handle_t handle) = 0;
virtual bool UpdateBuffer_Locked(buffer_handle_t handle, const void*, size_t) = 0;
virtual size_t Size_Locked(buffer_handle_t) = 0;
};
class CDeviceBufferManager : public IDeviceBufferManager
{
buffer_handle_t Create_Locked(BUFFER_BIND_TYPE, BUFFER_USAGE, size_t) override;
void Destroy_Locked(buffer_handle_t) override;
void* BeginRead_Locked(buffer_handle_t handle) override;
void* BeginWrite_Locked(buffer_handle_t handle) override;
void EndReadWrite_Locked(buffer_handle_t handle) override;
bool UpdateBuffer_Locked(buffer_handle_t handle, const void*, size_t) override;
size_t Size_Locked(buffer_handle_t) override;
public:
CDeviceBufferManager();
~CDeviceBufferManager();
////////////////////////////////////////////////////////////////////////////////////////
// Initialization and destruction and high level update funcationality
bool Init();
void Update(uint32 frameId, bool called_during_loading);
void ReleaseEmptyBanks(uint32 frameId);
void Sync(uint32 frameId);
bool Shutdown();
AzRHI::ConstantBuffer* CreateConstantBuffer(
const char* name,
AZ::u32 size,
AzRHI::ConstantBufferUsage usage,
AzRHI::ConstantBufferFlags flags = AzRHI::ConstantBufferFlags::None);
////////////////////////////////////////////////////////////////////////////////////////
// Descriptor blocks
SDescriptorBlock* CreateDescriptorBlock(size_t size);
void ReleaseDescriptorBlock(SDescriptorBlock* pBlock);
////////////////////////////////////////////////////////////////////////////////////////
// Locks the global devicebuffer lock
void LockDevMan() override;
void UnlockDevMan() override;
// Returns the size in bytes of the allocation
size_t Size(buffer_handle_t);
////////////////////////////////////////////////////////////////////////////////////////
// Buffer Resource creation methods
//
buffer_handle_t Create(BUFFER_BIND_TYPE, BUFFER_USAGE, size_t);
void Destroy(buffer_handle_t);
////////////////////////////////////////////////////////////////////////////////////////
// Manual IO operations
//
// Note: it's an error to NOT end an IO operation with EndReadWrite!!!
//
// Note: If you are writing (updating) a buffer only partially, please be aware that the
// the contents of the untouched areas might be undefined as a copy-on-write semantic
// ensures that the updating of buffers does not synchronize with the GPU at any cost.
//
void* BeginRead(buffer_handle_t handle);
void* BeginWrite(buffer_handle_t handle);
void EndReadWrite(buffer_handle_t handle);
bool UpdateBuffer(buffer_handle_t handle, const void*, size_t);
////////////////////////////////////////////////////////////////////////////////////////
// Get Stats back from the devbuffer
bool GetStats(BUFFER_BIND_TYPE, BUFFER_USAGE, SDeviceBufferPoolStats&);
# ifndef NULL_RENDERER
D3DBuffer* GetD3D(buffer_handle_t handle, size_t* outOffset);
# endif
/////////////////////////////////////////////////////////////
// Legacy interface
//
// Use with care, can be removed at any point!
CVertexBuffer* CreateVBuffer(size_t, const AZ::Vertex::Format&, const char*, BUFFER_USAGE usage = BU_STATIC); //waltont given that this is a legacy interface, does it make more sense to just remove it? What is the alternative, new interface? The only place that uses it is BreakableGlass.
void ReleaseVBuffer(CVertexBuffer*);
CIndexBuffer* CreateIBuffer(size_t, const char*, BUFFER_USAGE usage = BU_STATIC);
void ReleaseIBuffer(CIndexBuffer*);
bool UpdateVBuffer(CVertexBuffer*, void*, size_t);
bool UpdateIBuffer(CIndexBuffer*, void*, size_t);
};
class CGuardedDeviceBufferManager
: public NoCopy
{
private:
IDeviceBufferManager* m_pDevMan;
public:
explicit CGuardedDeviceBufferManager(IDeviceBufferManager* pDevMan)
: m_pDevMan(pDevMan)
{
m_pDevMan->LockDevMan();
}
~CGuardedDeviceBufferManager()
{
m_pDevMan->UnlockDevMan();
}
inline buffer_handle_t Create(BUFFER_BIND_TYPE type, BUFFER_USAGE usage, size_t size)
{
return m_pDevMan->Create_Locked(type, usage, size);
}
inline void Destroy(buffer_handle_t handle)
{
return m_pDevMan->Destroy_Locked(handle);
}
inline void* BeginRead(buffer_handle_t handle)
{
return m_pDevMan->BeginRead_Locked(handle);
}
inline void* BeginWrite(buffer_handle_t handle)
{
return m_pDevMan->BeginWrite_Locked(handle);
}
inline void EndReadWrite(buffer_handle_t handle)
{
m_pDevMan->EndReadWrite_Locked(handle);
}
inline bool UpdateBuffer(buffer_handle_t handle, const void* src, size_t size)
{
return m_pDevMan->UpdateBuffer_Locked(handle, src, size);
}
# ifndef NULL_RENDERER
inline D3DBuffer* GetD3D(buffer_handle_t handle, size_t* offset)
{
return m_pDevMan->GetD3D(handle, offset);
}
# endif
};
class SRecursiveSpinLock
{
volatile LONG m_lock;
volatile threadID m_owner;
volatile uint16 m_counter;
enum
{
SPIN_COUNT = 10
};
public:
SRecursiveSpinLock()
: m_lock()
, m_owner()
, m_counter()
{}
~SRecursiveSpinLock() {}
void Lock()
{
threadID threadId = CryGetCurrentThreadId();
int32 iterations = 0;
retry:
IF (CryInterlockedCompareExchange(&(this->m_lock), 1L, 0L) == 0L, 1)
{
assert (m_owner == 0u && m_counter == 0u);
m_owner = threadId;
m_counter = 1;
}
else
{
IF (m_owner == threadId, 1)
{
++m_counter;
}
else
{
Sleep((1 & isneg(SPIN_COUNT - iterations++)));
goto retry;
}
}
}
bool TryLock()
{
threadID threadId = CryGetCurrentThreadId();
IF (CryInterlockedCompareExchange(&m_lock, 1L, 0L) == 0L, 1)
{
assert (m_owner == 0u && m_counter == 0u);
m_owner = threadId;
m_counter = 1;
return true;
}
else
{
IF (m_owner == threadId, 1)
{
++m_counter;
return true;
}
else
{
return false;
}
}
}
void Unlock()
{
assert (m_owner == CryGetCurrentThreadId() && m_counter != 0u);
IF ((m_counter -= 1) == 0u, 1)
{
m_owner = 0u;
m_lock = 0L;
MemoryBarrier();
}
}
};
class SRecursiveSpinLocker
{
SRecursiveSpinLock* lock;
public:
SRecursiveSpinLocker(SRecursiveSpinLock* _lock)
: lock(_lock)
{
lock->Lock();
}
~SRecursiveSpinLocker() { lock->Unlock(); }
};
#define SREC_AUTO_LOCK(x) SRecursiveSpinLocker AZ_JOIN(_lock, __LINE__)(&(x))
class CConditonalDevManLock
{
CDeviceBufferManager* m_pDevBufMan;
int m_Active;
public:
explicit CConditonalDevManLock(CDeviceBufferManager* DevMan, int active)
: m_pDevBufMan(DevMan)
, m_Active(active)
{
if (m_Active)
{
m_pDevBufMan->LockDevMan();
}
}
~CConditonalDevManLock()
{
if (m_Active)
{
m_pDevBufMan->UnlockDevMan();
}
}
};
// WrappedDX11Buffer Flags
#define DX11BUF_DYNAMIC BIT(0)
#define DX11BUF_STRUCTURED BIT(1)
#define DX11BUF_BIND_SRV BIT(2)
#define DX11BUF_BIND_UAV BIT(3)
#define DX11BUF_UAV_APPEND BIT(4)
#define DX11BUF_DRAWINDIRECT BIT(5)
#define DX11BUF_STAGING BIT(6)
#if !defined(NULL_RENDERER)
struct WrappedDX11Buffer
{
WrappedDX11Buffer()
: m_pBuffer{}
, m_pSRV{}
, m_pUAV{}
, m_numElements{}
, m_elementSize{}
, m_elementFormat{DXGI_FORMAT_UNKNOWN}
, m_flags(0)
, m_currentBuffer{}
{
}
~WrappedDX11Buffer();
WrappedDX11Buffer(const WrappedDX11Buffer& src);
WrappedDX11Buffer& operator=(const WrappedDX11Buffer& rhs);
bool operator==(const WrappedDX11Buffer& other) const;
D3DUnorderedAccessView* GetUnorderedAccessView() const
{
return m_pUAV[m_currentBuffer];
}
D3DShaderResourceView* GetShaderResourceView() const
{
return m_pSRV[m_currentBuffer];
}
void Create(uint32 numElements, uint32 elementSize, DXGI_FORMAT elementFormat, uint32 flags, const void* pData, int32 nESRAMOffset = -1);
void Release();
void UpdateBufferContent(void* pData, size_t nSize);
static const uint32_t MAX_VIEW_COUNT = 3;
D3DBuffer* m_pBuffer;
D3DShaderResourceView* m_pSRV[MAX_VIEW_COUNT];
D3DUnorderedAccessView* m_pUAV[MAX_VIEW_COUNT];
uint32 m_elementSize;
uint32 m_numElements;
DXGI_FORMAT m_elementFormat;
uint32 m_flags;
uint32_t m_currentBuffer;
};
#endif
+147
View File
@@ -0,0 +1,147 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
///////////////////////////////////////////////////////////////////////////////
// Vertex Data container optmized for direct VideoMemory access on Consoles
// No driver overhead, the lock function returns a direct pointer into Video Memory
// which is used by the GPU
// *NOTE: The programmer has to ensure that the Video Memory is not overwritten
// while beeing used. For this the container provides additional fence and
// wait for fence functions. Also double buffering of the container could be needed
// *NOTE: On non console platforms, this container is using the driver facilities to ensure
// no memory is overwrite. This could mean additional memory allocated by the driver
template <class IndexType>
class FencedIB
{
public:
FencedIB(uint32 nIndexCount, uint32 nIndexStride);
~FencedIB();
IndexType* LockIB(uint32 nLockCount);
void UnlockIB();
HRESULT Bind(uint32 nOffs);
uint32 GetIndexCount() const;
void SetFence();
void WaitForFence();
private:
D3DBuffer* m_pIB;
uint32 m_nIndexCount;
IndexType* m_pLockedData;
uint32 m_nIndexStride;
DeviceFenceHandle m_Fence;
};
///////////////////////////////////////////////////////////////////////////////
template <class IndexType>
FencedIB<IndexType>::FencedIB(uint32 nIndexCount, uint32 nIndexStride)
: m_pIB(NULL)
, m_pLockedData(NULL)
, m_nIndexStride(nIndexStride)
, m_nIndexCount(nIndexCount)
{
HRESULT hr = gRenDev->m_DevMan.CreateDirectAccessBuffer(m_nIndexCount, m_nIndexStride, CDeviceManager::BIND_INDEX_BUFFER, (D3DBuffer**)&m_pIB);
CHECK_HRESULT(hr);
gRenDev->m_DevMan.CreateFence(m_Fence);
}
///////////////////////////////////////////////////////////////////////////////
template <class IndexType>
FencedIB<IndexType>::~FencedIB()
{
UnlockIB();
if (m_pIB)
{
gRenDev->m_DevMan.DestroyDirectAccessBuffer((D3DBuffer*)m_pIB);
}
gRenDev->m_DevMan.ReleaseFence(m_Fence);
}
///////////////////////////////////////////////////////////////////////////////
template <class IndexType>
IndexType* FencedIB<IndexType>::LockIB([[maybe_unused]] uint32 nLockCount)
{
// Ensure there is enough space in the VB for this data
assert (nLockCount <= m_nIndexCount);
if (m_pLockedData)
{
return m_pLockedData;
}
if (m_pIB)
{
gRenDev->m_DevMan.LockDirectAccessBuffer((D3DBuffer*)m_pIB, CDeviceManager::BIND_INDEX_BUFFER, (void**)&m_pLockedData);
}
return m_pLockedData;
}
///////////////////////////////////////////////////////////////////////////////
template <class IndexType>
void FencedIB<IndexType>::UnlockIB()
{
if (m_pLockedData && m_pIB)
{
gRenDev->m_DevMan.UnlockDirectAccessBuffer((D3DBuffer*)m_pIB, CDeviceManager::BIND_INDEX_BUFFER);
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(FencedIB_h)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
# else
CDeviceManager::InvalidateCpuCache(m_pLockedData, 0, m_nIndexCount * m_nIndexStride);
CDeviceManager::InvalidateGpuCache((D3DBuffer*)m_pIB, m_pLockedData, 0, m_nIndexCount * m_nIndexStride);
# endif
m_pLockedData = NULL;
}
}
///////////////////////////////////////////////////////////////////////////////
template <class IndexType>
HRESULT FencedIB<IndexType>::Bind(uint32 nOffs)
{
COMPILE_TIME_ASSERT(sizeof(IndexType) == 2 || sizeof(IndexType) == 4);
return gcpRendD3D->FX_SetIStream(m_pIB, nOffs, (sizeof(IndexType) == 2 ? Index16 : Index32));
}
///////////////////////////////////////////////////////////////////////////////
template <class IndexType>
uint32 FencedIB<IndexType>::GetIndexCount() const
{
return m_nIndexCount;
}
///////////////////////////////////////////////////////////////////////////////
template <class IndexType>
void FencedIB<IndexType>::SetFence()
{
#if BUFFER_ENABLE_DIRECT_ACCESS == 1
gRenDev->m_DevMan.IssueFence(m_Fence);
#endif
}
///////////////////////////////////////////////////////////////////////////////
template <class IndexType>
void FencedIB<IndexType>::WaitForFence()
{
#if BUFFER_ENABLE_DIRECT_ACCESS == 1
gRenDev->m_DevMan.SyncFence(m_Fence, true, false);
#endif
}
+149
View File
@@ -0,0 +1,149 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
///////////////////////////////////////////////////////////////////////////////
// Vertex Data container optmized for direct VideoMemory access on Consoles
// No driver overhead, the lock function returns a direct pointer into Video Memory
// which is used by the GPU
// *NOTE: The programmer has to ensure that the Video Memory is not overwritten
// while beeing used. For this the container provides additional fence and
// wait for fence functions. Also double buffering of the container could be needed
// *NOTE: On non console platforms, this container is using the driver facilities to ensure
// no memory is overwrite. This could mean additional memory allocated by the driver
template <class VertexType>
class FencedVB
{
public:
FencedVB(uint32 nVertexCount, uint32 nVertStride);
~FencedVB();
VertexType* LockVB(uint32 nLockCount);
void UnlockVB();
HRESULT Bind(uint32 StreamNumber = 0, int nBytesOffset = 0, int nStride = 0);
uint32 GetVertexCount() const;
void SetFence();
void WaitForFence();
private:
D3DBuffer* m_pVB;
uint32 m_nVertexCount;
VertexType* m_pLockedData;
uint32 m_nVertStride;
DeviceFenceHandle m_Fence;
};
///////////////////////////////////////////////////////////////////////////////
template <class VertexType>
FencedVB<VertexType>::FencedVB(uint32 nVertexCount, uint32 nVertStride)
: m_pVB(NULL)
, m_pLockedData(NULL)
, m_nVertStride(nVertStride)
, m_nVertexCount(nVertexCount)
{
HRESULT hr = gRenDev->m_DevMan.CreateDirectAccessBuffer(m_nVertexCount, m_nVertStride, CDeviceManager::BIND_VERTEX_BUFFER, (D3DBuffer**)&m_pVB);
CHECK_HRESULT(hr);
gRenDev->m_DevMan.CreateFence(m_Fence);
}
///////////////////////////////////////////////////////////////////////////////
template <class VertexType>
FencedVB<VertexType>::~FencedVB()
{
UnlockVB();
if (m_pVB)
{
gRenDev->m_DevMan.DestroyDirectAccessBuffer((D3DBuffer*)m_pVB);
}
gRenDev->m_DevMan.ReleaseFence(m_Fence);
}
///////////////////////////////////////////////////////////////////////////////
template <class VertexType>
VertexType* FencedVB<VertexType>::LockVB([[maybe_unused]] uint32 nLockCount)
{
// Ensure there is enough space in the VB for this data
assert (nLockCount <= m_nVertexCount);
if (m_pLockedData)
{
return m_pLockedData;
}
if (m_pVB)
{
gRenDev->m_DevMan.LockDirectAccessBuffer((D3DBuffer*)m_pVB, CDeviceManager::BIND_VERTEX_BUFFER, (void**)&m_pLockedData);
}
return m_pLockedData;
}
///////////////////////////////////////////////////////////////////////////////
template <class VertexType>
void FencedVB<VertexType>::UnlockVB()
{
if (m_pLockedData && m_pVB)
{
gRenDev->m_DevMan.UnlockDirectAccessBuffer((D3DBuffer*)m_pVB, CDeviceManager::BIND_VERTEX_BUFFER);
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(FencedVB_h)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
# else
CDeviceManager::InvalidateCpuCache(m_pLockedData, 0, m_nVertexCount * m_nVertStride);
CDeviceManager::InvalidateGpuCache((D3DBuffer*)m_pVB, m_pLockedData, 0, m_nVertexCount * m_nVertStride);
# endif
m_pLockedData = NULL;
}
}
///////////////////////////////////////////////////////////////////////////////
template <class VertexType>
HRESULT FencedVB<VertexType>::Bind(uint32 StreamNumber, int nBytesOffset, int nStride)
{
HRESULT h = gcpRendD3D->FX_SetVStream(StreamNumber, m_pVB, nBytesOffset, nStride == 0 ? m_nVertStride : nStride);
CHECK_HRESULT(h);
return h;
}
///////////////////////////////////////////////////////////////////////////////
template <class VertexType>
uint32 FencedVB<VertexType>::GetVertexCount() const
{
return m_nVertexCount;
}
///////////////////////////////////////////////////////////////////////////////
template <class VertexType>
void FencedVB<VertexType>::SetFence()
{
#if BUFFER_ENABLE_DIRECT_ACCESS == 1
gRenDev->m_DevMan.IssueFence(m_Fence);
#endif
}
///////////////////////////////////////////////////////////////////////////////
template <class VertexType>
void FencedVB<VertexType>::WaitForFence()
{
#if BUFFER_ENABLE_DIRECT_ACCESS == 1
gRenDev->m_DevMan.SyncFence(m_Fence, true, false);
#endif
}
@@ -0,0 +1,206 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// A simple profiler useful for collecting multiple call times per frame
// and displaying their different average statistics.
// For usage, see the bottom of the file
#pragma once
#include <AzCore/Debug/Profiler.h>
#define PP_CONCAT2(A, B) A##B
#define PP_CONCAT(A, B) PP_CONCAT2(A, B)
// set #if 0 here if you don't want profiling to be compiled in the code
//#if 0
#ifdef ENABLE_FRAME_PROFILER
// define PROFILE_RENDERER_DETAILED for additional render device events
// #define PROFILE_RENDERER_DETAILED
#ifdef PROFILE_RENDERER_DETAILED
# define PROFILE_FRAME(id) FRAME_PROFILER_FAST("Renderer:" #id, iSystem, PROFILE_RENDERER, g_bProfilerEnabled)
#else
# define PROFILE_FRAME(id)
#endif
#define PROFILE_PS_TIME_SCOPE(EXT) \
PROFILE_PS_TIME_SCOPE_COND(EXT, true)
#define PROFILE_PS_TIME_SCOPE_COND(EXT, CONDITION) \
class CProfilePSTimeScope \
{ \
bool m_bCondition; \
CTimeValue m_startTime; \
public: \
CProfilePSTimeScope(bool bCondition) \
{ \
m_bCondition = bCondition; \
if (bCondition) { \
m_startTime = iTimer->GetAsyncTime(); } \
} \
~CProfilePSTimeScope() \
{ \
if (m_bCondition) { \
gRenDev->m_RP.m_PS[gRenDev->m_RP.m_nProcessThreadID].m_##EXT += iTimer->GetAsyncTime().GetDifferenceInSeconds(m_startTime); } \
} \
} PP_CONCAT(profilePSTimeScope, __LINE__)(CONDITION);
#define PROFILE_DIPS_START \
CTimeValue TimeDIP = iTimer->GetAsyncTime(); \
#define PROFILE_DIPS_END(id) \
gRenDev->m_RP.m_PS[gRenDev->m_RP.m_nProcessThreadID].m_fTimeDIPs[id] += iTimer->GetAsyncTime().GetDifferenceInSeconds(TimeDIP); \
// to get around a stupid compiler bug (Win32 debug with Edit and Continue enabled) where assert can't be used
#if defined(_DEBUG)
#define FP_CHECK_SHADER if (!gRenDev->m_RP.m_pShader) {__debugbreak(); }
#else
#define FP_CHECK_SHADER
#endif
#define PROFILE_SHADER_SCOPE \
class CProfileShaderScope \
{ \
bool bProfile; \
bool bDoEnd; \
float time0; \
int nNumDips; \
int nNumPolys; \
public: \
CProfileShaderScope() \
{ \
bDoEnd = true; \
time0 = 0; \
nNumDips = 0; \
nNumPolys = 0; \
if (CRenderer::CV_r_profileshaders == 1 || (CRenderer::CV_r_profileshaders == 2 && gRenDev->m_RP.m_pCurObject && (gRenDev->m_RP.m_pCurObject->m_ObjFlags & FOB_SELECTED))) \
{ \
bProfile = true; \
time0 = iTimer->GetAsyncCurTime(); \
gRenDev->m_RP.m_fProfileTime = time0; \
nNumPolys = gRenDev->m_RP.m_PS[gRenDev->m_RP.m_nProcessThreadID].m_nPolygons[gRenDev->m_RP.m_nPassGroupDIP]; \
nNumDips = gRenDev->m_RP.m_PS[gRenDev->m_RP.m_nProcessThreadID].m_nDIPs[gRenDev->m_RP.m_nPassGroupDIP]; \
} \
else \
{ \
bProfile = false; \
} \
} \
~CProfileShaderScope() \
{ End(); } \
void End() \
{ \
if (!bDoEnd) { \
return; } \
bDoEnd = false; \
float fTime = 0; \
if (bProfile) \
{ \
float time1 = iTimer->GetAsyncCurTime(); \
fTime = time1 - time0; \
} \
\
if (gRenDev->m_RP.m_pShader && gRenDev->m_RP.m_pCurTechnique) \
{ \
if (CRenderer::CV_r_profileshaders == 1 || (CRenderer::CV_r_profileshaders == 2 && gRenDev->m_RP.m_pCurObject && (gRenDev->m_RP.m_pCurObject->m_ObjFlags & FOB_SELECTED))) \
{ \
if (time0 == gRenDev->m_RP.m_fProfileTime) \
{ \
SProfInfo pi; \
pi.Time = fTime; \
pi.NumPolys = gRenDev->m_RP.m_PS[gRenDev->m_RP.m_nProcessThreadID].m_nPolygons[gRenDev->m_RP.m_nPassGroupDIP] - nNumPolys; \
pi.NumDips = gRenDev->m_RP.m_PS[gRenDev->m_RP.m_nProcessThreadID].m_nDIPs[gRenDev->m_RP.m_nPassGroupDIP] - nNumDips; \
FP_CHECK_SHADER; \
pi.pShader = gRenDev->m_RP.m_pShader; \
pi.pTechnique = gRenDev->m_RP.m_pCurTechnique; \
pi.m_nItems = 0; \
gRenDev->m_RP.m_Profile.AddElem(pi); \
} \
} \
} \
} \
} profileShaderScope;
#define PROFILE_SHADER_START \
PROFILE_SHADER_SCOPE
#define PROFILE_SHADER_END \
profileShaderScope.End();
#else
#define PROFILE_FRAME(id)
#define PROFILE_SHADER_SCOPE
#define PROFILE_SHADER_START
#define PROFILE_SHADER_END
#define PROFILE_PS_TIME_SCOPE(EXT)
#define PROFILE_PS_TIME_SCOPE_COND(EXT, CONDITION)
#define PROFILE_DIPS_START
#define PROFILE_DIPS_END(id)
#endif
#if defined(ENABLE_FRAME_PROFILER_LABELS)
// define these to instrument push/pop marker for GPU, also added to the internal profiler and CPU Markers
#define PROFILE_LABEL(X)
#define PROFILE_LABEL_PUSH(X)
#define PROFILE_LABEL_POP(X)
// scope util class for GPU profiling Marker
#define PROFILE_LABEL_SCOPE(X) \
AZ_PROFILE_SCOPE(AZ::Debug::ProfileCategory::Renderer, X); \
class CProfileLabelScope \
{ \
const char* m_label; \
AZ::Debug::EventTrace::ScopedSlice m_slice; \
public: \
CProfileLabelScope(const char* label) \
: m_label(label) \
, m_slice(label, "Renderer") \
{ PROFILE_LABEL_PUSH(label); } \
~CProfileLabelScope() \
{ PROFILE_LABEL_POP(m_label); } \
} PP_CONCAT(profileLabelScope, __LINE__)(X);
// scope util class for GPU profiling Marker with a dynamic string name
#define PROFILE_LABEL_SCOPE_DYNAMIC(X) \
AZ_PROFILE_SCOPE_DYNAMIC(AZ::Debug::ProfileCategory::Renderer, "%s", X); \
class CProfileLabelScope \
{ \
const char* m_label; \
AZ::Debug::EventTrace::ScopedSlice m_slice; \
public: \
CProfileLabelScope(const char* label) \
: m_label(label) \
, m_slice(label, "Renderer") \
{ PROFILE_LABEL_PUSH(label); } \
~CProfileLabelScope() \
{ PROFILE_LABEL_POP(m_label); } \
} PP_CONCAT(profileLabelScope, __LINE__)(X);
#else
#define PROFILE_LABEL(X)
#define PROFILE_LABEL_PUSH(X)
#define PROFILE_LABEL_POP(X)
#define PROFILE_LABEL_SCOPE(X)
#endif
#define PROFILE_LABEL_SHADER(X) PROFILE_LABEL(X)
#if defined(ENABLE_FRAME_PROFILER) && !defined(_RELEASE)
#define FUNCTION_PROFILER_RENDER_FLAT \
FUNCTION_PROFILER_LEGACYONLY(gEnv->pSystem, PROFILE_RENDERER) \
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::RendererDetailed)
#else
#define FUNCTION_PROFILER_RENDER_FLAT
#endif
@@ -0,0 +1,23 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include <IColorGradingController.h>
struct IColorGradingControllerInt
: public IColorGradingController
{
virtual void RT_SetLayers(const SColorChartLayer* pLayers, uint32 numLayers) = 0;
};
@@ -0,0 +1,182 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifdef __cplusplus
// C++
#pragma once
#pragma pack(push,4)
#define hlsl_cbuffer(name) struct HLSL_##name
#define hlsl_cbuffer_register(name, reg, slot) \
enum { SLOT_##name = slot }; \
struct HLSL_##name
#define hlsl_int(member) int32 member
#define hlsl_int2(member) Vec2i member
#define hlsl_int3(member) Vec3i member
#define hlsl_int4(member) Vec4i member
#define hlsl_uint(member) uint32 member
#define hlsl_uint2(member) Vec2ui member
#define hlsl_uint3(member) Vec3ui member
#define hlsl_uint4(member) Vec4ui member
#define hlsl_float(member) float member
#define hlsl_float2(member) Vec2 member
#define hlsl_float3(member) Vec3 member
#define hlsl_float4(member) Vec4 member
#define hlsl_matrix44(member) Matrix44 member
#define hlsl_matrix34(member) Matrix34 member
#else //__cplusplus
// HLSL
#define hlsl_cbuffer(name) cbuffer name
#define hlsl_cbuffer_register(name, reg, float) cbuffer name: reg
#define hlsl_int(member) int member
#define hlsl_int2(member) int2 member
#define hlsl_int3(member) int3 member
#define hlsl_int4(member) int4 member
#define hlsl_uint(member) uint member
#define hlsl_uint2(member) uint2 member
#define hlsl_uint3(member) uint3 member
#define hlsl_uint4(member) uint4 member
#define hlsl_float(member) float member
#define hlsl_float2(member) float2 member
#define hlsl_float3(member) float3 member
#define hlsl_float4(member) float4 member
#define hlsl_matrix44(member) float4x4 member
#define hlsl_matrix34(member) float3x4 member
#endif //__cplusplus
// TODO: include in shaders
hlsl_cbuffer(PerPassConstantBuffer_GBuffer)
{
hlsl_float4(g_VS_WorldViewPos);
hlsl_matrix44(g_VS_ViewProjMatr);
hlsl_matrix44(g_VS_ViewProjZeroMatr);
};
#if defined(FEATURE_SVO_GI)
hlsl_cbuffer(PerPassConstantBuffer_Svo)
{
hlsl_float4(PerPass_SvoTreeSettings0);
hlsl_float4(PerPass_SvoTreeSettings1);
hlsl_float4(PerPass_SvoParams0);
hlsl_float4(PerPass_SvoParams1);
hlsl_float4(PerPass_SvoParams2);
hlsl_float4(PerPass_SvoParams3);
hlsl_float4(PerPass_SvoParams4);
hlsl_float4(PerPass_SvoParams5);
hlsl_float4(PerPass_SvoParams6);
};
#endif
hlsl_cbuffer(PerSubPassConstantBuffer_ShadowGen)
{
hlsl_float4(PerShadow_LightPos);
hlsl_float4(PerShadow_ViewPos);
hlsl_float4(PerShadow_FrustumInfo);
hlsl_float4(PerShadow_BiasInfo);
};
hlsl_cbuffer(PerInstanceConstantBuffer)
{
hlsl_matrix34(SPIObjWorldMat);
hlsl_float4(SPIBendInfo);
hlsl_float4(SPIBendInfoPrev);
hlsl_float4(SPIAmbientOpacity);
hlsl_float4(SPIDissolveRef);
};
hlsl_cbuffer(PerViewConstantBuffer)
{
hlsl_float4(PerView_WorldViewPos);
hlsl_float4(PerView_WorldViewPosPrev);
hlsl_matrix44(PerView_ViewProjZeroMatr);
hlsl_matrix44(PerView_ViewProjZeroMatrPrev);
hlsl_matrix44(PerView_ViewProjZeroMatrPrevNearest);
hlsl_float4(PerView_AnimGenParams);
hlsl_float4(PerView_ViewBasisX);
hlsl_float4(PerView_ViewBasisY);
hlsl_float4(PerView_ViewBasisZ);
hlsl_matrix44(PerView_ViewProjMatr);
hlsl_matrix44(PerView_ViewProjMatrPrev);
hlsl_matrix44(PerView_ViewMatr);
hlsl_matrix44(PerView_ProjMatr);
hlsl_float4(PerView_TessellationParams);
hlsl_float4(PerView_ScreenSize);
hlsl_float4(PerView_HPosScale);
hlsl_float4(PerView_ProjRatio);
hlsl_float4(PerView_NearestScaled);
hlsl_float4(PerView_NearFarClipDist);
hlsl_float4(PerView_FogColor);
hlsl_matrix44(PerView_FrustumPlaneEquation);
hlsl_float4(PerView_JitterParams);
};
hlsl_cbuffer(PerFrameConstantBuffer)
{
hlsl_float4(PerFrame_VolumetricFogParams);
hlsl_float4(PerFrame_VolumetricFogRampParams);
hlsl_float4(PerFrame_VolumetricFogColorGradientBase);
hlsl_float4(PerFrame_VolumetricFogColorGradientDelta);
hlsl_float4(PerFrame_VolumetricFogColorGradientParams);
hlsl_float4(PerFrame_VolumetricFogColorGradientRadial);
hlsl_float4(PerFrame_VolumetricFogSamplingParams);
hlsl_float4(PerFrame_VolumetricFogDistributionParams);
hlsl_float4(PerFrame_VolumetricFogScatteringParams);
hlsl_float4(PerFrame_VolumetricFogScatteringBlendParams);
hlsl_float4(PerFrame_VolumetricFogScatteringColor);
hlsl_float4(PerFrame_VolumetricFogScatteringSecondaryColor);
hlsl_float4(PerFrame_VolumetricFogHeightDensityParams);
hlsl_float4(PerFrame_VolumetricFogHeightDensityRampParams);
hlsl_float4(PerFrame_VolumetricFogDistanceParams);
hlsl_float4(PerFrame_VolumetricFogGlobalEnvProbe0);
hlsl_float4(PerFrame_VolumetricFogGlobalEnvProbe1);
hlsl_float4(PerFrame_SvoLightingParams);
hlsl_float4(PerFrame_Time);
hlsl_float4(PerFrame_SunColor);
hlsl_float4(PerFrame_SunDirection);
hlsl_float4(PerFrame_HDRParams);
hlsl_float4(PerFrame_CloudShadingColorSun);
hlsl_float4(PerFrame_CloudShadingColorSky);
hlsl_float4(PerFrame_CloudShadowParams);
hlsl_float4(PerFrame_CloudShadowAnimParams);
hlsl_float4(PerFrame_CausticsSmoothSunDirection);
hlsl_float4(PerFrame_DecalZFightingRemedy);
hlsl_float4(PerFrame_WaterLevel);
hlsl_float4(PerFrame_StereoParams);
hlsl_float4(PerFrame_RandomParams);
hlsl_uint4(PerFrame_MultiLayerAlphaBlendLayerData);
};
#ifdef __cplusplus
// C++
#pragma pack(pop)
#else //__cplusplus
// HLSL
#endif //__cplusplus
@@ -0,0 +1,393 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "RenderDll_precompiled.h"
#include <Common/Memory/VRAMDriller.h>
#include <AzCore/Math/Crc.h>
namespace Render
{
namespace Debug
{
//=========================================================================
struct VRAMCategoryInfo
{
VRAMAllocationCategory m_category = VRAM_CATEGORY_INVALID;
const char* m_categoryName = nullptr;
VRAMSubCategoryType m_subcategories;
};
struct VRAMAllocationInfo
{
void* m_address = nullptr;
size_t m_byteSize = 0;
string m_allocationName;
VRAMAllocationCategory m_category = VRAM_CATEGORY_INVALID;
VRAMAllocationSubcategory m_subcategory = VRAM_SUBCATEGORY_INVALID;
};
typedef AZStd::unordered_map<VRAMAllocationCategory, VRAMCategoryInfo, AZStd::hash<VRAMAllocationCategory>, AZStd::equal_to<VRAMAllocationCategory>, AZ::OSStdAllocator> VRAMCategoryType;
typedef AZStd::unordered_map<void*, VRAMAllocationInfo, AZStd::hash<void*>, AZStd::equal_to<void*>, AZ::OSStdAllocator> VRAMAllocationRecordsType;
/**
* VRAMDrillerAllocations: A class that tracks VRAM allocations and categories/subcategories for the allocations
*/
class VRAMDrillerAllocations
{
friend class VRAMDriller;
AZ_CLASS_ALLOCATOR(VRAMDrillerAllocations, AZ::OSAllocator, 0)
public:
VRAMDrillerAllocations() {}
~VRAMDrillerAllocations()
{
m_allocations.clear();
}
//=========================================================================
const VRAMCategoryInfo* RegisterCategory(VRAMAllocationCategory category, const char* categoryName, const VRAMSubCategoryType& subcategories)
{
AZ_Assert(category < VRAM_CATEGORY_INVALID, ("Error, invalid VRAM category"));
// Insert and populate the category
VRAMCategoryType::pair_iter_bool iterBool = m_categories.insert_key(category);
AZ_Assert(iterBool.second, "VRAM category %u is already registered!", category);
VRAMCategoryInfo& categoryInfo = iterBool.first->second;
categoryInfo.m_category = category;
categoryInfo.m_categoryName = categoryName;
categoryInfo.m_subcategories = subcategories;
return &categoryInfo;
}
void UnregisterAllCategories(AZ::Debug::DrillerOutputStream* output)
{
// Skip if we have no active output
if (output != nullptr)
{
for (AZStd::pair<VRAMAllocationCategory, VRAMCategoryInfo> currentCategory : m_categories)
{
output->BeginTag(AZ_CRC("VRAMDriller"));
output->BeginTag(AZ_CRC("UnregisterCategory"));
output->Write(AZ_CRC("Category"), static_cast<unsigned int>(currentCategory.first));
output->EndTag(AZ_CRC("UnregisterCategory"));
output->EndTag(AZ_CRC("VRAMDriller"));
}
}
m_categories.clear();
}
const VRAMCategoryType& GetCategoriesMap()
{
return m_categories;
}
//=========================================================================
const VRAMAllocationInfo* RegisterAllocation(void* address, size_t byteSize, const char* allocationName, VRAMAllocationCategory category, VRAMAllocationSubcategory subcategory)
{
AZ_Assert(address, ("Error, allocation address is null"));
// Insert and populate the allocation record
VRAMAllocationRecordsType::pair_iter_bool iterBool = m_allocations.insert_key(address);
// Turning off the VRAMDriller altogether causes weird allocation errors
AZ_Warning("Driller", iterBool.second, "VRAM memory address 0x%p is already allocated and being tracked! VRAM memory reporting may now be inaccurate.", address);
VRAMAllocationInfo& allocationInfo = iterBool.first->second;
allocationInfo.m_byteSize = byteSize;
allocationInfo.m_allocationName = allocationName;
allocationInfo.m_category = category;
allocationInfo.m_subcategory = subcategory;
// Update simple tracking statistics
m_simpleAllocationStatistics[category][subcategory].m_allocatedBytes += byteSize;
m_simpleAllocationStatistics[category][subcategory].m_numberAllocations++;
return &allocationInfo;
}
void UnregisterAllocation(void* address)
{
VRAMAllocationRecordsType::iterator iter = m_allocations.find(address);
// Turning off the VRAMDriller altogether causes weird allocation errors
AZ_Warning("Driller", iter != m_allocations.end(), "VRAM memory address 0x%p does not exist in the records. VRAM memory reporting may now be inaccurate.", address);
if ( iter != m_allocations.end() )
{
// Update simple tracking statistics
VRAMAllocationInfo& allocationInfo = iter->second;
m_simpleAllocationStatistics[allocationInfo.m_category][allocationInfo.m_subcategory].m_allocatedBytes -= allocationInfo.m_byteSize;
m_simpleAllocationStatistics[allocationInfo.m_category][allocationInfo.m_subcategory].m_numberAllocations--;
m_allocations.erase(iter);
}
}
const VRAMAllocationRecordsType& GetAllocationsMap()
{
return m_allocations;
}
//=========================================================================
struct SimpleAllocationStatistics
{
size_t m_allocatedBytes = 0;
size_t m_numberAllocations = 0;
};
SimpleAllocationStatistics m_simpleAllocationStatistics[VRAM_CATEGORY_NUMBER_CATEGORIES][VRAM_SUBCATEGORY_NUMBER_SUBCATEGORIES];
private:
VRAMCategoryType m_categories;
VRAMAllocationRecordsType m_allocations;
};
//=========================================================================
VRAMDriller::VRAMDriller()
{
#if PLATFORM_MEMORY_INSTRUMENTATION_ENABLED
m_platformMemoryInstrumentationRootGroupId = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationRootGroupId, "VRAM", AZ::PlatformMemoryInstrumentation::m_groupRoot);
m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_TEXTURE] = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_TEXTURE], "Texture", m_platformMemoryInstrumentationRootGroupId);
m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_BUFFER] = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_BUFFER], "Buffer", m_platformMemoryInstrumentationRootGroupId);
m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_MISC] = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_MISC], "Misc", m_platformMemoryInstrumentationRootGroupId);
m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_TEXTURE_RENDERTARGET] = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_TEXTURE_RENDERTARGET], "Render Target", m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_TEXTURE]);
m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_TEXTURE_TEXTURE] = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_TEXTURE_TEXTURE], "Texture", m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_TEXTURE]);
m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_TEXTURE_DYNAMIC] = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_TEXTURE_DYNAMIC], "Dynamic", m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_TEXTURE]);
m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_BUFFER_VERTEX_BUFFER] = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_BUFFER_VERTEX_BUFFER], "Vertex Buffer", m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_BUFFER]);
m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_BUFFER_INDEX_BUFFER] = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_BUFFER_INDEX_BUFFER], "Index Buffer", m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_BUFFER]);
m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_BUFFER_CONSTANT_BUFFER] = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_BUFFER_CONSTANT_BUFFER], "Constant Buffer", m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_BUFFER]);
m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_BUFFER_OTHER_BUFFER] = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_BUFFER_OTHER_BUFFER], "Other Buffer", m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_BUFFER]);
m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_MISC_OTHER] = AZ::PlatformMemoryInstrumentation::GetNextGroupId();
AZ::PlatformMemoryInstrumentation::RegisterGroup(m_platformMemoryInstrumentationSubcategoryIds[VRAM_SUBCATEGORY_MISC_OTHER], "Misc", m_platformMemoryInstrumentationCategoryIds[VRAM_CATEGORY_MISC]);
#endif
BusConnect();
}
VRAMDriller::~VRAMDriller()
{
BusDisconnect();
}
const char* VRAMDriller::GroupName() const
{
return "RenderingDrillers";
}
const char* VRAMDriller::GetName() const
{
return "VRAMDriller";
}
const char* VRAMDriller::GetDescription() const
{
return "Reports all VRAM memory allocations.";
}
void VRAMDriller::Start(const Param* params, int numParams)
{
(void)params;
(void)numParams;
if (m_allocations)
{
const VRAMCategoryType& categoriesMap = m_allocations->GetCategoriesMap();
for (VRAMCategoryType::const_iterator iter = categoriesMap.begin(); iter != categoriesMap.end(); ++iter)
{
RegisterCategoryOutput(iter->first, &iter->second);
}
const VRAMAllocationRecordsType& allocationMap = m_allocations->GetAllocationsMap();
for (VRAMAllocationRecordsType::const_iterator iter = allocationMap.begin(); iter != allocationMap.end(); ++iter)
{
RegisterAllocationOutput(iter->first, &iter->second);
}
}
}
void VRAMDriller::Stop()
{
}
void VRAMDriller::CreateAllocationRecords([[maybe_unused]] unsigned char stackRecordLevels, [[maybe_unused]] bool isMemoryGuard, [[maybe_unused]] bool isMarkUnallocatedMemory)
{
AZ_Assert(m_allocations == nullptr, "Allocation records for the VRAMDriller already exist");
m_allocations = aznew VRAMDrillerAllocations();
}
void VRAMDriller::DestroyAllocationRecords()
{
AZ_Assert(m_allocations != nullptr, "Allocation records for the VRAMDriller do not exist");
delete m_allocations;
m_allocations = nullptr;
}
//=========================================================================
void VRAMDriller::RegisterAllocation(void* address, size_t byteSize, const char* allocationName, VRAMAllocationCategory category, VRAMAllocationSubcategory subcategory)
{
AZ_Assert(category != VRAM_CATEGORY_INVALID, "Invalid VRAM allocation category");
AZ_Assert(subcategory != VRAM_SUBCATEGORY_INVALID, "No subcategory provided for VRAM Allocation");
#if PLATFORM_MEMORY_INSTRUMENTATION_ENABLED
AZ::PlatformMemoryInstrumentation::Alloc(address, byteSize, 0, m_platformMemoryInstrumentationSubcategoryIds[subcategory]);
#else
AZ_Assert(m_allocations != nullptr, "Allocation records for the VRAMDriller do not exist!");
const VRAMAllocationInfo* info = m_allocations->RegisterAllocation(address, byteSize, allocationName, category, subcategory);
// Skip if we have no active output
if (m_output == nullptr)
{
return;
}
RegisterAllocationOutput(address, info);
#endif
}
void VRAMDriller::RegisterAllocationOutput(void* address, const VRAMAllocationInfo* info)
{
AZ_Assert(m_output != nullptr, ("The DrillerOutputStream is null"));
m_output->BeginTag(AZ_CRC("VRAMDriller"));
m_output->BeginTag(AZ_CRC("RegisterAllocation", 0x992a9780));
m_output->Write(AZ_CRC("Address", 0x0d4e6f81), address);
m_output->Write(AZ_CRC("Category"), static_cast<unsigned int>(info->m_category));
m_output->Write(AZ_CRC("Subcategory"), static_cast<unsigned int>(info->m_subcategory));
m_output->Write(AZ_CRC("Name", 0x5e237e06), info->m_allocationName.c_str());
m_output->Write(AZ_CRC("Size", 0xf7c0246a), info->m_byteSize);
m_output->EndTag(AZ_CRC("RegisterAllocation", 0x992a9780));
m_output->EndTag(AZ_CRC("VRAMDriller"));
}
void VRAMDriller::UnregisterAllocation(void* address)
{
#if PLATFORM_MEMORY_INSTRUMENTATION_ENABLED
AZ::PlatformMemoryInstrumentation::Free(address);
#else
AZ_Assert(m_allocations != nullptr, "Allocation records for the VRAMDriller do not exist!");
m_allocations->UnregisterAllocation(address);
// Skip if the driller is not actively capturing
if (m_output == nullptr)
{
return;
}
m_output->BeginTag(AZ_CRC("VRAMDriller"));
m_output->BeginTag(AZ_CRC("UnRegisterAllocation", 0xea5dc4cd));
m_output->Write(AZ_CRC("Address", 0x0d4e6f81), address);
m_output->EndTag(AZ_CRC("UnRegisterAllocation", 0xea5dc4cd));
m_output->EndTag(AZ_CRC("VRAMDriller"));
#endif
}
//=========================================================================
void VRAMDriller::RegisterCategory(VRAMAllocationCategory category, const char* categoryName, const VRAMSubCategoryType& subcategories)
{
AZ_Assert(m_allocations != nullptr, "Allocation records for the VRAMDriller do not exist!");
AZ_Assert(category != VRAM_CATEGORY_INVALID, "Invalid VRAM allocation category");
AZ_Assert(subcategories.size(), "No subcategory provided for VRAM category");
const VRAMCategoryInfo* info = m_allocations->RegisterCategory(category, categoryName, subcategories);
// Skip if the driller is not actively capturing
if (m_output == nullptr)
{
return;
}
RegisterCategoryOutput(category, info);
}
void VRAMDriller::RegisterCategoryOutput(VRAMAllocationCategory category, const VRAMCategoryInfo* info)
{
AZ_Assert(m_output != nullptr, ("The DrillerOutputStream is null"));
AZ_Assert(info != nullptr, ("The VRAMCategoryInfo is null"));
m_output->BeginTag(AZ_CRC("VRAMDriller"));
m_output->BeginTag(AZ_CRC("RegisterCategory"));
m_output->Write(AZ_CRC("Category"), static_cast<unsigned int>(category));
m_output->Write(AZ_CRC("CategoryName"), info->m_categoryName);
for (VRAMSubCategoryType::const_iterator iter = info->m_subcategories.begin(); iter != info->m_subcategories.end(); ++iter)
{
const VRAMSubcategory* subcategoryInfo = iter;
m_output->Write(AZ_CRC("SubcategoryId"), static_cast<unsigned int>(subcategoryInfo->m_subcategoryId));
m_output->Write(AZ_CRC("SubcategoryName"), subcategoryInfo->m_subcategoryName);
}
m_output->EndTag(AZ_CRC("RegisterCategory"));
m_output->EndTag(AZ_CRC("VRAMDriller"));
}
void VRAMDriller::UnregisterAllCategories()
{
AZ_Assert(m_allocations != nullptr, "Allocation records for the VRAMDriller do not exist!");
m_allocations->UnregisterAllCategories(m_output);
}
//=========================================================================
void VRAMDriller::GetCurrentVRAMStats(VRAMAllocationCategory category, VRAMAllocationSubcategory subcategory, AZStd::string& categoryName, AZStd::string& subcategoryName, size_t& numberBytesAllocated, size_t& numberAllocations)
{
// Verify the category exists
const VRAMCategoryType& categoriesMap = m_allocations->GetCategoriesMap();
auto categoryIter = categoriesMap.find(category);
if (categoryIter != categoriesMap.end())
{
// Get the category and subcategory names
const VRAMCategoryInfo& categoryInfo = categoryIter->second;
categoryName = categoryInfo.m_categoryName;
subcategoryName = "INVALID_SUBCATEGORY";
for (int subCat=0; subCat<categoryInfo.m_subcategories.size(); ++subCat)
{
if (categoryInfo.m_subcategories[subCat].m_subcategoryId == subcategory)
{
subcategoryName = categoryInfo.m_subcategories[subCat].m_subcategoryName;
break;
}
}
// Get the basic allocation statistics
VRAMDrillerAllocations::SimpleAllocationStatistics& stats = m_allocations->m_simpleAllocationStatistics[category][subcategory];
numberBytesAllocated = stats.m_allocatedBytes;
numberAllocations = stats.m_numberAllocations;
}
}
//=========================================================================
}// namespace Debug
} // namespace Render
@@ -0,0 +1,78 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_MEMORY_VRAMDRILLER_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_MEMORY_VRAMDRILLER_H 1
#include <AzCore/Driller/Driller.h>
#include <Common/Memory/VRAMDrillerBus.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/Memory/PlatformMemoryInstrumentation.h>
namespace Render
{
namespace Debug
{
/**
* VRAMDriller: A class that tracks VRAM allocations and communicates with the Driller
* to log and generate reports for the allocations.
*/
class VRAMDriller
: public AZ::Debug::Driller
, public VRAMDrillerBus::Handler
{
public:
AZ_CLASS_ALLOCATOR(VRAMDriller, AZ::OSAllocator, 0)
VRAMDriller();
~VRAMDriller();
void CreateAllocationRecords(unsigned char stackRecordLevels, bool isMemoryGuard, bool isMarkUnallocatedMemory);
void DestroyAllocationRecords();
protected:
//////////////////////////////////////////////////////////////////////////
// Driller
virtual const char* GroupName() const;
virtual const char* GetName() const;
virtual const char* GetDescription() const;
virtual void Start(const Param* params = NULL, int numParams = 0);
virtual void Stop();
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// VRAMDrillerBus
virtual void RegisterCategory(VRAMAllocationCategory category, const char* categoryName, const VRAMSubCategoryType& subcategories);
virtual void UnregisterAllCategories();
virtual void RegisterAllocation(void* address, size_t byteSize, const char* allocationName, VRAMAllocationCategory category, VRAMAllocationSubcategory subcategory);
virtual void UnregisterAllocation(void* address);
virtual void GetCurrentVRAMStats(VRAMAllocationCategory category, VRAMAllocationSubcategory subcategory, AZStd::string& categoryName, AZStd::string& subcategoryName, size_t& numberBytesAllocated, size_t& numberAllocations);
//////////////////////////////////////////////////////////////////////////
// Subfunctions of RegisterCategory and RegisterAllocation.
// Split out due to these parts being called in from both of those functions and the Start function
void RegisterCategoryOutput(VRAMAllocationCategory category, const struct VRAMCategoryInfo* info);
void RegisterAllocationOutput(void* address, const struct VRAMAllocationInfo* info);
private:
#if PLATFORM_MEMORY_INSTRUMENTATION_ENABLED
uint16_t m_platformMemoryInstrumentationRootGroupId = 0;
uint16_t m_platformMemoryInstrumentationCategoryIds[Render::Debug::VRAM_CATEGORY_NUMBER_CATEGORIES] = { 0 };
uint16_t m_platformMemoryInstrumentationSubcategoryIds[Render::Debug::VRAM_SUBCATEGORY_NUMBER_SUBCATEGORIES] = { 0 };
#endif
class VRAMDrillerAllocations* m_allocations = nullptr;
};
} // namespace Debug
} // namespace Render
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_MEMORY_VRAMDRILLER_H
#pragma once
@@ -0,0 +1,93 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_MEMORY_VRAMDRILLERBUS_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_MEMORY_VRAMDRILLERBUS_H 1
#include <AzCore/Driller/DrillerBus.h>
namespace Render
{
namespace Debug
{
enum VRAMAllocationCategory
{
VRAM_CATEGORY_TEXTURE,
VRAM_CATEGORY_BUFFER,
VRAM_CATEGORY_MISC,
VRAM_CATEGORY_NUMBER_CATEGORIES,
VRAM_CATEGORY_INVALID = VRAM_CATEGORY_NUMBER_CATEGORIES
};
enum VRAMAllocationSubcategory
{
VRAM_SUBCATEGORY_TEXTURE_RENDERTARGET, // Rendertarget allocations
VRAM_SUBCATEGORY_TEXTURE_TEXTURE, // Texture resources loaded from a file
VRAM_SUBCATEGORY_TEXTURE_DYNAMIC, // Texture created dynamically at runtime (staging or CPU-updated)
VRAM_SUBCATEGORY_BUFFER_VERTEX_BUFFER, // Vertex buffers
VRAM_SUBCATEGORY_BUFFER_INDEX_BUFFER, // Index buffers
VRAM_SUBCATEGORY_BUFFER_CONSTANT_BUFFER, // Constant buffers
VRAM_SUBCATEGORY_BUFFER_OTHER_BUFFER, // Other buffers
VRAM_SUBCATEGORY_MISC_OTHER, // Other
VRAM_SUBCATEGORY_NUMBER_SUBCATEGORIES,
VRAM_SUBCATEGORY_INVALID = VRAM_SUBCATEGORY_NUMBER_SUBCATEGORIES,
};
struct VRAMSubcategory
{
VRAMSubcategory(VRAMAllocationSubcategory subcategoryId, const char* subcategoryName)
: m_subcategoryId(subcategoryId)
, m_subcategoryName(subcategoryName)
{}
VRAMAllocationSubcategory m_subcategoryId = VRAM_SUBCATEGORY_INVALID;
const char* m_subcategoryName = nullptr;
};
typedef AZStd::vector<VRAMSubcategory, AZ::OSStdAllocator> VRAMSubCategoryType;
/**
* VRAM allocations driller message.
*
* We use a driller bus so all messages are sending in exclusive matter no other driller messages
* can be triggered at that moment, so we already preserve the calling order. You can assume
* all access code in the driller framework in guarded. You can manually lock the driller mutex are you
* use by using \ref AZ::Debug::DrillerEBusMutex.
*/
class VRAMDrillerMessages
: public AZ::Debug::DrillerEBusTraits
{
public:
virtual ~VRAMDrillerMessages() {}
// Register a category with a set of subcategories. A category
virtual void RegisterCategory(VRAMAllocationCategory category, const char* categoryName, const VRAMSubCategoryType& subcategories) = 0;
virtual void UnregisterAllCategories() = 0;
// Functions for registering and unregistering individual VRAM allocations
virtual void RegisterAllocation(void* address, size_t byteSize, const char* allocationName, VRAMAllocationCategory category, VRAMAllocationSubcategory subcategories) = 0;
virtual void UnregisterAllocation(void* address) = 0;
// Query the most up-to-date information about a specific category and subcategory.
// Returns the category and subcategory names, the number of currently allocated bytes and the current number of allocations
virtual void GetCurrentVRAMStats(VRAMAllocationCategory category, VRAMAllocationSubcategory subcategory, AZStd::string& categoryName, AZStd::string& subcategoryName, size_t& numberBytesAllocated, size_t& numberAllocations) = 0;
};
typedef AZ::EBus<VRAMDrillerMessages> VRAMDrillerBus;
} // namespace Debug
} // namespace Render
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_MEMORY_VRAMDRILLERBUS_H
#pragma once
@@ -0,0 +1,61 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_OCCLQUERY_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_OCCLQUERY_H
#pragma once
class COcclusionQuery
{
public:
COcclusionQuery()
: m_nVisSamples(~0)
, m_nCheckFrame(0)
, m_nDrawFrame(0)
, m_nOcclusionID(0)
{
}
~COcclusionQuery()
{
Release();
}
void Create();
void Release();
void BeginQuery();
void EndQuery();
uint32 GetVisibleSamples(bool bAsynchronous);
int GetDrawFrame() const
{
return m_nDrawFrame;
}
bool IsReady();
bool IsCreated() const { return m_nOcclusionID != 0; }
private:
int m_nVisSamples;
int m_nCheckFrame;
int m_nDrawFrame;
UINT_PTR m_nOcclusionID; // this will carry a pointer D3DQuery, so it needs to be 64-bit on Windows 64
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_OCCLQUERY_H
@@ -0,0 +1,319 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "PerInstanceConstantBufferPool.h"
#include "DevBuffer.h"
#include "RenderView.h"
#include "RenderPipeline.h"
#include "Include_HLSL_CPP_Shared.h"
#if !defined(NULL_RENDERER)
#include "DriverD3D.h"
#endif
namespace
{
void BuildPerInstanceConstantBuffer(HLSL_PerInstanceConstantBuffer* outBuffer, CRenderObject* renderObject, float realTime, float realTimePrev)
{
AZ::u64 objectFlags = renderObject->m_ObjFlags;
outBuffer->SPIObjWorldMat = renderObject->GetMatrix();
SBending* bending = renderObject->m_data.m_pBending;
if (bending != nullptr)
{
outBuffer->SPIBendInfo = bending->GetShaderConstants(realTime);
}
bending = renderObject->m_data.m_BendingPrev;
if (bending != nullptr)
{
outBuffer->SPIBendInfoPrev = bending->GetShaderConstants(realTimePrev);
}
outBuffer->SPIAmbientOpacity.x = renderObject->m_II.m_AmbColor.r;
outBuffer->SPIAmbientOpacity.y = renderObject->m_II.m_AmbColor.g;
outBuffer->SPIAmbientOpacity.z = renderObject->m_II.m_AmbColor.b;
outBuffer->SPIAmbientOpacity.w = renderObject->m_fAlpha;
const bool bDissolve = (objectFlags & (FOB_DISSOLVE_OUT | FOB_DISSOLVE)) != 0;
const bool bDissolveOut = (objectFlags & FOB_DISSOLVE_OUT) != 0;
outBuffer->SPIDissolveRef.x = bDissolve ? (float)(renderObject->m_DissolveRef) * (1.0f / 255.0f) : 0.0f;
outBuffer->SPIDissolveRef.y = bDissolveOut ? 1.0f : -1.0f;
outBuffer->SPIDissolveRef.z = 0.0f;
outBuffer->SPIDissolveRef.w = 0.0f;
}
}
PerInstanceConstantBufferPool::PerInstanceConstantBufferPool()
: m_CurrentRenderItem{}
, m_UpdateConstantBuffer{}
, m_UpdateIndirectConstantBuffer{}
, m_PooledConstantBuffer{}
#if defined(FEATURE_SPI_INDEXED_CB)
, m_PooledIndirectConstantBuffer{}
#endif
{
}
void PerInstanceConstantBufferPool::Init()
{
for (AZ::u32 i = 0; i < SPI_NUM_STATIC_INST_CB; ++i)
{
m_PooledConstantBuffer[i] = NULL;
}
#if defined(FEATURE_SPI_INDEXED_CB)
for (AZ::u32 i = 0; i < SPI_NUM_INSTS_PER_CB; ++i)
{
m_PooledIndirectConstantBuffer[i] = NULL;
}
#endif
m_UpdateConstantBuffer = nullptr;
m_UpdateIndirectConstantBuffer = nullptr;
}
void PerInstanceConstantBufferPool::Shutdown()
{
for (AZ::u32 i = 0; i < SPI_NUM_STATIC_INST_CB; ++i)
{
SAFE_RELEASE(m_PooledConstantBuffer[i]);
}
#if defined(FEATURE_SPI_INDEXED_CB)
for (AZ::u32 i = 0; i < SPI_NUM_INSTS_PER_CB; ++i)
{
SAFE_RELEASE(m_PooledIndirectConstantBuffer[i]);
}
#endif
SAFE_RELEASE(m_UpdateIndirectConstantBuffer);
SAFE_RELEASE(m_UpdateConstantBuffer);
}
void PerInstanceConstantBufferPool::Update(CRenderView& renderView, float realTime)
{
#if !defined(NULL_RENDERER)
if (m_PooledConstantBuffer[0] == nullptr)
{
auto& bufferManager = gRenDev->m_DevBufMan;
for (AZ::u32 i = 0; i < SPI_NUM_STATIC_INST_CB; ++i)
{
m_PooledConstantBuffer[i] = bufferManager.CreateConstantBuffer(
"PerInstancePool",
SPI_NUM_INSTS_PER_CB * sizeof(HLSL_PerInstanceConstantBuffer),
AzRHI::ConstantBufferUsage::Dynamic,
AzRHI::ConstantBufferFlags::DenyStreaming);
}
#ifdef FEATURE_SPI_INDEXED_CB
for (AZ::u32 i = 0; i < SPI_NUM_INSTS_PER_CB; ++i)
{
AZ::u32 data[4] = { i, 0, 0, 0 };
m_PooledIndirectConstantBuffer[i] = bufferManager.CreateConstantBuffer(
"PerInstanceIndirectPool",
sizeof(AZ::u32) * 4,
AzRHI::ConstantBufferUsage::Static,
AzRHI::ConstantBufferFlags::DenyStreaming);
m_PooledIndirectConstantBuffer[i]->UpdateBuffer(&data, sizeof(AZ::u32) * 4);
}
#endif
m_UpdateConstantBuffer = bufferManager.CreateConstantBuffer(
"PerInstanceUpdate",
SPI_NUM_INSTS_PER_CB * sizeof(HLSL_PerInstanceConstantBuffer),
AzRHI::ConstantBufferUsage::Dynamic,
AzRHI::ConstantBufferFlags::DenyStreaming);
AZ::u32 data[4] = { 0, 0, 0, 0 };
m_UpdateIndirectConstantBuffer = bufferManager.CreateConstantBuffer(
"PerInstanceIndirectUpdate",
sizeof(AZ::u32) * 4,
AzRHI::ConstantBufferUsage::Static,
AzRHI::ConstantBufferFlags::DenyStreaming);
m_UpdateIndirectConstantBuffer->UpdateBuffer(&data, sizeof(AZ::u32) * 4);
}
PROFILE_FRAME(UpdatePerInstanceConstants);
AZ_TRACE_METHOD();
AZ::u32 nextBufferIdx = 0;
AZ::u32 nextInstanceIdx = 0;
AZ::u32 constantBufferIdxLimit = SPI_NUM_STATIC_INST_CB;
void* mappedData = nullptr;
// Assign half of the constant buffer budget per eye when in VR mode
if (gcpRendD3D->GetIStereoRenderer()->IsRenderingToHMD())
{
// For the right eye (rendered second), begin indexing half way into the array
if (gRenDev->m_CurRenderEye == STEREO_EYE_RIGHT)
{
nextBufferIdx = constantBufferIdxLimit / 2;
}
else
{
// For the left eye, just reduce the limit by half
constantBufferIdxLimit /= 2;
}
}
float realTimePrev = realTime - CRenderer::GetElapsedTime();
for (AZ::u32 renderListIdx = EFSLIST_PREPROCESS; renderListIdx < EFSLIST_NUM; renderListIdx++)
{
for (AZ::u32 bAfterWater = 0; bAfterWater < 2; bAfterWater++)
{
auto& renderItems = renderView.GetRenderItems(bAfterWater, renderListIdx);
for (AZ::u32 itemIndex = 0; itemIndex < renderItems.size(); itemIndex++)
{
SRendItem* renderItem = &renderItems[itemIndex];
CRenderObject* renderObject = renderItem->pObj;
if (!renderObject)
{
AZ_Assert(false, "Failed to update static inst buffer pool, index %u - the render object is null", nextBufferIdx);
continue;
}
if (renderObject->m_PerInstanceConstantBufferKey.IsValid())
{
continue;
}
if (nextBufferIdx >= constantBufferIdxLimit)
{
auto* renderer = gEnv->pRenderer;
int nDrawCalls, nShadowGenDrawCalls;
renderer->GetCurrentNumberOfDrawCalls(nDrawCalls, nShadowGenDrawCalls);
int nTotalDrawCalls = nDrawCalls + nShadowGenDrawCalls;
int nTotalInstanced = nTotalDrawCalls + renderer->GetNumGeomInstanceDrawCalls();
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Ran out of static inst buffers -- DP: %04d ShadowGen: %04d Total: %04d Instanced: %04d", nDrawCalls, nShadowGenDrawCalls, nTotalDrawCalls, nTotalInstanced);
return;
}
AzRHI::ConstantBuffer* constantBuffer = m_PooledConstantBuffer[nextBufferIdx];
if (nextInstanceIdx == 0)
{
mappedData = constantBuffer->BeginWrite();
if (!mappedData)
{
AZ_Error("Renderer", false, "Failed to update static inst buffer pool, index %u", nextBufferIdx);
return;
}
}
HLSL_PerInstanceConstantBuffer* outputData = reinterpret_cast<HLSL_PerInstanceConstantBuffer*>(mappedData) + nextInstanceIdx;
BuildPerInstanceConstantBuffer(outputData, renderObject, realTime, realTimePrev);
renderObject->m_PerInstanceConstantBufferKey.m_Id = nextInstanceIdx + (nextBufferIdx * SPI_NUM_INSTS_PER_CB);
#ifdef FEATURE_SPI_INDEXED_CB
renderObject->m_PerInstanceConstantBufferKey.m_IndirectId = nextInstanceIdx;
#endif
nextInstanceIdx++;
if (nextInstanceIdx == SPI_NUM_INSTS_PER_CB)
{
constantBuffer->EndWrite();
nextInstanceIdx = 0;
nextBufferIdx++;
}
}
}
}
if (nextInstanceIdx != 0)
{
m_PooledConstantBuffer[nextBufferIdx]->EndWrite();
}
#endif
}
void PerInstanceConstantBufferPool::SetConstantBuffer(SRendItem* renderItem)
{
CRenderObject* object = renderItem->pObj;
const AZ::u32 directId = object->m_PerInstanceConstantBufferKey.m_Id;
if (directId == 0xffff)
{
return;
}
m_CurrentRenderItem = renderItem;
AZ::u32 bufferIndex = directId / SPI_NUM_INSTS_PER_CB;
AZ::u32 itemIndex = directId % SPI_NUM_INSTS_PER_CB;
AZ::u32 first[1] = { itemIndex * static_cast<AZ::u32>(sizeof(HLSL_PerInstanceConstantBuffer)) };
AZ::u32 count[1] = { static_cast<AZ::u32>(sizeof(HLSL_PerInstanceConstantBuffer)) };
auto& deviceManager = gRenDev->m_DevMan;
#if (SPI_NUM_INSTS_PER_CB == 1)
deviceManager.BindConstantBuffer(eHWSC_Vertex, m_PooledConstantBuffer[bufferIndex], eConstantBufferShaderSlot_SPI);
deviceManager.BindConstantBuffer(eHWSC_Pixel, m_PooledConstantBuffer[bufferIndex], eConstantBufferShaderSlot_SPI);
#elif defined(FEATURE_SPI_INDEXED_CB)
AZ::u32 indirectId = object->m_PerInstanceConstantBufferKey.m_IndirectId;
if (indirectId >= SPI_NUM_INSTS_PER_CB)
{
CryLogAlways("ERROR: SetBuffer - indirect index is invalid");
return;
}
deviceManager.BindConstantBuffer(eHWSC_Vertex, m_PooledConstantBuffer[bufferIndex], eConstantBufferShaderSlot_SPI);
deviceManager.BindConstantBuffer(eHWSC_Pixel, m_PooledConstantBuffer[bufferIndex], eConstantBufferShaderSlot_SPI);
deviceManager.BindConstantBuffer(eHWSC_Vertex, m_PooledIndirectConstantBuffer[indirectId], eConstantBufferShaderSlot_SPIIndex);
deviceManager.BindConstantBuffer(eHWSC_Pixel, m_PooledIndirectConstantBuffer[indirectId], eConstantBufferShaderSlot_SPIIndex);
#else
deviceManager.BindConstantBuffer(eHWSC_Vertex, m_PooledConstantBuffer[bufferIndex], eConstantBufferShaderSlot_SPI, first[0], count[0]);
deviceManager.BindConstantBuffer(eHWSC_Pixel, m_PooledConstantBuffer[bufferIndex], eConstantBufferShaderSlot_SPI, first[0], count[0]);
#endif
}
void PerInstanceConstantBufferPool::UpdateConstantBuffer(ConstantUpdateCB constantUpdateCallback, float realTime)
{
AZ_Assert(m_CurrentRenderItem, "current render item is null");
CRenderObject* renderObject = m_CurrentRenderItem->pObj;
if (!renderObject)
{
AZ_Assert(false, "Failed to update static inst buffer - the current render object is null");
return;
}
float realTimePrev = realTime - CRenderer::GetElapsedTime();
void* mappedData = m_UpdateConstantBuffer->BeginWrite();
if (!mappedData)
{
AZ_Error("Renderer", false, "Failed to update static inst buffer");
return;
}
BuildPerInstanceConstantBuffer(reinterpret_cast<HLSL_PerInstanceConstantBuffer*>(mappedData), renderObject, realTime, realTimePrev);
constantUpdateCallback(mappedData);
m_UpdateConstantBuffer->EndWrite();
auto& devManager = gRenDev->m_DevMan;
devManager.BindConstantBuffer(eHWSC_Vertex, m_UpdateConstantBuffer, eConstantBufferShaderSlot_SPI);
devManager.BindConstantBuffer(eHWSC_Pixel, m_UpdateConstantBuffer, eConstantBufferShaderSlot_SPI);
#if defined(FEATURE_SPI_INDEXED_CB)
devManager.BindConstantBuffer(eHWSC_Vertex, m_UpdateIndirectConstantBuffer, eConstantBufferShaderSlot_SPIIndex);
devManager.BindConstantBuffer(eHWSC_Pixel, m_UpdateIndirectConstantBuffer, eConstantBufferShaderSlot_SPIIndex);
#endif
}
@@ -0,0 +1,81 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include "Defs.h"
#if (defined(WIN32) || defined(APPLE) || defined(LINUX) || defined(USE_FEATURE_SPI_INDEXED_CB_BY_DEFAULT))
#define FEATURE_SPI_INDEXED_CB
#if defined(DONT_USE_SPI_INDEXED_CB)
#undef FEATURE_SPI_INDEXED_CB
#endif
#endif
// DirectX 11.0
#if defined(WIN32) || defined(LINUX) || defined(APPLE) || defined(USE_FEATURE_SPI_INDEXED_CB_BY_DEFAULT)
#define SPI_NUM_STATIC_INST_CB_DEFAULT (2048 * 64)
#ifdef FEATURE_SPI_INDEXED_CB
#define SPI_NUM_INSTS_PER_CB 128 // Must match SPI struct in FXConstantDefs.cfi
#define SPI_NUM_STATIC_INST_CB (SPI_NUM_STATIC_INST_CB_DEFAULT / SPI_NUM_INSTS_PER_CB)
#else
#define SPI_NUM_INSTS_PER_CB 1
#define SPI_NUM_STATIC_INST_CB SPI_NUM_STATIC_INST_CB_DEFAULT
#endif // FEATURE_SPI_INDEXED_CB
// DirectX 11.1 and higher
#else
#define SPI_NUM_INSTS_PER_CB 2048
#define SPI_NUM_STATIC_INST_CB 64
#endif
struct SRendItem;
class IPerInstanceConstantBufferPool
{
virtual void SetConstantBuffer(SRendItem* renderItem) = 0;
};
class PerInstanceConstantBufferPool : public IPerInstanceConstantBufferPool
{
public:
PerInstanceConstantBufferPool();
using ConstantUpdateCB = AZStd::function<void(void*)>;
inline SRendItem* GetCurrentRenderItem()
{
return m_CurrentRenderItem;
}
void Init();
void Shutdown();
void SetConstantBuffer(SRendItem* renderItem);
void UpdateConstantBuffer(ConstantUpdateCB callback, float realTime);
void Update(CRenderView& renderView, float realTime);
private:
SRendItem* m_CurrentRenderItem;
AzRHI::ConstantBuffer* m_PooledConstantBuffer[SPI_NUM_STATIC_INST_CB];
#if defined(FEATURE_SPI_INDEXED_CB)
AzRHI::ConstantBuffer* m_PooledIndirectConstantBuffer[SPI_NUM_INSTS_PER_CB];
#endif
AzRHI::ConstantBuffer* m_UpdateConstantBuffer;
AzRHI::ConstantBuffer* m_UpdateIndirectConstantBuffer;
};
@@ -0,0 +1,869 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "I3DEngine.h"
#include "PostEffects.h"
#include "PostProcessUtils.h"
#include "IPostEffectGroup.h"
#include <AzCore/std/sort.h>
#include "../../../Cry3DEngine/Environment/OceanEnvironmentBus.h"
AZStd::vector< CWaterRipples::SWaterHit, AZ::StdLegacyAllocator > CWaterRipples::s_pWaterHits[RT_COMMAND_BUF_COUNT];
AZStd::vector< CWaterRipples::SWaterHit, AZ::StdLegacyAllocator > CWaterRipples::s_pWaterHitsMGPU;
AZStd::vector< CWaterRipples::SWaterHitRecord, AZ::StdLegacyAllocator > CWaterRipples::m_DebugWaterHits;
Vec3 CWaterRipples::s_CameraPos = Vec3(ZERO);
Vec2 CWaterRipples::s_SimOrigin = Vec2(ZERO);
int CWaterRipples::s_nUpdateMask;
Vec4 CWaterRipples::s_vParams = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
Vec4 CWaterRipples::s_vLookupParams = Vec4(0.0f, 0.0f, 0.0f, 0.0f);
bool CWaterRipples::s_bInitializeSim;
int CSunShafts::Initialize()
{
Release();
m_pOcclQuery = new COcclusionQuery;
m_pOcclQuery->Create();
return true;
}
void CSunShafts::Release()
{
SAFE_DELETE(m_pOcclQuery);
}
void CSunShafts::Reset([[maybe_unused]] bool bOnSpecChange)
{
}
void CSunShafts::OnLostDevice()
{
Release();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CFilterSharpening::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessFilters)
{
return false;
}
if (fabs(m_pAmount->GetParam() - 1.0f) + CRenderer::CV_r_Sharpening + CRenderer::CV_r_ChromaticAberration > 0.09f)
{
return true;
}
return false;
}
void CFilterSharpening::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(1.0f);
m_pType->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CFilterBlurring::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessFilters)
{
return false;
}
if (m_pAmount->GetParam() > 0.09f)
{
return true;
}
return false;
}
void CFilterBlurring::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
m_pType->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CUberGamePostProcess::Preprocess()
{
const float fParamThreshold = 1.0f / 255.0f;
const Vec4 vWhite = Vec4(1.0f, 1.0f, 1.0f, 1.0f);
bool bEnable = false;
bEnable |= m_pColorTint->GetParamVec4() != vWhite;
bEnable |= m_pNoise->GetParam() > fParamThreshold;
bEnable |= m_pSyncWaveAmplitude->GetParam() > fParamThreshold;
bEnable |= m_pGrainAmount->GetParam() > fParamThreshold;
bEnable |= m_pPixelationScale->GetParam() > fParamThreshold;
if (m_pInterlationAmount->GetParam() > fParamThreshold || m_pVSyncAmount->GetParam() > fParamThreshold)
{
m_nCurrPostEffectsMask |= ePE_SyncArtifacts;
bEnable = true;
}
// todo: looks like some game code/flowgraph doing silly stuff - investigate
const float fParamThresholdBackCompatibility = 0.09f;
if (m_pChromaShiftAmount->GetParam() > fParamThresholdBackCompatibility || m_pFilterChromaShiftAmount->GetParam() > fParamThresholdBackCompatibility)
{
m_nCurrPostEffectsMask |= ePE_ChromaShift;
bEnable = true;
}
return bEnable;
}
void CUberGamePostProcess::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_nCurrPostEffectsMask = 0;
m_pVSyncAmount->ResetParam(0.0f);
m_pVSyncFreq->ResetParam(1.0f);
const Vec4 vWhite = Vec4(1.0f, 1.0f, 1.0f, 1.0f);
m_pColorTint->ResetParamVec4(vWhite);
m_pInterlationAmount->ResetParam(0.0f);
m_pInterlationTiling->ResetParam(1.0f);
m_pInterlationRotation->ResetParam(0.0f);
m_pPixelationScale->ResetParam(0.0f);
m_pNoise->ResetParam(0.0f);
m_pSyncWaveFreq->ResetParam(0.0f);
m_pSyncWavePhase->ResetParam(0.0f);
m_pSyncWaveAmplitude->ResetParam(0.0f);
m_pFilterChromaShiftAmount->ResetParam(0.0f);
m_pChromaShiftAmount->ResetParam(0.0f);
m_pGrainAmount->ResetParam(0.0f);
m_pGrainTile->ResetParam(1.0f);
m_pMask->Release();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CColorGrading::Preprocess()
{
// Depreceated: to be removed / replaced by UberPostProcess shader
return false;
}
void CColorGrading::Reset([[maybe_unused]] bool bOnSpecChange)
{
// reset user params
m_pSaturationOffset->ResetParam(0.0f);
m_pPhotoFilterColorOffset->ResetParamVec4(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
m_pPhotoFilterColorDensityOffset->ResetParam(0.0f);
m_pGrainAmountOffset->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CUnderwaterGodRays::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
static ICVar* pVar = iConsole->GetCVar("e_WaterOcean");
//bool bOceanVolumeVisible = (gEnv->p3DEngine->GetOceanRenderFlags() & OCR_OCEANVOLUME_VISIBLE) != 0;
bool godRaysEnabled = OceanToggle::IsActive() ? OceanRequest::GetGodRaysEnabled() : (CRenderer::CV_r_water_godrays == 1);
if (godRaysEnabled && m_pAmount->GetParam() > 0.005f) // && bOceanEnabled && bOceanVolumeVisible)
{
float fWatLevel = SPostEffectsUtils::m_fWaterLevel;
if (fWatLevel - 0.1f > gRenDev->GetViewParameters().vOrigin.z)
{
// check water level
return true;
}
}
return false;
}
void CUnderwaterGodRays::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(1.0f);
m_pQuality->ResetParam(1.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CVolumetricScattering::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_High, eSQ_High);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessGameFx)
{
return false;
}
if (m_pAmount->GetParam() > 0.005f)
{
return true;
}
return false;
}
void CVolumetricScattering::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
m_pType->ResetParam(0.0f);
m_pQuality->ResetParam(1.0f);
m_pTiling->ResetParam(1.0f);
m_pSpeed->ResetParam(1.0f);
m_pColor->ResetParamVec4(Vec4(0.5f, 0.75f, 1.0f, 1.0f));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Game/Hud specific post-effects
////////////////////////////////////////////////////////////////////////////////////////////////////
void CAlienInterference::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
m_pTintColor->ResetParamVec4(Vec4(Vec3(0.85f, 0.95f, 1.25f) * 0.5f, 1.0f));
}
bool CAlienInterference::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessGameFx)
{
return false;
}
if (m_pAmount->GetParam() > 0.09f)
{
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
int CGhostVision::CreateResources()
{
Release();
m_pUserTex1 = CTexture::ForName("EngineAssets/Textures/user_tex1.tif", FT_DONT_STREAM, eTF_Unknown);
m_pUserTex2 = CTexture::ForName("EngineAssets/Textures/user_tex2.tif", FT_DONT_STREAM, eTF_Unknown);
return true;
}
void CGhostVision::Release()
{
SAFE_RELEASE(m_pUserTex1);
SAFE_RELEASE(m_pUserTex2);
}
void CGhostVision::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pUserValue1->ResetParam(0.0f);
m_pUserValue2->ResetParam(0.0f);
m_pUserValue3->ResetParam(0.0f);
m_pTintColor->ResetParamVec4(Vec4(Vec3(0.85f, 0.95f, 1.25f) * 0.5f, 1.0f));
}
bool CGhostVision::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Low, eSQ_Low);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessGameFx)
{
return false;
}
if (m_pUserValue1->GetParam() > 0.09f || m_pUserValue2->GetParam() > 0.09f || m_pUserValue3->GetParam() > 0.09f)
{
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CWaterDroplets::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
const bool bUserActive = m_pAmount->GetParam() > 0.005f;
bool godRaysEnabled = OceanToggle::IsActive() ? OceanRequest::GetGodRaysEnabled() : (CRenderer::CV_r_water_godrays == 1);
if (godRaysEnabled)
{
return bUserActive; // user enabled override
}
return false;
}
void CWaterDroplets::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CWaterFlow::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessGameFx)
{
return false;
}
if (m_pAmount->GetParam() > 0.005f)
{
return true;
}
return false;
}
void CWaterFlow::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CWaterVolume::Preprocess()
{
if (!gRenDev->m_RP.m_eQuality)
{
return false;
}
if (m_pAmount->GetParam() > 0.005f)
{
return true;
}
return false;
}
void CWaterVolume::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CScreenFrost::Preprocess()
{
bool bQualityCheck = CPostEffectsMgr::CheckPostProcessQuality(eRQ_Medium, eSQ_Medium);
if (!bQualityCheck)
{
return false;
}
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessGameFx)
{
return false;
}
if (m_pAmount->GetParam() > 0.09f)
{
return true;
}
return false;
}
void CScreenFrost::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
m_pCenterAmount->ResetParam(1.0f);
m_fRandOffset = 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
int CRainDrops::CreateResources()
{
Release();
//create texture for HitEffect accumulation
m_bFirstFrame = true;
// Already generated ? No need to proceed
if (!m_pDropsLst.empty())
{
return 1;
}
m_pDropsLst.reserve(m_nMaxDropsCount);
for (int p = 0; p < m_nMaxDropsCount; p++)
{
SRainDrop* pDrop = new SRainDrop;
m_pDropsLst.push_back(pDrop);
}
return 1;
}
void CRainDrops::Release()
{
if (m_pDropsLst.empty())
{
return;
}
SRainDropsItor pItor, pItorEnd = m_pDropsLst.end();
for (pItor = m_pDropsLst.begin(); pItor != pItorEnd; ++pItor)
{
SAFE_DELETE((*pItor));
}
m_pDropsLst.clear();
}
void CRainDrops::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_bFirstFrame = true;
m_uCurrentDytex = 0;
m_pAmount->ResetParam(0.0f);
m_pSpawnTimeDistance->ResetParam(0.35f);
m_pSize->ResetParam(5.0f);
m_pSizeVar->ResetParam(2.5f);
m_nAliveDrops = 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void CHudSilhouettes::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pActive->ResetParam(0.0f);
m_pAmount->ResetParam(1.0f);
m_pType->ResetParam(1);
FindIfSilhouettesOptimisedTechAvailable();
}
bool CHudSilhouettes::Preprocess()
{
if ((CRenderer::CV_r_customvisions != 3) || (m_bSilhouettesOptimisedTechAvailable))
{
if (!CRenderer::CV_r_PostProcessGameFx ||
!CRenderer::CV_r_customvisions ||
gRenDev->IsPost3DRendererEnabled())
{
return false;
}
// no need to proceed
float fType = m_pType->GetParam();
uint32 nBatchMask = SRendItem::BatchFlags(EFSLIST_GENERAL, gRenDev->m_RP.m_pRLD) | SRendItem::BatchFlags(EFSLIST_TRANSP, gRenDev->m_RP.m_pRLD);
if ((!(nBatchMask & FB_CUSTOM_RENDER)) && fType == 1.0f)
{
return false;
}
if (m_pAmount->GetParam() > 0.005f)
{
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void CFlashBang::Release()
{
SAFE_DELETE(m_pGhostImage);
}
void CFlashBang::Reset([[maybe_unused]] bool bOnSpecChange)
{
SAFE_DELETE(m_pGhostImage);
m_pActive->ResetParam(0.0f);
m_pTime->ResetParam(2.0f);
m_pDifractionAmount->ResetParam(1.0f);
m_pBlindAmount->ResetParam(0.5f);
m_fBlindAmount = 1.0f;
m_fSpawnTime = 0.0f;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void CSoftAlphaTest::Reset([[maybe_unused]] bool bOnSpecChange)
{
}
bool CSoftAlphaTest::Preprocess()
{
uint32 nBatchMask = SRendItem::BatchFlags(EFSLIST_GENERAL, gRenDev->m_RP.m_pRLD);
return CRenderer::CV_r_SoftAlphaTest != 0 && (nBatchMask & FB_SOFTALPHATEST);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool CImageGhosting::Preprocess()
{
CTexture* pPrevFrame = CTexture::s_ptexPrevFrameScaled;
if (!pPrevFrame)
{
m_bInit = true;
return false;
}
if (m_pAmount->GetParam() > 0.09f)
{
return true;
}
m_bInit = true;
return false;
}
void CImageGhosting::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_bInit = true;
m_pAmount->ResetParam(0.0f);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
int CFilterKillCamera::Initialize()
{
m_techName = "KillCameraFilter";
m_paramName = "psParams";
return 1;
}
bool CFilterKillCamera::Preprocess()
{
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessFilters)
{
return false;
}
if (m_pActive->GetParam() > 0.0f)
{
const int mode = int_round(m_pMode->GetParam());
if (mode != m_lastMode)
{
m_blindTimer = 0.0f;
m_lastMode = mode;
}
return true;
}
m_blindTimer = 0.0f;
return false;
}
void CFilterKillCamera::Reset([[maybe_unused]] bool bOnSpecChange)
{
// Game controls parameters + reset (removed from here due to a race condition).
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void CScreenBlood::Reset([[maybe_unused]] bool bOnSpecChange)
{
m_pAmount->ResetParam(0.0f);
m_pBorder->ResetParamVec4(Vec4(0.0f, 0.0f, 2.0f, 1.0f)); // Border: x=xOffset y=yOffset z=range w=alpha
}
bool CScreenBlood::Preprocess()
{
return (CRenderer::CV_r_PostProcessGameFx && m_pAmount->GetParam() > 0.005f);
}
//////////////////////////////////////////////////////////////////////////
bool CPost3DRenderer::Preprocess()
{
if (IsActive())
{
// Defer turning off post effect for 5 frames - sometimes the flash is left rendering on the screen
// for a frame, if we don't render the post effect for this frame then junk will be rendered into
// the flash. Currently the post effect is disabled at the latest point in menu code, thus this is the
// simplest/safest fix.
m_deferDisableFrameCountDown = 5;
}
else if (m_deferDisableFrameCountDown > 0)
{
m_deferDisableFrameCountDown--;
}
const bool bRender = (m_deferDisableFrameCountDown > 0) ? true : false;
return bRender;
}
void CPost3DRenderer::Reset([[maybe_unused]] bool bOnSpecChange)
{
// Let game code fully control its active status, otherwise in some situations
// the post effect system will get reset between menus and game and thus this
// will get turned off when undesired
}
//////////////////////////////////////////////////////////////////////////
// AZStd visitor class to resolve the effect parameter into the appropriate type
class FetchVisitor
{
public:
void SetEffectParam( CEffectParam* effectParameter )
{
m_effectParam = effectParameter;
}
void operator()(float param)
{
m_effectParam->SetParam(param);
}
void operator()(const Vec4& param)
{
m_effectParam->SetParamVec4(param);
}
void operator()(const AZStd::string& param)
{
m_effectParam->SetParamString(param.c_str());
}
private:
CEffectParam* m_effectParam = nullptr;
};
// Helper function to set a CEffectParam from a group, visitor and parameter name
void SetEffectParamFromVisitor( IPostEffectGroup* group, FetchVisitor& fetchVisitor, const char* paramName, CEffectParam* effectParam /* in/out */ )
{
PostEffectGroupParam* groupParam = group->GetParam(paramName);
fetchVisitor.SetEffectParam( effectParam );
AZStd::visit(fetchVisitor, *groupParam);
}
bool ScreenFader::Preprocess()
{
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_PostProcessGameFx)
{
return false;
}
IPostEffectGroupManager* groupManager = gEnv->p3DEngine->GetPostEffectGroups();
const PostEffectGroupList& toggledGroupList = groupManager->GetGroupsToggledThisFrame();
bool newScreenPassAdded = false;
// Iterate over all of the groups that had their enabled/disabled flag toggled this frame
// If the group already exists in the screenpass list, then that should mean it either needs change its
// state to fade-in (if it was actively fading-out), or it needs to change to fade-out (if it was actively fading in or rendering at full opacity)
// Once a group has faded out completely, then it will be removed from the screenpass list.
for ( auto groupIter = toggledGroupList.begin(); groupIter != toggledGroupList.end(); ++groupIter )
{
IPostEffectGroup* group = (*groupIter);
bool foundGroupInList = false;
for ( ScreenPassList::iterator passIter = m_screenPasses.begin(); passIter != m_screenPasses.end(); ++passIter )
{
ScreenFaderPass* pass = (*passIter);
if ( pass->m_group == group )
{
foundGroupInList = true;
if ( group->GetEnable() )
{
// If the group has changed to enabled, then that means the group was actively fading out before
// Change its state to fade-in, and fade from its existing alpha value.
pass->m_fadingIn = true;
pass->m_fadingOut = false;
pass->m_fadeDirection = 1.0f;
pass->m_fadeDuration = pass->m_fadeInTime;
}
else
{
// If the group has changed to disabled, then that means we were either actively fading in or rendering at full opacity.
// Change its state to fade out and fade from its existing alpha value
pass->m_fadingIn = false;
pass->m_fadingOut = true;
pass->m_fadeDirection = -1.0f;
pass->m_fadeDuration = pass->m_fadeOutTime;
}
break;
}
}
// If the group was not found, then add it to the list
if ( !foundGroupInList )
{
FetchVisitor groupParamVisitor;
SetEffectParamFromVisitor( group, groupParamVisitor, "ScreenFader_Enable", m_enable );
bool fadeIn = m_enable->GetParam() ? true : false;
if ( fadeIn )
{
// The screen fader is different from the other PostEffects in the PostEffectsGroups.
// We do not want the interpolated parameters when enabling another group since we want to render
// multiple stacked screenfaders. Fetch the parameters from the original PostEffectGroup for this
// screen fader pass
ScreenFaderPass* pass = new ScreenFaderPass();
pass->m_group = group;
pass->m_fadingIn = true;
pass->m_fadeDirection = 1.0f;
SetEffectParamFromVisitor( group, groupParamVisitor, "ScreenFader_FadeColor", m_fadeColor );
pass->m_currentColor = m_fadeColor->GetParamVec4();
SetEffectParamFromVisitor( group, groupParamVisitor, "ScreenFader_ScreenCoordinates", m_screenCoordinates );
pass->m_screenCoordinates = m_screenCoordinates->GetParamVec4();
SetEffectParamFromVisitor( group, groupParamVisitor, "ScreenFader_TextureName", m_fadeTextureParam );
pass->m_fadeTexture = static_cast<CParamTexture*>(m_fadeTextureParam)->GetParamTexture();
if (pass->m_fadeTexture)
{
// Since we are manually holding onto a CTexture pointer, make sure we increment the ref count
pass->m_fadeTexture->AddRef();
}
SetEffectParamFromVisitor( group, groupParamVisitor, "ScreenFader_FadeOutTime", m_fadeOutTime );
pass->m_fadeOutTime = m_fadeOutTime->GetParam();
SetEffectParamFromVisitor( group, groupParamVisitor, "ScreenFader_FadeInTime", m_fadeInTime );
pass->m_fadeInTime = m_fadeInTime->GetParam();
pass->m_fadeDuration = pass->m_fadeInTime;
m_screenPasses.push_back( pass );
newScreenPassAdded = true;
}
}
}
// If we added a new ScreenPass, then re-sort our ScreenPasses based on the PostEffectGroup's priorities
if ( newScreenPassAdded )
{
m_screenPasses.sort(SortFaderPasses);
}
// Update all of the screen passes, removing any that have recently faded out from the list.
auto passIter = m_screenPasses.begin();
while ( passIter != m_screenPasses.end() )
{
ScreenFaderPass* pass = (*passIter);
if ( pass->m_fadingOut && pass->m_currentFadeTime <= 0.0f )
{
// We have finished fading out. Now clean up the list and remove the pass.
delete pass;
passIter = m_screenPasses.erase(passIter);
}
else if ( pass->m_fadingIn && (pass->m_currentFadeTime >= pass->m_fadeDuration) )
{
// We have finished fading in. Stay at 100% fade time until fade out is triggered.
pass->m_currentFadeTime = pass->m_fadeDuration;
pass->m_fadingIn = false;
}
++passIter;
}
return m_screenPasses.size() > 0;
}
void ScreenFader::Reset([[maybe_unused]] bool bOnSpecChange)
{
// Do not clear m_screenPasses here, otherwise global and default PostEffectGroups will be removed
}
bool ScreenFader::SortFaderPasses(ScreenFaderPass* pass1, ScreenFaderPass* pass2)
{
return pass1->m_group->GetPriority() < pass2->m_group->GetPriority();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,673 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "PostEffects.h"
#include <I3DEngine.h>
void CParamBool::SetParam(float fParam, [[maybe_unused]] bool bForceValue)
{
const int threadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
CParamBoolThreadSafeData* pThreadSafeData = &m_threadSafeData[threadID];
pThreadSafeData->bParam = (fParam) ? true : false;
pThreadSafeData->bSetThisFrame = true;
}
float CParamBool::GetParam()
{
const int threadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
return static_cast<float>(m_threadSafeData[threadID].bParam);
}
void CParamBool::SyncMainWithRender()
{
CParamBoolThreadSafeData* pFillData = &m_threadSafeData[gRenDev->m_RP.m_nFillThreadID];
const bool bIsMultiThreaded = (gRenDev->m_pRT) ? (gRenDev->m_pRT->IsMultithreaded()) : false;
CParamBoolThreadSafeData* pProcessData = NULL;
if (bIsMultiThreaded)
{
// If value is set on render thread, then this should override main thread value
pProcessData = &m_threadSafeData[gRenDev->m_RP.m_nProcessThreadID];
if (pProcessData->bSetThisFrame)
{
pFillData->bParam = pProcessData->bParam;
}
}
// Reset set value
pFillData->bSetThisFrame = false;
if (bIsMultiThreaded)
{
// Copy fill data into process data
memcpy(pProcessData, pFillData, sizeof(CParamBoolThreadSafeData));
}
}
void CParamInt::SetParam(float fParam, [[maybe_unused]] bool bForceValue)
{
const int threadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
CParamIntThreadSafeData* pThreadSafeData = &m_threadSafeData[threadID];
pThreadSafeData->nParam = static_cast<int>(fParam);
pThreadSafeData->bSetThisFrame = true;
}
float CParamInt::GetParam()
{
const int threadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
return static_cast<float>(m_threadSafeData[threadID].nParam);
}
void CParamInt::SyncMainWithRender()
{
CParamIntThreadSafeData* pFillData = &m_threadSafeData[gRenDev->m_RP.m_nFillThreadID];
const bool bIsMultiThreaded = (gRenDev->m_pRT) ? (gRenDev->m_pRT->IsMultithreaded()) : false;
CParamIntThreadSafeData* pProcessData = NULL;
if (bIsMultiThreaded)
{
// If value is set on render thread, then this should override main thread value
pProcessData = &m_threadSafeData[gRenDev->m_RP.m_nProcessThreadID];
if (pProcessData->bSetThisFrame)
{
pFillData->nParam = pProcessData->nParam;
}
}
// Reset set value
pFillData->bSetThisFrame = false;
if (bIsMultiThreaded)
{
// Copy fill data into process data
memcpy(pProcessData, pFillData, sizeof(CParamIntThreadSafeData));
}
}
void CParamFloat::SetParam(float fParam, [[maybe_unused]] bool bForceValue)
{
const int threadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
CParamFloatThreadSafeData* pThreadSafeData = &m_threadSafeData[threadID];
pThreadSafeData->fParam = fParam;
pThreadSafeData->bSetThisFrame = true;
}
float CParamFloat::GetParam()
{
const int threadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
return m_threadSafeData[threadID].fParam;
}
void CParamFloat::SyncMainWithRender()
{
// The Effect params can be set/get from both threads, accumulate and sync data here
CParamFloatThreadSafeData* pFillData = &m_threadSafeData[gRenDev->m_RP.m_nFillThreadID];
const bool bIsMultiThreaded = (gRenDev->m_pRT) ? (gRenDev->m_pRT->IsMultithreaded()) : false;
CParamFloatThreadSafeData* pProcessData = NULL;
if (bIsMultiThreaded)
{
// If value is set on render thread, then this should override main thread value
pProcessData = &m_threadSafeData[gRenDev->m_RP.m_nProcessThreadID];
if (pProcessData->bSetThisFrame)
{
pFillData->fParam = pProcessData->fParam;
}
}
// Reset set value
pFillData->bSetThisFrame = false;
if (bIsMultiThreaded)
{
// Copy fill data into process data
memcpy(pProcessData, pFillData, sizeof(CParamFloatThreadSafeData));
}
}
void CParamVec4::SetParamVec4(const Vec4& vParam, [[maybe_unused]] bool bForceValue)
{
const int threadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
CParamVec4ThreadSafeData* pThreadSafeData = &m_threadSafeData[threadID];
pThreadSafeData->vParam = vParam;
pThreadSafeData->bSetThisFrame = true;
}
Vec4 CParamVec4::GetParamVec4()
{
const int threadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
return m_threadSafeData[threadID].vParam;
}
void CParamVec4::SyncMainWithRender()
{
// The Effect params can be set/get from both threads, accumulate and sync data here
CParamVec4ThreadSafeData* pFillData = &m_threadSafeData[gRenDev->m_RP.m_nFillThreadID];
const bool bIsMultiThreaded = (gRenDev->m_pRT) ? (gRenDev->m_pRT->IsMultithreaded()) : false;
CParamVec4ThreadSafeData* pProcessData = NULL;
if (bIsMultiThreaded)
{
// If value is set on render thread, then this should override main thread value
pProcessData = &m_threadSafeData[gRenDev->m_RP.m_nProcessThreadID];
if (pProcessData->bSetThisFrame)
{
pFillData->vParam = pProcessData->vParam;
}
}
// Reset set value
pFillData->bSetThisFrame = false;
if (bIsMultiThreaded)
{
// Copy fill data into process data
memcpy(pProcessData, pFillData, sizeof(CParamVec4ThreadSafeData));
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
#if !defined(_RELEASE)
static void SetPostEffectParamF(IConsoleCmdArgs* pArgs)
{
if (pArgs->GetArgCount() < 3)
{
return;
}
bool bForceValue = false;
if (pArgs->GetArgCount() > 3)
{
const int iForceValue = (int)atoi(pArgs->GetArg(3));
if (iForceValue != 0)
{
bForceValue = true;
}
}
const char* szPostEffectParamName = pArgs->GetArg(1);
const float fValue = (float)atof(pArgs->GetArg(2));
I3DEngine* pEngine = gEnv->p3DEngine;
pEngine->SetPostEffectParam(szPostEffectParamName, fValue, bForceValue);
}
static void GetPostEffectParamF(IConsoleCmdArgs* pArgs)
{
if (pArgs->GetArgCount() < 2)
{
return;
}
const char* szPostEffectParamName = pArgs->GetArg(1);
I3DEngine* pEngine = gEnv->p3DEngine;
float fValue = 0.0f;
pEngine->GetPostEffectParam(szPostEffectParamName, fValue);
CryLogAlways("\nPost effect param value: %f", fValue);
}
#endif // !defined(_RELEASE)
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
int CPostEffectsMgr::Init()
{
m_bPostReset = false;
ClearCache();
// Initialize the CRC table
// This is the official polynomial used by CRC-32
// in PKZip, WinZip and Ethernet.
unsigned int ulPolynomial = 0x04c11db7;
// 256 values representing ASCII character codes.
for (int i = 0; i <= 0xFF; i++)
{
m_nCRC32Table[i] = CRC32Reflect(i, 8) << 24;
for (int j = 0; j < 8; j++)
{
m_nCRC32Table[i] = (m_nCRC32Table[i] << 1) ^ (m_nCRC32Table[i] & (1 << 31) ? ulPolynomial : 0);
}
m_nCRC32Table[i] = CRC32Reflect(m_nCRC32Table[i], 32);
} //i
// Register default parameters
AddParamFloat("Global_Brightness", m_pBrightness, 1.0f); // brightness
AddParamFloat("Global_Contrast", m_pContrast, 1.0f); // contrast
AddParamFloat("Global_Saturation", m_pSaturation, 1.0f); // saturation
AddParamFloat("Global_ColorC", m_pColorC, 0.0f); // cyan amount
AddParamFloat("Global_ColorY", m_pColorY, 0.0f); // yellow amount
AddParamFloat("Global_ColorM", m_pColorM, 0.0f); // magenta amount
AddParamFloat("Global_ColorK", m_pColorK, 0.0f); // darkness amount
AddParamFloat("Global_ColorHue", m_pColorHue, 0.0f); // image hue rotation
// User parameters
AddParamFloat("Global_User_Brightness", m_pUserBrightness, 1.0f); // brightness
AddParamFloat("Global_User_Contrast", m_pUserContrast, 1.0f); // contrast
AddParamFloat("Global_User_Saturation", m_pUserSaturation, 1.0f); // saturation
AddParamFloat("Global_User_ColorC", m_pUserColorC, 0.0f); // cyan amount
AddParamFloat("Global_User_ColorY", m_pUserColorY, 0.0f); // yellow amount
AddParamFloat("Global_User_ColorM", m_pUserColorM, 0.0f); // magenta amount
AddParamFloat("Global_User_ColorK", m_pUserColorK, 0.0f); // darkness amount
AddParamFloat("Global_User_ColorHue", m_pUserColorHue, 0.0f); // image hue rotation
AddParamFloat("Global_User_HDRBloom", m_UserHDRBloom, 0.f); // bloom amount
// Register all post processes
AddEffect(CSceneSnow);
AddEffect(CSceneRain);
AddEffect(CSunShafts);
AddEffect(CDepthOfField);
AddEffect(CMotionBlur);
AddEffect(CUnderwaterGodRays);
AddEffect(CVolumetricScattering);
AddEffect(CRainDrops);
AddEffect(CWaterDroplets);
AddEffect(CWaterFlow);
AddEffect(CScreenFrost);
AddEffect(CAlienInterference);
AddEffect(CFlashBang);
AddEffect(CFilterSharpening);
AddEffect(CFilterBlurring);
AddEffect(CColorGrading);
AddEffect(CHudSilhouettes);
AddEffect(CImageGhosting);
AddEffect(CWaterRipples);
AddEffect(CWaterVolume);
AddEffect(CPostAA);
AddEffect(CFilterKillCamera);
AddEffect(CUberGamePostProcess);
AddEffect(CSoftAlphaTest);
AddEffect(CScreenBlood);
AddEffect(CPost3DRenderer);
AddEffect(CGhostVision);
AddEffect(ScreenFader);
// Sort all post effects by ID
std::sort(m_pEffects.begin(), m_pEffects.end(), SortEffectsByID);
// Initialize all post process techniques
std::for_each(m_pEffects.begin(), m_pEffects.end(), SContainerPostEffectInitialize());
m_bCreated = false;
// Initialize parameters
StringEffectMapItor pItor = m_pNameIdMapGen.begin(), pEnd = m_pNameIdMapGen.end();
for (; pItor != pEnd; ++pItor)
{
m_pNameIdMap.insert(KeyEffectMapItor::value_type(GetCRC(pItor->first.c_str()), pItor->second));
}
m_pNameIdMapGen.clear();
#if !defined(_RELEASE)
REGISTER_COMMAND("r_setposteffectparamf", SetPostEffectParamF, VF_CHEAT, "Sets post effect param (float)n"
"Usage: r_setposteffectparamf [posteffectparamname, value, forceValue(OPTIONAL)]\n"
"Example: r_setposteffectparamf HUD3D_FOV 35.0 (Doesn't force value)\n"
"Example: r_setposteffectparamf HUD3D_FOV 35.0 1 (Forces value)\n");
REGISTER_COMMAND("r_getposteffectparamf", GetPostEffectParamF, VF_CHEAT, "Outputs post effect param value (float) to log"
"Usage: r_setposteffectparamf [posteffectparamname]\n"
"Example: r_getposteffectparamf HUD3D_FOV\n");
#endif
// TESTING
static int r_3MonHack;
static float r_3MonHackHUDFOVX;
static float r_3MonHackHUDFOVY;
static float r_3MonHackLeftCGFOffsetX;
static float r_3MonHackRightCGFOffsetX;
REGISTER_CVAR(r_3MonHack, 0, VF_CHEAT | VF_CHEAT_NOCHECK, "Enables 3 monitor hack hud in center");
REGISTER_CVAR(r_3MonHackHUDFOVX, 28, VF_CHEAT | VF_CHEAT_NOCHECK, "3 monitor hack hud in center - X FOV");
REGISTER_CVAR(r_3MonHackHUDFOVY, 60, VF_CHEAT | VF_CHEAT_NOCHECK, "3 monitor hack hud in center - Y FOV");
REGISTER_CVAR(r_3MonHackLeftCGFOffsetX, 0.93f, VF_CHEAT | VF_CHEAT_NOCHECK, "3 monitor hack hud in center - Adds position offset in X direction to all left CGF planes");
REGISTER_CVAR(r_3MonHackRightCGFOffsetX, -0.93f, VF_CHEAT | VF_CHEAT_NOCHECK, "3 monitor hack hud in center - Adds position offset in X direction to all right CGF planes");
return 1;
}
void CPostEffectsMgr::CreateResources()
{
// Initialize all post process techniques
if (!m_bCreated)
{
std::for_each(m_pEffects.begin(), m_pEffects.end(), SContainerPostEffectCreateResources());
}
m_bCreated = true;
}
void CPostEffectsMgr::ReleaseResources()
{
if (m_bCreated)
{
std::for_each(m_pEffects.begin(), m_pEffects.end(), container_object_safe_release());
}
#ifndef _RELEASE
ClearDebugInfo();
#endif
m_bCreated = false;
}
void CPostEffectsMgr::Release()
{
// Free all resources
ClearCache();
std::for_each(m_pNameIdMap.begin(), m_pNameIdMap.end(), SContainerKeyEffectParamDelete());
m_pNameIdMap.clear();
std::for_each(m_pEffects.begin(), m_pEffects.end(), container_object_safe_release());
std::for_each(m_pEffects.begin(), m_pEffects.end(), container_object_safe_delete());
m_pEffects.clear();
m_bCreated = false;
#if !defined(_RELEASE)
IConsole* pConsole = gEnv->pConsole;
if (pConsole)
{
pConsole->RemoveCommand("r_setposteffectparamf");
pConsole->RemoveCommand("r_getposteffectparamf");
}
#endif
}
void CPostEffectsMgr::Reset(bool bOnSpecChange)
{
ClearCache();
m_pBrightness->ResetParam(1.0f);
m_pContrast->ResetParam(1.0f);
m_pSaturation->ResetParam(1.0f);
m_pColorC->ResetParam(0.0f);
m_pColorY->ResetParam(0.0f);
m_pColorM->ResetParam(0.0f);
m_pColorK->ResetParam(0.0f);
m_pColorHue->ResetParam(0.0f);
m_pUserBrightness->ResetParam(1.0f);
m_pUserContrast->ResetParam(1.0f);
m_pUserSaturation->ResetParam(1.0f);
m_pUserColorC->ResetParam(0.0f);
m_pUserColorY->ResetParam(0.0f);
m_pUserColorM->ResetParam(0.0f);
m_pUserColorK->ResetParam(0.0f);
m_pUserColorHue->ResetParam(0.0f);
if (bOnSpecChange)
{
std::for_each(m_pEffects.begin(), m_pEffects.end(), SContainerPostEffectResetOnSpecChange());
}
else
{
std::for_each(m_pEffects.begin(), m_pEffects.end(), SContainerPostEffectReset());
}
}
int32 CPostEffectsMgr::GetEffectID(const char* pEffectName)
{
int32 effectID = ePFX_Invalid;
CPostEffectsMgr* pPostMgr = PostEffectMgr();
for (CPostEffectItor pItor = pPostMgr->GetEffects().begin(), pItorEnd = pPostMgr->GetEffects().end(); pItor != pItorEnd; ++pItor)
{
CPostEffect* pCurrEffect = (*pItor);
if (strcmp(pEffectName, pCurrEffect->GetName()) == 0)
{
effectID = pCurrEffect->GetID();
break;
}
}
return effectID;
}
void CPostEffectsMgr::OnLostDevice()
{
std::for_each(m_pEffects.begin(), m_pEffects.end(), SContainerPostEffectOnLostDevice());
}
void CPostEffectsMgr::OnBeginFrame()
{
std::for_each(m_pEffects.begin(), m_pEffects.end(), SContainerPostEffectOnBeginFrame());
}
void CPostEffectsMgr::SyncMainWithRender()
{
KeyEffectMapItor iter;
for (iter = m_pNameIdMap.begin(); iter != m_pNameIdMap.end(); iter++)
{
iter->second->SyncMainWithRender();
}
}
// Used only when creating the crc table
uint32 CPostEffectsMgr::CRC32Reflect(uint32 ref, char ch)
{
uint32 value = 0;
// Swap bit 0 for bit 7
// bit 1 for bit 6, etc.
for (int i = 1; i < (ch + 1); i++)
{
if (ref & 1)
{
value |= 1 << (ch - i);
}
ref >>= 1;
}
return value;
}
uint32 CPostEffectsMgr::GetCRC(const char* pszName)
{
if (!pszName)
{
assert(false && "CPostEffectsMgr::GetCRC() invalid string passed");
return 0;
}
// Once the lookup table has been filled in by the constructor,
// this function creates all CRCs using only the lookup table.
// Be sure to use unsigned variables, because negative values introduce high bits where zero bits are required.
const char* szPtr = pszName;
uint32 ulCRC = 0xffffffff; // Start out with all bits set high.
unsigned char c;
while (*szPtr)
{
c = *szPtr++;
if (c >= 'a' && c <= 'z')
{
c -= 32; //convert to uppercase
}
ulCRC = (ulCRC >> 8) ^ m_nCRC32Table[(ulCRC & 0xFF) ^ c];
}
// Exclusive OR the result with the beginning value...avoids the % operator
return ulCRC ^ 0xffffffff;
}
CEffectParam* CPostEffectsMgr::GetByName(const char* pszParam)
{
assert(pszParam || "mfGetByName: null FX name");
uint32 nCurrKey = GetCRC(pszParam);
int nThreadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
// cache per-thread
ParamCache* pCache = &m_pParamCache[nThreadID];
// Check cache first
if (nCurrKey == pCache->m_nKey && pCache->m_pParam)
{
if (CRenderer::CV_r_PostProcess == 3)
{
m_pEffectParamsUpdated.insert(StringEffectMapItor::value_type(pszParam, pCache->m_pParam));
}
return pCache->m_pParam;
}
KeyEffectMapItor pItor = m_pNameIdMap.find(nCurrKey);
if (pItor != m_pNameIdMap.end())
{
pCache->m_pParam = pItor->second;
pCache->m_nKey = nCurrKey;
if (CRenderer::CV_r_PostProcess == 3)
{
m_pEffectParamsUpdated.insert(StringEffectMapItor::value_type(pszParam, pCache->m_pParam));
}
return pCache->m_pParam;
}
return 0;
}
float CPostEffectsMgr::GetByNameF(const char* pszParam)
{
CEffectParam* pParam = GetByName(pszParam);
if (pParam)
{
return pParam->GetParam();
}
return 0.0f;
}
Vec4 CPostEffectsMgr::GetByNameVec4(const char* pszParam)
{
CEffectParam* pParam = GetByName(pszParam);
if (pParam)
{
return pParam->GetParamVec4();
}
return Vec4(0, 0, 0, 0);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
int CPostEffectsMgr::SortEffectsByID(const CPostEffect* p1, const CPostEffect* p2)
{
return (p1->GetID() < p2->GetID());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
int CParamTexture::Create(const char* pszFileName)
{
if (!pszFileName || pszFileName[0] == '\0')
{
return 0;
}
const int threadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
CParamTextureThreadSafeData* pThreadSafeData = &m_threadSafeData[threadID];
if (pThreadSafeData->pTexParam)
{
// check if texture is same
if (!azstricmp(pThreadSafeData->pTexParam->GetName(), pszFileName))
{
return 0;
}
// release texture if required
SAFE_RELEASE(pThreadSafeData->pTexParam);
}
pThreadSafeData->pTexParam = CTexture::ForName(pszFileName, FT_DONT_STREAM, eTF_Unknown);
pThreadSafeData->bSetThisFrame = true;
assert(pThreadSafeData->pTexParam || "CParamTexture.Create: texture not found!");
return 1;
}
const char* CParamTexture::GetParamString() const
{
const int threadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
const CTexture* texture = m_threadSafeData[threadID].pTexParam;
return texture ? texture->GetName() : "";
}
void CParamTexture::Release()
{
CParamTextureThreadSafeData* pFillData = &m_threadSafeData[gRenDev->m_RP.m_nFillThreadID];
const bool bIsMultiThreaded = (gRenDev->m_pRT) ? (gRenDev->m_pRT->IsMultithreaded()) : false;
if (bIsMultiThreaded)
{
CParamTextureThreadSafeData* pProcessData = &m_threadSafeData[gRenDev->m_RP.m_nProcessThreadID];
if (pProcessData->pTexParam != pFillData->pTexParam)
{
SAFE_RELEASE(pProcessData->pTexParam);
pProcessData->bSetThisFrame = true;
}
}
SAFE_RELEASE(pFillData->pTexParam);
pFillData->bSetThisFrame = true;
}
void CParamTexture::SyncMainWithRender()
{
CParamTextureThreadSafeData* pFillData = &m_threadSafeData[gRenDev->m_RP.m_nFillThreadID];
const bool bIsMultiThreaded = (gRenDev->m_pRT) ? (gRenDev->m_pRT->IsMultithreaded()) : false;
CParamTextureThreadSafeData* pProcessData = NULL;
if (bIsMultiThreaded)
{
// If value is set on render thread, then this should override main thread value
pProcessData = &m_threadSafeData[gRenDev->m_RP.m_nProcessThreadID];
if (pProcessData->bSetThisFrame)
{
if (pFillData->bSetThisFrame)
{
// If the main thread also set a texture on the same frame (highly unlikely), then release this texture
// 1st before overriding it with the texture set from the render thread
SAFE_RELEASE(pFillData->pTexParam);
}
pFillData->pTexParam = pProcessData->pTexParam;
}
}
// Reset set value
pFillData->bSetThisFrame = false;
if (bIsMultiThreaded)
{
// Copy fill data into process data
memcpy(pProcessData, pFillData, sizeof(CParamTextureThreadSafeData));
}
}
CPostEffectsMgr* PostEffectMgr()
{
return gRenDev->m_pPostProcessMgr;
}
@@ -0,0 +1,736 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef _POSTPROCESS_H_
#define _POSTPROCESS_H_
class CShader;
class CTexture;
// Declare effects ID - this will also be used as rendering sort order
enum EPostEffectID
{
ePFX_Invalid = -1,
ePFX_WaterVolume = 0,
ePFX_WaterRipples,
ePFX_SceneRain,
// Don't change order of post processes before sunshafts (on pc we doing some trickery to avoid redundant stretchrects)
ePFX_SunShafts,
ePFX_eMotionBlur,
ePFX_ColorGrading,
ePFX_eDepthOfField,
ePFX_HUDSilhouettes,
ePFX_eSoftAlphaTest,
ePFX_PostAA,
ePFX_SceneSnow,
ePFX_eUnderwaterGodRays,
ePFX_eVolumetricScattering,
// todo: merge all following into UberGamePostProcess
ePFX_FilterSharpening,
ePFX_FilterBlurring,
ePFX_UberGamePostProcess,
ePFX_eFlashBang,
ePFX_ImageGhosting,
ePFX_eRainDrops,
ePFX_eWaterDroplets,
ePFX_eWaterFlow,
ePFX_eScreenBlood,
ePFX_eScreenFrost,
ePFX_FilterKillCamera,
ePFX_eAlienInterference,
ePFX_eGhostVision,
ePFX_Post3DRenderer,
ePFX_ScreenFader,
ePFX_Max
};
// Base effect parameter class, derive all new from this one
class CEffectParam
{
public:
CEffectParam(){ }
virtual ~CEffectParam()
{
Release();
}
// Should implement where necessary. For example check CParamTexture
virtual void Release() { }
// Set parameters
virtual void SetParam([[maybe_unused]] float fParam, [[maybe_unused]] bool bForceValue = false) {}
virtual void SetParamVec4([[maybe_unused]] const Vec4& pParam, [[maybe_unused]] bool bForceValue = false) {}
virtual void SetParamString([[maybe_unused]] const char* pszParam) {}
virtual void ResetParam(float fParam) { SetParam(fParam, true); }
virtual void ResetParamVec4(const Vec4& pParam) { SetParamVec4(pParam, true); }
// Get parameters
virtual float GetParam() { return 1.0f; }
virtual Vec4 GetParamVec4() { return Vec4(1.0f, 1.0f, 1.0f, 1.0f); }
virtual const char* GetParamString() const { return 0; }
// Sync main thread data with render thread data
virtual void SyncMainWithRender() {}
// Create effect parameter
template <typename ParamT, typename T>
static CEffectParam* Create(const T& pParam, bool bSmoothTransition = true)
{
return new ParamT(pParam, bSmoothTransition);
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Bool type effect param
class CParamBool
: public CEffectParam
{
public:
CParamBool(bool bParam, [[maybe_unused]] bool bSmoothTransition)
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
CParamBoolThreadSafeData* pThreadSafeData = &m_threadSafeData[i];
pThreadSafeData->bParam = bParam;
pThreadSafeData->bSetThisFrame = false;
}
}
virtual void SetParam(float fParam, bool bForceValue);
virtual float GetParam();
virtual void SyncMainWithRender();
private:
struct CParamBoolThreadSafeData
{
bool bParam;
bool bSetThisFrame;
};
CParamBoolThreadSafeData m_threadSafeData[RT_COMMAND_BUF_COUNT];
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Int type effect param
class CParamInt
: public CEffectParam
{
public:
CParamInt(int nParam, [[maybe_unused]] bool bSmoothTransition)
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
CParamIntThreadSafeData* pThreadSafeData = &m_threadSafeData[i];
pThreadSafeData->nParam = nParam;
pThreadSafeData->bSetThisFrame = false;
}
}
virtual void SetParam(float fParam, bool bForceValue);
virtual float GetParam();
virtual void SyncMainWithRender();
private:
struct CParamIntThreadSafeData
{
int nParam;
bool bSetThisFrame;
};
CParamIntThreadSafeData m_threadSafeData[RT_COMMAND_BUF_COUNT];
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Float type effect param
class CParamFloat
: public CEffectParam
{
public:
CParamFloat(float fParam, bool bSmoothTransition)
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
CParamFloatThreadSafeData* pThreadSafeData = &m_threadSafeData[i];
pThreadSafeData->fParam = fParam;
pThreadSafeData->fFrameParamAcc = fParam;
pThreadSafeData->nFrameSetCount = 0;
pThreadSafeData->bValueForced = false;
}
m_fParamDefault = fParam;
m_bSmoothTransition = bSmoothTransition;
}
virtual void SetParam(float fParam, bool bForceValue);
virtual float GetParam();
virtual void SyncMainWithRender();
private:
struct CParamFloatThreadSafeData
{
float fParam;
float fFrameParamAcc;
uint8 nFrameSetCount;
bool bValueForced;
bool bSetThisFrame;
};
CParamFloatThreadSafeData m_threadSafeData[RT_COMMAND_BUF_COUNT];
float m_fParamDefault;
bool m_bSmoothTransition;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Vec4 type effect param
class CParamVec4
: public CEffectParam
{
public:
CParamVec4(const Vec4& vParam, bool bSmoothTransition)
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
CParamVec4ThreadSafeData* pThreadSafeData = &m_threadSafeData[i];
pThreadSafeData->vParam = vParam;
pThreadSafeData->vFrameParamAcc = vParam;
pThreadSafeData->nFrameSetCount = 0;
pThreadSafeData->bValueForced = false;
}
m_vParamDefault = vParam;
m_bSmoothTransition = bSmoothTransition;
}
virtual void SetParamVec4(const Vec4& vParam, bool bForceValue);
virtual Vec4 GetParamVec4();
virtual void SyncMainWithRender();
private:
struct CParamVec4ThreadSafeData
{
Vec4 vParam;
Vec4 vFrameParamAcc;
uint8 nFrameSetCount;
bool bValueForced;
bool bSetThisFrame;
};
CParamVec4ThreadSafeData m_threadSafeData[RT_COMMAND_BUF_COUNT];
Vec4 m_vParamDefault;
bool m_bSmoothTransition;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// CTexture type effect param
class CParamTexture
: public CEffectParam
{
public:
CParamTexture()
{
Reset();
}
CParamTexture([[maybe_unused]] int nInit, [[maybe_unused]] bool bSmoothTransition)
{
Reset();
}
virtual ~CParamTexture()
{
Release();
}
int Create(const char* pszFileName);
virtual void Release();
virtual void SetParamString(const char* pParam)
{
Create(pParam);
}
virtual const char* GetParamString() const;
CTexture* GetParamTexture() const
{
const int threadID = gRenDev->m_pRT ? gRenDev->m_pRT->GetThreadList() : 0;
return m_threadSafeData[threadID].pTexParam;
}
virtual void SyncMainWithRender();
private:
void Reset()
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
CParamTextureThreadSafeData* pThreadSafeData = &m_threadSafeData[i];
pThreadSafeData->pTexParam = NULL;
pThreadSafeData->bSetThisFrame = false;
}
}
struct CParamTextureThreadSafeData
{
CTexture* pTexParam;
bool bSetThisFrame;
};
CParamTextureThreadSafeData m_threadSafeData[RT_COMMAND_BUF_COUNT];
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// Post processing render flags
enum EPostProcessRenderFlag
{
PSP_UPDATE_BACKBUFFER = (1 << 0), // updates back-buffer texture for technique
PSP_REQUIRES_UPDATE = (1 << 1), // required calling update member function
PSP_LAST_ENABLED_POSTPROCESS = (1 << 2), // last enabled post process (used to determine if rendering directly to backbuffer required)
PSP_UPDATE_SCENE_SPECULAR = (1 << 3) // updates/overwrites the scene specular texture (s_ptexSceneSpecular) for use in the current effect
};
// Post effects base structure interface. All techniques derive from this one.
class CPostEffect
{
public:
CPostEffect()
: m_pActive(0)
, /*m_nID(ePFX_DefaultID),*/ m_nRenderFlags(PSP_UPDATE_BACKBUFFER)
{
}
virtual ~CPostEffect()
{
Release();
}
// Initialize post processing technique - device access allowed (queries, ...)
virtual int Initialize() { return 1; }
// Create all the resources for the pp effects which don't require the device (such as textures)
virtual int CreateResources() { return 1; }
// Free resources used
virtual void Release() { }
// Preprocess technique
virtual bool Preprocess() { return IsActive(); }
// Some effects might require updating data/parameters, etc
virtual void Update() { };
// Render technique
virtual void Render() = 0;
// Reset technique state to default
virtual void Reset(bool bOnSpecChange = false) = 0;
// release resources when required
virtual void OnLostDevice() { }
// Add render element/object to post process (use for custom geometry)
virtual void AddRE([[maybe_unused]] const CRendElementBase* pRE, [[maybe_unused]] const SShaderItem* pShaderItem, [[maybe_unused]] CRenderObject* pObj, [[maybe_unused]] const SRenderingPassInfo& passInfo) { }
// release resources when required
virtual void OnBeginFrame() { }
// Get technique render flags
int GetRenderFlags() const
{
return m_nRenderFlags;
}
// Get effect name
virtual const char* GetName() const
{
return "PostEffectDefault";
}
// Is technique active ?
virtual bool IsActive() const
{
float fActive = m_pActive->GetParam();
return (fActive) ? 1 : 0;
}
inline uint8 GetID() const
{
return m_nID;
}
protected:
uint8 m_nRenderFlags;
uint8 m_nID;
CEffectParam* m_pActive;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
typedef std::map<string, CEffectParam*> StringEffectMap;
typedef StringEffectMap::iterator StringEffectMapItor;
typedef std::map<uint32, CEffectParam*> KeyEffectMap;
typedef KeyEffectMap::iterator KeyEffectMapItor;
typedef std::vector< CPostEffect* > CPostEffectVec;
typedef CPostEffectVec::iterator CPostEffectItor;
# ifndef _RELEASE
#define POSTSEFFECTS_DEBUGINFO_TIMEOUT (1.0f)
struct SPostEffectsDebugInfo
{
SPostEffectsDebugInfo(CPostEffect* _pEffect)
: pEffect(_pEffect)
, szParamName(NULL)
, fParamVal(0.0f)
, fTimeOut(POSTSEFFECTS_DEBUGINFO_TIMEOUT){}
SPostEffectsDebugInfo(const string& _szParamName, float val)
: pEffect(NULL)
, szParamName(_szParamName)
, fParamVal(val)
, fTimeOut(POSTSEFFECTS_DEBUGINFO_TIMEOUT){}
CPostEffect* pEffect;
string szParamName;
float fParamVal;
float fTimeOut;
};
typedef std::vector< SPostEffectsDebugInfo > CPostEffectDebugVec;
#endif
class CPostEffectsMgr;
CPostEffectsMgr* PostEffectMgr();
// Post process effects manager
class CPostEffectsMgr
{
public:
CPostEffectsMgr()
: m_nPostBlendEffectsFlags(0)
{
ClearCache();
#ifndef _RELEASE
m_activeEffectsDebug.reserve(16);
m_activeParamsDebug.reserve(32);
#endif
m_bCreated = false;
}
virtual ~CPostEffectsMgr()
{
Release();
}
// Create/Initialize post processing effects
int Init();
void CreateResources();
// Free resources used
void Release();
void ReleaseResources();
// Reset all post effects
void Reset(bool bOnSpecChange = false);
// Start processing effects
void Begin();
// End processing effects
void End();
// release resources when required
void OnLostDevice();
// release resources when required
void OnBeginFrame();
// Sync main thread post effect data with render thread post effect data
void SyncMainWithRender();
// Get techniques list
CPostEffectVec& GetEffects()
{
return m_pEffects;
}
inline bool IsCreated()
{
return m_pEffects.size() != 0;
}
// Get post effect
CPostEffect* GetEffect(EPostEffectID nID)
{
assert(nID < ePFX_Max);
return m_pEffects[ nID ];
}
// Get post effect ID
int32 GetEffectID(const char* pEffectName);
// Get name to id map
KeyEffectMap& GetNameIdMap()
{
return m_pNameIdMap;
}
// Given a string returns corresponding SEffectParam if exists, else returns null
CEffectParam* GetByName(const char* pszParam);
// Given a string returns containing value if exists, else returns 0
float GetByNameF(const char* pszParam);
Vec4 GetByNameVec4(const char* pszParam);
// Register effect
void RegisterEffect(CPostEffect* pEffect)
{
assert(pEffect);
m_pEffects.push_back(pEffect);
}
// Register a parameter
template <typename paramT, typename T>
void RegisterParam(const char* pszName, CEffectParam*& pParam, const T& pParamVal, bool bSmoothTransition = true)
{
pParam = CEffectParam::Create< paramT >(pParamVal, bSmoothTransition);
m_pNameIdMapGen.insert(StringEffectMapItor::value_type(pszName, pParam));
}
// Current enabled post blending effects
uint8 GetPostBlendEffectsFlags()
{
return m_nPostBlendEffectsFlags;
}
// Enabled/disable post blending effects
void SetPostBlendEffectsFlags(uint8 nFlags)
{
m_nPostBlendEffectsFlags = nFlags;
}
friend CPostEffectsMgr* PostEffectMgr();
static bool CheckPostProcessQuality(ERenderQuality nMinRQ, EShaderQuality nMinSQ)
{
if (gRenDev->m_RP.m_eQuality >= nMinRQ && gRenDev->EF_GetShaderQuality(eST_PostProcess) >= nMinSQ)
{
return true;
}
return false;
}
StringEffectMap* GetDebugParamsUsedInFrame()
{
return &m_pEffectParamsUpdated;
}
#ifndef _RELEASE
CPostEffectDebugVec& GetActiveEffectsDebug() { return m_activeEffectsDebug; }
CPostEffectDebugVec& GetActiveEffectsParamsDebug() { return m_activeParamsDebug; }
void ClearDebugInfo()
{
m_activeEffectsDebug.clear();
m_activeParamsDebug.clear();
}
#endif
static int SortEffectsByID(const CPostEffect* p1, const CPostEffect* p2);
// Get techniques list
CPostEffectVec& GetActiveEffects(int threadID)
{
return m_activeEffects[threadID];
}
private:
// Pass a text string to this function and it will return the CRC
uint32 GetCRC(const char* pszName);
// Used only when creating the crc table
uint32 CRC32Reflect(uint32 ref, char ch);
// zero out the cache
void ClearCache()
{
#ifndef _RELEASE
ClearDebugInfo();
#endif
for (int i = 0; i < RT_COMMAND_BUF_COUNT; i++)
{
m_pParamCache[i].m_nKey = 0;
m_pParamCache[i].m_pParam = 0;
}
}
protected:
bool m_bPostReset;
bool m_bCreated;
uint8 m_nPostBlendEffectsFlags;
// Shared parameters
CEffectParam* m_pBrightness, * m_pContrast, * m_pSaturation, * m_pSharpening;
CEffectParam* m_pColorC, * m_pColorY, * m_pColorM, * m_pColorK, * m_pColorHue;
CEffectParam* m_pUserBrightness, * m_pUserContrast, * m_pUserSaturation, * m_pUserSharpening;
CEffectParam* m_pUserColorC, * m_pUserColorY, * m_pUserColorM, * m_pUserColorK, * m_pUserColorHue;
// sorry: quick & dirty solution for c2 shipping - custom type handling for HDR setup in cinematics - make this properly after shipping
CEffectParam* m_UserHDRBloom;
CPostEffectVec m_pEffects;
CPostEffectVec m_activeEffects[RT_COMMAND_BUF_COUNT];
KeyEffectMap m_pNameIdMap;
StringEffectMap m_pNameIdMapGen;
// for debugging purposes only
StringEffectMap m_pEffectParamsUpdated;
#ifndef _RELEASE
CPostEffectDebugVec m_activeEffectsDebug;
CPostEffectDebugVec m_activeParamsDebug;
#endif
uint32 m_nCRC32Table[256]; // Lookup table array
struct ParamCache
{
uint32 m_nKey;
CEffectParam* m_pParam;
} m_pParamCache[RT_COMMAND_BUF_COUNT];
};
//////////////////////////////////////////////////////////////////////////////////////////////////
// Some nice utilities for handling post effects containers
//////////////////////////////////////////////////////////////////////////////////////////////////
#define AddEffect(ef) PostEffectMgr()->RegisterEffect(CryAlignedNew<ef>())
#define AddParamBool(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamBool, bool>((szName), (pParam), val)
#define AddParamInt(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamInt, int>((szName), (pParam), val)
#define AddParamFloat(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamFloat, float>((szName), (pParam), val)
#define AddParamVec4(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamVec4, Vec4>((szName), (pParam), val)
#define AddParamFloatNoTransition(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamFloat, float>((szName), (pParam), val, false)
#define AddParamVec4NoTransition(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamVec4, Vec4>((szName), (pParam), val, false)
#define AddParamTex(szName, pParam, val) PostEffectMgr()->RegisterParam<CParamTexture, int>((szName), (pParam), val)
struct container_object_safe_delete
{
template<typename T>
void operator()(T* pObj) const
{
CryAlignedDelete(pObj);
}
};
struct container_object_safe_release
{
template<typename T>
void operator()(T* pObj) const
{
SAFE_RELEASE(pObj);
}
};
struct SContainerKeyEffectParamDelete
{
void operator()(KeyEffectMap::value_type& pObj)
{
SAFE_DELETE(pObj.second);
}
};
struct SContainerPostEffectInitialize
{
void operator() (CPostEffect* pObj) const
{
if (pObj)
{
pObj->Initialize();
}
}
};
struct SContainerPostEffectCreateResources
{
void operator() (CPostEffect* pObj) const
{
if (pObj)
{
pObj->CreateResources();
}
}
};
struct SContainerPostEffectReset
{
void operator()(CPostEffect* pObj) const
{
if (pObj)
{
pObj->Reset();
}
}
};
struct SContainerPostEffectResetOnSpecChange
{
void operator()(CPostEffect* pObj) const
{
if (pObj)
{
pObj->Reset(true);
}
}
};
struct SContainerPostEffectOnLostDevice
{
void operator() (CPostEffect* pObj) const
{
if (pObj)
{
pObj->OnLostDevice();
}
}
};
struct SContainerPostEffectOnBeginFrame
{
void operator() (CPostEffect* pObj) const
{
if (pObj)
{
pObj->OnBeginFrame();
}
}
};
#endif
@@ -0,0 +1,702 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Post processing common utilities
#include "RenderDll_precompiled.h"
#include "PostProcessUtils.h"
#include "../RendElements/FlareSoftOcclusionQuery.h"
RECT SPostEffectsUtils::m_pScreenRect;
ITimer* SPostEffectsUtils::m_pTimer;
int SPostEffectsUtils::m_iFrameCounter = 0;
SDepthTexture* SPostEffectsUtils::m_pCurDepthSurface;
CShader* SPostEffectsUtils::m_pCurrShader;
int SPostEffectsUtils::m_nColorMatrixFrameID;
float SPostEffectsUtils::m_fWaterLevel;
float SPostEffectsUtils::m_fOverscanBorderAspectRatio = 1.0f;
Matrix44 SPostEffectsUtils::m_pScaleBias = Matrix44(
0.5f, 0, 0, 0,
0, -0.5f, 0, 0,
0, 0, 1.0f, 0,
0.5f, 0.5f, 0, 1.0f);
Vec3 SPostEffectsUtils::m_vRT = Vec3(0, 0, 0);
Vec3 SPostEffectsUtils::m_vLT = Vec3(0, 0, 0);
Vec3 SPostEffectsUtils::m_vLB = Vec3(0, 0, 0);
Vec3 SPostEffectsUtils::m_vRB = Vec3(0, 0, 0);
int SPostEffectsUtils::m_nFrustrumFrameID = 0;
CTexture* SPostEffectsUtils::m_UpscaleTarget = nullptr;
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool SPostEffectsUtils::Create()
{
assert(gRenDev);
#if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
// disregard size changes or texture creation for render scene to texture passes
// or we will introduce texture create/delete thrashing
if (gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_RENDER_SCENE_TO_TEXTURE)
{
return false;
}
#endif // if AZ_RENDER_TO_TEXTURE_GEM_ENABLED
const SViewport& MainVp = gRenDev->m_MainViewport;
const bool bCreatePostAA = CRenderer::CV_r_AntialiasingMode && !CTexture::IsTextureExist(CTexture::s_ptexPrevBackBuffer[0][0]);
//@NOTE: CV_r_watercaustics will be removed when the infinite ocean component feature toggle is removed.
const bool bCreateCaustics = (CRenderer::CV_r_watervolumecaustics && CRenderer::CV_r_watercaustics) && !CTexture::IsTextureExist(CTexture::s_ptexWaterCaustics[0]);
static ICVar* DolbyCvar = gEnv->pConsole->GetCVar("r_HDRDolby");
int DolbyCvarValue = DolbyCvar ? DolbyCvar->GetIVal() : eDVM_Disabled;
ETEX_Format nHDRReducedFormat = gRenDev->UseHalfFloatRenderTargets() ? eTF_R11G11B10F : eTF_R10G10B10A2;
ETEX_Format taaFormat = eTF_R8G8B8A8;
if (CRenderer::CV_r_AntialiasingMode == eAT_TAA)
{
taaFormat = eTF_R16G16B16A16F;
}
bool taaFormatMismatch = (CRenderer::CV_r_AntialiasingMode && CTexture::s_ptexPrevBackBuffer[0][0] && CTexture::s_ptexPrevBackBuffer[0][0]->GetDstFormat() != taaFormat);
if (!CTexture::s_ptexBackBufferScaled[0] || taaFormatMismatch || m_pScreenRect.right != MainVp.nWidth || m_pScreenRect.bottom != MainVp.nHeight || bCreatePostAA || bCreateCaustics)
{
assert(gRenDev);
const int nWidth = gRenDev->GetWidth();
const int nHeight = gRenDev->GetHeight();
// Update viewport info
m_pScreenRect.left = 0;
m_pScreenRect.top = 0;
m_pScreenRect.right = nWidth;
m_pScreenRect.bottom = nHeight;
if (CRenderer::CV_r_AntialiasingMode)
{
CreateRenderTarget("$PrevBackBuffer0", CTexture::s_ptexPrevBackBuffer[0][0], nWidth, nHeight, Clr_Unknown, 1, 0, taaFormat, TO_PREVBACKBUFFERMAP0, FT_DONT_RELEASE | FT_USAGE_ALLOWREADSRGB);
CreateRenderTarget("$PrevBackBuffer1", CTexture::s_ptexPrevBackBuffer[1][0], nWidth, nHeight, Clr_Unknown, 1, 0, taaFormat, TO_PREVBACKBUFFERMAP1, FT_DONT_RELEASE | FT_USAGE_ALLOWREADSRGB);
if (gRenDev->m_bDualStereoSupport)
{
CreateRenderTarget("$PrevBackBuffer0_R", CTexture::s_ptexPrevBackBuffer[0][1], nWidth, nHeight, Clr_Unknown, 1, 0, taaFormat, -1, FT_DONT_RELEASE | FT_USAGE_ALLOWREADSRGB);
CreateRenderTarget("$PrevBackBuffer1_R", CTexture::s_ptexPrevBackBuffer[1][1], nWidth, nHeight, Clr_Unknown, 1, 0, taaFormat, -1, FT_DONT_RELEASE | FT_USAGE_ALLOWREADSRGB);
}
}
else
{
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[0][0]);
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[1][0]);
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[0][1]);
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[1][1]);
}
CreateRenderTarget("$Cached3DHud", CTexture::s_ptexCached3DHud, nWidth, nHeight, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
CreateRenderTarget("$Cached3DHudDownsampled", CTexture::s_ptexCached3DHudScaled, nWidth >> 2, nHeight >> 2, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
// Scaled versions of the scene target
CreateRenderTarget("$BackBufferScaled_d2", CTexture::s_ptexBackBufferScaled[0], nWidth >> 1, nHeight >> 1, Clr_Unknown, 1, 0, eTF_R8G8B8A8, TO_BACKBUFFERSCALED_D2, FT_DONT_RELEASE);
// Ghosting requires data overframes, need to handle for each GPU in MGPU mode
CreateRenderTarget("$PrevFrameScaled", CTexture::s_ptexPrevFrameScaled, nWidth >> 1, nHeight >> 1, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
CreateRenderTarget("$BackBufferScaledTemp_d2", CTexture::s_ptexBackBufferScaledTemp[0], nWidth >> 1, nHeight >> 1, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
CreateRenderTarget("$WaterVolumeRefl", CTexture::s_ptexWaterVolumeRefl[0], nWidth >> 1, nHeight >> 1, Clr_Unknown, 1, true, nHDRReducedFormat, TO_WATERVOLUMEREFLMAP, FT_DONT_RELEASE);
//CTexture::s_ptexWaterVolumeRefl[0]->DisableMgpuSync();
CreateRenderTarget("$WaterVolumeReflPrev", CTexture::s_ptexWaterVolumeRefl[1], nWidth >> 1, nHeight >> 1, Clr_Unknown, 1, true, nHDRReducedFormat, TO_WATERVOLUMEREFLMAPPREV, FT_DONT_RELEASE);
//CTexture::s_ptexWaterVolumeRefl[1]->DisableMgpuSync();
CreateRenderTarget("$BackBufferScaled_d4", CTexture::s_ptexBackBufferScaled[1], nWidth >> 2, nHeight >> 2, Clr_Unknown, 1, 0, eTF_R8G8B8A8, TO_BACKBUFFERSCALED_D4, FT_DONT_RELEASE);
CreateRenderTarget("$BackBufferScaledTemp_d4", CTexture::s_ptexBackBufferScaledTemp[1], nWidth >> 2, nHeight >> 2, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
CreateRenderTarget("$BackBufferScaled_d8", CTexture::s_ptexBackBufferScaled[2], nWidth >> 3, nHeight >> 3, Clr_Unknown, 1, 0, eTF_R8G8B8A8, TO_BACKBUFFERSCALED_D8, FT_DONT_RELEASE);
CreateRenderTarget("$RainDropsAccumRT_0", CTexture::s_ptexRainDropsRT[0], nWidth >> 2, nHeight >> 2, Clr_Unknown, 1, false, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
CreateRenderTarget("$RainDropsAccumRT_1", CTexture::s_ptexRainDropsRT[1], nWidth >> 2, nHeight >> 2, Clr_Unknown, 1, false, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
CreateRenderTarget("$RainSSOcclusion0", CTexture::s_ptexRainSSOcclusion[0], nWidth >> 3, nHeight >> 3, Clr_Unknown, 1, false, eTF_R8G8B8A8);
CreateRenderTarget("$RainSSOcclusion1", CTexture::s_ptexRainSSOcclusion[1], nWidth >> 3, nHeight >> 3, Clr_Unknown, 1, false, eTF_R8G8B8A8);
CreateRenderTarget("$RainOcclusion", CTexture::s_ptexRainOcclusion, RAIN_OCC_MAP_SIZE, RAIN_OCC_MAP_SIZE, Clr_Unknown, false, false, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
// Water phys simulation requires data overframes, need to handle for each GPU in MGPU mode
CreateRenderTarget("$WaterRipplesDDN_0", CTexture::s_ptexWaterRipplesDDN, 256, 256, Clr_Unknown, 1, true, eTF_R8G8B8A8, TO_WATERRIPPLESMAP);
//CTexture::s_ptexWaterRipplesDDN->DisableMgpuSync();
if (gRenDev->UseHalfFloatRenderTargets())
{
CreateRenderTarget("$WaterVolumeDDN", CTexture::s_ptexWaterVolumeDDN, 64, 64, Clr_Unknown, 1, true, eTF_R16G16B16A16F, TO_WATERVOLUMEMAP);
}
else
{
CreateRenderTarget("$WaterVolumeDDN", CTexture::s_ptexWaterVolumeDDN, 64, 64, Clr_Unknown, 1, true, eTF_R8G8B8A8, TO_WATERVOLUMEMAP);
}
//CTexture::s_ptexWaterVolumeDDN->DisableMgpuSync();
if (CRenderer::CV_r_watervolumecaustics && CRenderer::CV_r_watercaustics) //@NOTE: CV_r_watercaustics will be removed when the infinite ocean component feature toggle is removed.
{
const int nCausticRes = clamp_tpl(CRenderer::CV_r_watervolumecausticsresolution, 256, 4096);
CreateRenderTarget("$WaterVolumeCaustics", CTexture::s_ptexWaterCaustics[0], nCausticRes, nCausticRes, Clr_Unknown, 1, false, eTF_R8G8B8A8, TO_WATERVOLUMECAUSTICSMAP);
CreateRenderTarget("$WaterVolumeCausticsTemp", CTexture::s_ptexWaterCaustics[1], nCausticRes, nCausticRes, Clr_Unknown, 1, false, eTF_R8G8B8A8, TO_WATERVOLUMECAUSTICSMAPTEMP);
}
else
{
SAFE_RELEASE(CTexture::s_ptexWaterCaustics[0]);
SAFE_RELEASE(CTexture::s_ptexWaterCaustics[1]);
}
#if defined(VOLUMETRIC_FOG_SHADOWS)
int fogShadowBufDiv = (CRenderer::CV_r_FogShadows == 2) ? 4 : 2;
CreateRenderTarget("$VolFogShadowBuf0", CTexture::s_ptexVolFogShadowBuf[0], nWidth / fogShadowBufDiv, nHeight / fogShadowBufDiv, Clr_Unknown, 1, 0, eTF_R8G8B8A8, TO_VOLFOGSHADOW_BUF);
CreateRenderTarget("$VolFogShadowBuf1", CTexture::s_ptexVolFogShadowBuf[1], nWidth / fogShadowBufDiv, nHeight / fogShadowBufDiv, Clr_Unknown, 1, 0, eTF_R8G8B8A8);
#endif
char str[256];
// TODO: Only create necessary RTs for minimal ring?
for (int i = 0; i < MAX_OCCLUSION_READBACK_TEXTURES; i++)
{
azsprintf(str, "$FlaresOcclusion_%d", i);
CreateRenderTarget(str, CTexture::s_ptexFlaresOcclusionRing[i], CFlareSoftOcclusionQuery::s_nIDColMax, CFlareSoftOcclusionQuery::s_nIDRowMax, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE | FT_STAGE_READBACK);
}
CreateRenderTarget("$FlaresGather", CTexture::s_ptexFlaresGather, CFlareSoftOcclusionQuery::s_nGatherTextureWidth, CFlareSoftOcclusionQuery::s_nGatherTextureHeight, Clr_Unknown, 1, 0, eTF_R8G8B8A8, -1, FT_DONT_RELEASE);
}
return 1;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::Release()
{
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[0][0]);
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[1][0]);
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[0][1]);
SAFE_RELEASE(CTexture::s_ptexPrevBackBuffer[1][1]);
SAFE_RELEASE(CTexture::s_ptexBackBufferScaled[0]);
SAFE_RELEASE(CTexture::s_ptexBackBufferScaled[1]);
SAFE_RELEASE(CTexture::s_ptexBackBufferScaled[2]);
SAFE_RELEASE(CTexture::s_ptexBackBufferScaledTemp[0]);
SAFE_RELEASE(CTexture::s_ptexBackBufferScaledTemp[1]);
SAFE_RELEASE(CTexture::s_ptexWaterVolumeDDN);
SAFE_RELEASE(CTexture::s_ptexWaterVolumeRefl[0]);
SAFE_RELEASE(CTexture::s_ptexWaterVolumeRefl[1]);
SAFE_RELEASE(CTexture::s_ptexWaterCaustics[0]);
SAFE_RELEASE(CTexture::s_ptexWaterCaustics[1]);
SAFE_RELEASE(CTexture::s_ptexCached3DHud);
SAFE_RELEASE(CTexture::s_ptexCached3DHudScaled);
SAFE_RELEASE(CTexture::s_ptexPrevFrameScaled);
SAFE_RELEASE(CTexture::s_ptexWaterRipplesDDN);
SAFE_RELEASE(CTexture::s_ptexRainDropsRT[0]);
SAFE_RELEASE(CTexture::s_ptexRainDropsRT[1]);
SAFE_RELEASE(CTexture::s_ptexRainSSOcclusion[0]);
SAFE_RELEASE(CTexture::s_ptexRainSSOcclusion[1]);
SAFE_RELEASE(CTexture::s_ptexRainOcclusion);
#if defined(VOLUMETRIC_FOG_SHADOWS)
SAFE_RELEASE(CTexture::s_ptexVolFogShadowBuf[0]);
SAFE_RELEASE(CTexture::s_ptexVolFogShadowBuf[1]);
#endif
for (int i = 0; i < MAX_OCCLUSION_READBACK_TEXTURES; i++)
{
SAFE_RELEASE(CTexture::s_ptexFlaresOcclusionRing[i]);
}
SAFE_RELEASE(CTexture::s_ptexFlaresGather);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::GetFullScreenTri(SVF_P3F_C4B_T2F pResult[3], int nTexWidth, int nTexHeight, float z, const RECT * pSrcRegion)
{
if (gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH)
z = 1.0f - z;
pResult[0].xyz = Vec3(-0.0f, -0.0f, z);
pResult[0].color.dcolor = ~0U;
pResult[0].st = Vec2(0, 0);
pResult[1].xyz = Vec3(-0.0f, 2.0f, z);
pResult[1].color.dcolor = ~0U;
pResult[1].st = Vec2(0, 2);
pResult[2].xyz = Vec3(2.0f, -0.0f, z);
pResult[2].color.dcolor = ~0U;
pResult[2].st = Vec2(2, 0);
if (pSrcRegion)
{
const Vec4 vTexCoordsRegion(2.0f*float(pSrcRegion->left) / nTexWidth,
2.0f*float(pSrcRegion->right) / nTexWidth,
2.0f*float(pSrcRegion->top) / nTexHeight,
2.0f*float(pSrcRegion->bottom) / nTexHeight);
pResult[0].st = Vec2(vTexCoordsRegion.x, vTexCoordsRegion.z);
pResult[1].st = Vec2(vTexCoordsRegion.x, vTexCoordsRegion.w);
pResult[2].st = Vec2(vTexCoordsRegion.y, vTexCoordsRegion.z);
}
}
void SPostEffectsUtils::DrawFullScreenTri(int nTexWidth, int nTexHeight, float z, const RECT * pSrcRegion)
{
SVF_P3F_C4B_T2F screenTri[3];
GetFullScreenTri(screenTri, nTexWidth, nTexHeight, z, pSrcRegion);
CVertexBuffer strip(screenTri, eVF_P3F_C4B_T2F);
gRenDev->DrawPrimitivesInternal(&strip, 3, eptTriangleList);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::DrawScreenQuad([[maybe_unused]] int nTexWidth, [[maybe_unused]] int nTexHeight, float x0, float y0, float x1, float y1)
{
const float z = (gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH) ? 1.0f : 0.0f;
Vec3 vv[4];
vv[0] = Vec3(x0, y0, z);
vv[1] = Vec3(x0, y1, z);
vv[2] = Vec3(x1, y0, z);
vv[3] = Vec3(x1, y1, z);
SVF_P3F_C4B_T2F pScreenQuad[] =
{
{ Vec3(0, 0, 0), {
{0}
}, Vec2(0, 0) },
{ Vec3(0, 0, 0), {
{0}
}, Vec2(0, 1) },
{ Vec3(0, 0, 0), {
{0}
}, Vec2(1, 0) },
{ Vec3(0, 0, 0), {
{0}
}, Vec2(1, 1) },
};
pScreenQuad[0].xyz = vv[0];
pScreenQuad[1].xyz = vv[1];
pScreenQuad[2].xyz = vv[2];
pScreenQuad[3].xyz = vv[3];
gRenDev->m_RP.m_PersFlags2 &= ~(RBPF2_COMMIT_PF);
CVertexBuffer strip(pScreenQuad, eVF_P3F_C4B_T2F);
gRenDev->DrawPrimitivesInternal(&strip, 4, eptTriangleStrip);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::DrawQuad([[maybe_unused]] int nTexWidth, [[maybe_unused]] int nTexHeight,
const Vec2& vxA, const Vec2& vxB, const Vec2& vxC, const Vec2& vxD,
const Vec2& uvA, const Vec2& uvB, const Vec2& uvC, const Vec2& uvD)
{
const float z = (gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH) ? 1.0f : 0.0f;
SVF_P3F_C4B_T2F pScreenQuad[4] =
{
{ Vec3(vxA.x, vxA.y, z), {
{0}
}, uvA },
{ Vec3(vxB.x, vxB.y, z), {
{0}
}, uvB },
{ Vec3(vxD.x, vxD.y, z), {
{0}
}, uvD },
{ Vec3(vxC.x, vxC.y, z), {
{0}
}, uvC }
};
gRenDev->m_RP.m_PersFlags2 &= ~(RBPF2_COMMIT_PF);
CVertexBuffer strip(pScreenQuad, eVF_P3F_C4B_T2F);
gRenDev->DrawPrimitivesInternal(&strip, 4, eptTriangleStrip);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::GetFullScreenTriWPOS(SVF_P3F_T2F_T3F pResult[3], int nTexWidth, int nTexHeight, float z, const RECT *pSrcRegion)
{
UpdateFrustumCorners();
if (gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH)
z = 1.0f - z;
pResult[0].p = Vec3(-0.0f, -0.0f, z);
pResult[0].st0 = Vec2(0, 0);
pResult[0].st1 = m_vLT;
pResult[1].p = Vec3(-0.0f, 2.0f, z);
pResult[1].st0 = Vec2(0, 2);
pResult[1].st1 = m_vLB*2.0f - m_vLT;
pResult[2].p = Vec3(2.0f, -0.0f, z);
pResult[2].st0 = Vec2(2, 0);
pResult[2].st1 = m_vRT*2.0f - m_vLT;
if (pSrcRegion)
{
const Vec4 vTexCoordsRegion(2.0f*float(pSrcRegion->left) / nTexWidth,
2.0f*float(pSrcRegion->right) / nTexWidth,
2.0f*float(pSrcRegion->top) / nTexHeight,
2.0f*float(pSrcRegion->bottom) / nTexHeight);
pResult[0].st0 = Vec2(vTexCoordsRegion.x, vTexCoordsRegion.z);
pResult[1].st0 = Vec2(vTexCoordsRegion.x, vTexCoordsRegion.w);
pResult[2].st0 = Vec2(vTexCoordsRegion.y, vTexCoordsRegion.z);
}
}
void SPostEffectsUtils::DrawFullScreenTriWPOS(int nTexWidth, int nTexHeight, float z, const RECT *pSrcRegion)
{
SVF_P3F_T2F_T3F screenTri[3];
GetFullScreenTriWPOS(screenTri, nTexWidth, nTexHeight, z, pSrcRegion);
CVertexBuffer strip(&screenTri[0], eVF_P3F_T2F_T3F);
gRenDev->DrawPrimitivesInternal(&strip, 3, eptTriangleList);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::SetTexture(CTexture* pTex, int nStage, int nFilter, int nClamp, bool bSRGBLookup, DWORD dwBorderColor)
{
if (pTex)
{
STexState TS;
TS.SetFilterMode(nFilter);
TS.SetClampMode(nClamp, nClamp, nClamp);
if (nClamp == TADDR_BORDER)
{
TS.SetBorderColor(dwBorderColor);
}
TS.m_bSRGBLookup = bSRGBLookup;
int nTexState = CTexture::GetTexState(TS);
pTex->Apply(nStage, nTexState);
}
else
{
CTexture::ApplyForID(nStage, 0, -1, -1);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool SPostEffectsUtils::CreateRenderTarget(const char* szTexName, CTexture*& pTex, int nWidth, int nHeight, const ColorF& cClear, [[maybe_unused]] bool bUseAlpha, bool bMipMaps, ETEX_Format eTF, int nCustomID, int nFlags)
{
// check if parameters are valid
if (!nWidth || !nHeight)
{
return 0;
}
uint32 flags = nFlags;
flags |= FT_DONT_STREAM | FT_USAGE_RENDERTARGET | (bMipMaps ? FT_FORCE_MIPS : FT_NOMIPS);
// if texture doesn't exist yet, create it
if (!CTexture::IsTextureExist(pTex))
{
pTex = CTexture::CreateRenderTarget(szTexName, nWidth, nHeight, cClear, eTT_2D, flags, eTF, nCustomID);
}
else
{
pTex->SetFlags(flags);
pTex->SetWidth(nWidth);
pTex->SetHeight(nHeight);
pTex->CreateRenderTarget(eTF, cClear);
}
// Following will mess up don't care resolve/restore actions since Fill() sets textures to be cleared on next draw
#if !defined(CRY_USE_METAL) && !defined(OPENGL_ES)
if (pTex)
{
pTex->Clear();
}
#endif
return CTexture::IsTextureExist(pTex) ? 1 : 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
bool SPostEffectsUtils::ShBeginPass(CShader* pShader, const CCryNameTSCRC& TechName, uint32 nFlags)
{
assert(pShader);
m_pCurrShader = pShader;
uint32 nPasses;
m_pCurrShader->FXSetTechnique(TechName);
m_pCurrShader->FXBegin(&nPasses, nFlags);
return m_pCurrShader->FXBeginPass(0);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::ShEndPass()
{
assert(m_pCurrShader);
m_pCurrShader->FXEndPass();
m_pCurrShader->FXEnd();
m_pCurrShader = 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::ShSetParamVS(const CCryNameR& pParamName, const Vec4& pParam)
{
assert(m_pCurrShader);
m_pCurrShader->FXSetVSFloat(pParamName, &pParam, 1);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::ShSetParamPS(const CCryNameR& pParamName, const Vec4& pParam)
{
assert(m_pCurrShader);
m_pCurrShader->FXSetPSFloat(pParamName, &pParam, 1);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::ClearScreen(float r, float g, float b, float a)
{
static CCryNameTSCRC pTechName("ClearScreen");
ShBeginPass(CShaderMan::s_shPostEffects, pTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
int iTempX, iTempY, iWidth, iHeight;
gRenDev->GetViewport(&iTempX, &iTempY, &iWidth, &iHeight);
Vec4 pClrScrParms = Vec4(r, g, b, a);
static CCryNameR pParamName("clrScrParams");
CShaderMan::s_shPostEffects->FXSetPSFloat(pParamName, &pClrScrParms, 1);
DrawFullScreenTri(iWidth, iHeight);
ShEndPass();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::PrepareGmemDeferredDecals()
{
static CCryNameTSCRC pTechName("PrepareGmemDeferredDecals");
ShBeginPass(CShaderMan::s_shPostEffects, pTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
int iTempX, iTempY, iWidth, iHeight;
gRenDev->GetViewport(&iTempX, &iTempY, &iWidth, &iHeight);
DrawFullScreenTri(iWidth, iHeight);
ShEndPass();
}
void SPostEffectsUtils::ClearGmemGBuffer()
{
static CCryNameTSCRC pTechName("ClearGmemGBuffer");
ShBeginPass(CShaderMan::s_shPostEffects, pTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
int iTempX, iTempY, iWidth, iHeight;
gRenDev->GetViewport(&iTempX, &iTempY, &iWidth, &iHeight);
DrawFullScreenTri(iWidth, iHeight);
ShEndPass();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::UpdateFrustumCorners()
{
auto& renderPipeline = gRenDev->m_RP;
auto& threadInfo = renderPipeline.m_TI[renderPipeline.m_nProcessThreadID];
int nFrameID = threadInfo.m_nFrameID;
if (m_nFrustrumFrameID != nFrameID || CRenderer::CV_r_StereoMode == 1)
{
Vec3 frustumCoords[8];
gRenDev->GetViewParameters().CalcVerts(frustumCoords);
m_vRT = frustumCoords[4] - frustumCoords[0];
m_vLT = frustumCoords[5] - frustumCoords[1];
m_vLB = frustumCoords[6] - frustumCoords[2];
m_vRB = frustumCoords[7] - frustumCoords[3];
// Swap order when mirrored culling enabled
if ((gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_MIRRORCULL))
{
m_vLT = frustumCoords[4] - frustumCoords[0];
m_vRT = frustumCoords[5] - frustumCoords[1];
m_vRB = frustumCoords[6] - frustumCoords[2];
m_vLB = frustumCoords[7] - frustumCoords[3];
}
m_nFrustrumFrameID = nFrameID;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void SPostEffectsUtils::UpdateOverscanBorderAspectRatio()
{
if (gRenDev)
{
const float screenWidth = (float)gRenDev->GetWidth();
const float screenHeight = (float)gRenDev->GetHeight();
Vec2 overscanBorders = Vec2(0.0f, 0.0f);
gRenDev->EF_Query(EFQ_OverscanBorders, overscanBorders);
const float aspectX = (screenWidth * (1.0f - (overscanBorders.y * 2.0f)));
const float aspectY = (screenHeight * (1.0f - (overscanBorders.x * 2.0f)));
m_fOverscanBorderAspectRatio = aspectX / max(aspectY, 0.001f);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
Matrix44& SPostEffectsUtils::GetColorMatrix()
{
CPostEffectsMgr* pPostMgr = PostEffectMgr();
int nFrameID = gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nProcessThreadID].m_nFrameID;
if (m_nColorMatrixFrameID != nFrameID)
{
// Create color transformation matrices
float fBrightness = pPostMgr->GetByNameF("Global_Brightness");
float fContrast = pPostMgr->GetByNameF("Global_Contrast");
float fSaturation = pPostMgr->GetByNameF("Global_Saturation");
float fColorC = pPostMgr->GetByNameF("Global_ColorC");
float fColorM = pPostMgr->GetByNameF("Global_ColorM");
float fColorY = pPostMgr->GetByNameF("Global_ColorY");
float fColorK = pPostMgr->GetByNameF("Global_ColorK");
float fColorHue = pPostMgr->GetByNameF("Global_ColorHue");
float fUserCyan = pPostMgr->GetByNameF("Global_User_ColorC");
fColorC = fUserCyan;
float fUserMagenta = pPostMgr->GetByNameF("Global_User_ColorM");
fColorM = fUserMagenta;
float fUserYellow = pPostMgr->GetByNameF("Global_User_ColorY");
fColorY = fUserYellow;
float fUserLuminance = pPostMgr->GetByNameF("Global_User_ColorK");
fColorK = fUserLuminance;
float fUserHue = pPostMgr->GetByNameF("Global_User_ColorHue");
fColorHue = fUserHue;
float fUserBrightness = pPostMgr->GetByNameF("Global_User_Brightness");
fBrightness = fUserBrightness;
float fUserContrast = pPostMgr->GetByNameF("Global_User_Contrast");
fContrast = fUserContrast;
float fUserSaturation = pPostMgr->GetByNameF("Global_User_Saturation"); // translate to 0
fSaturation = fUserSaturation;
// Saturation matrix
Matrix44 pSaturationMat;
{
float y = 0.3086f, u = 0.6094f, v = 0.0820f, s = clamp_tpl<float>(fSaturation, -1.0f, 100.0f);
float a = (1.0f - s) * y + s;
float b = (1.0f - s) * y;
float c = (1.0f - s) * y;
float d = (1.0f - s) * u;
float e = (1.0f - s) * u + s;
float f = (1.0f - s) * u;
float g = (1.0f - s) * v;
float h = (1.0f - s) * v;
float i = (1.0f - s) * v + s;
pSaturationMat.SetIdentity();
pSaturationMat.SetRow(0, Vec3(a, d, g));
pSaturationMat.SetRow(1, Vec3(b, e, h));
pSaturationMat.SetRow(2, Vec3(c, f, i));
}
// Create Brightness matrix
Matrix44 pBrightMat;
fBrightness = clamp_tpl<float>(fBrightness, 0.0f, 100.0f);
pBrightMat.SetIdentity();
pBrightMat.SetRow(0, Vec3(fBrightness, 0, 0));
pBrightMat.SetRow(1, Vec3(0, fBrightness, 0));
pBrightMat.SetRow(2, Vec3(0, 0, fBrightness));
// Create Contrast matrix
Matrix44 pContrastMat;
{
float c = clamp_tpl<float>(fContrast, -1.0f, 100.0f);
pContrastMat.SetIdentity();
pContrastMat.SetRow(0, Vec3(c, 0, 0));
pContrastMat.SetRow(1, Vec3(0, c, 0));
pContrastMat.SetRow(2, Vec3(0, 0, c));
pContrastMat.SetColumn(3, 0.5f * Vec3(1.0f - c, 1.0f - c, 1.0f - c));
}
// Create CMKY matrix
Matrix44 pCMKYMat;
{
Vec4 pCMYKParams = Vec4(fColorC + fColorK, fColorM + fColorK, fColorY + fColorK, 1.0f);
pCMKYMat.SetIdentity();
pCMKYMat.SetColumn(3, -Vec3(pCMYKParams.x, pCMYKParams.y, pCMYKParams.z));
}
// Create Hue rotation matrix
Matrix44 pHueMat;
{
pHueMat.SetIdentity();
const Vec3 pHueVec = Vec3(0.57735026f, 0.57735026f, 0.57735026f); // (normalized(1,1,1)
pHueMat = Matrix34::CreateRotationAA(fColorHue * PI, pHueVec);
pHueMat.SetColumn(3, Vec3(0, 0, 0));
}
// Compose final color matrix and set fragment program constants
m_pColorMat = pSaturationMat * (pBrightMat * pContrastMat * pCMKYMat * pHueMat);
m_nColorMatrixFrameID = nFrameID;
}
return m_pColorMat;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -0,0 +1,312 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Post processing common utilities
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_POSTPROCESS_POSTPROCESSUTILS_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_POSTPROCESS_POSTPROCESSUTILS_H
#pragma once
struct SDepthTexture;
class CShader;
struct SPostEffectsUtils
{
enum EDepthDownsample
{
eDepthDownsample_None = 0,
eDepthDownsample_Min,
eDepthDownsample_Max,
};
// Create all resources
bool Create();
// Release all used resources
void Release();
// Create a render target
static bool CreateRenderTarget(const char* szTexName, CTexture*& pTex, int iWidth, int iHeight, const ColorF& cClear, bool bUseAlpha, bool bMipMaps = 0, ETEX_Format pTexFormat = eTF_R8G8B8A8, int nCustomID = -1, int nFlags = 0);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Utilities to void some code duplication
////////////////////////////////////////////////////////////////////////////////////////////////////
// Begins render pass utility - for post process stuff only pass 0 assumed to be used
static bool ShBeginPass(CShader* pShader, const CCryNameTSCRC& TechName, uint32 nFlags = 0);
// Ends render pass utility
static void ShEndPass();
// Set vertex shader constant utility
static void ShSetParamVS(const CCryNameR& pParamName, const Vec4& pParam);
// Set pixel shader constant utility
static void ShSetParamPS(const CCryNameR& pParamName, const Vec4& pParam);
static void GetFullScreenTri(SVF_P3F_C4B_T2F pResult[3], int nTexWidth, int nTexHeight, float z = 0, const RECT * pSrcRegion = NULL);
static void GetFullScreenTriWPOS(SVF_P3F_T2F_T3F pResult[3], int nTexWidth, int nTexHeight, float z = 0, const RECT * pSrcRegion = NULL);
// Draws fullscreen aligned triangle
static void DrawFullScreenTri(int nTexWidth, int nTexHeight, float z = 0, const RECT* pSrcRegion = NULL);
static void DrawFullScreenTriWPOS(int nTexWidth, int nTexHeight, float z = 0, const RECT* pSrcRegion = NULL);
// Draws static quad. Uv/size offsets handled via vertex shader.
virtual void DrawQuadFS(CShader* pShader, bool bOutputCamVec, int nWidth, int nHeight, float x0 = 0, float y0 = 0, float x1 = 1, float y1 = 1, float z = 0) = 0;
// Deprecated - use DrawQuadFS. Draws screen aligned quad
static void DrawScreenQuad(int nTexWidth, int nTexHeight, float x0 = 0, float y0 = 0, float x1 = 1, float y1 = 1);
// Deprecated: Only used in GammaCorrection technique - Draws a generic, non-screen-aligned quad
static void DrawQuad(int nTexWidth, int nTexHeight,
const Vec2& vxA, const Vec2& vxB, const Vec2& vxC, const Vec2& vxD,
const Vec2& uvA = Vec2(0, 0), const Vec2& uvB = Vec2(0, 1), const Vec2& uvC = Vec2(1, 1), const Vec2& uvD = Vec2(1, 0));
// Sets a texture
static void SetTexture(CTexture* pTex, int nStage, int nFilter = FILTER_LINEAR, int nClamp = 1, bool bSRGBLookup = false, DWORD dwBorderColor = 0);
// Copy a texture into other texture
virtual void StretchRect(CTexture* pSrc, CTexture*& pDst, bool bClearAlpha = false, bool bDecodeSrcRGBK = false, bool bEncodeDstRGBK = false, bool bBigDownsample = false, EDepthDownsample depthDownsampleMode = eDepthDownsample_None, bool bBindMultisampled = false, const RECT* srcRegion = NULL) = 0;
// Copy screen into texture
virtual void CopyScreenToTexture(CTexture*& pDst, const RECT* pSrcRect) = 0;
// Apply Gaussian blur a texture
virtual void TexBlurGaussian(CTexture* pTex, int nAmount = 1, float fScale = 1.0f, float fDistribution = 5.0f, bool bAlphaOnly = false, CTexture* pMask = 0, bool bSRGB = false, CTexture* pBlurTmp = 0) = 0;
// Clear active render target region
static void ClearScreen(float r, float g, float b, float a);
static void UpdateFrustumCorners();
static void UpdateOverscanBorderAspectRatio();
// Special full screen pass utility functions used by GMEM path /////
static void PrepareGmemDeferredDecals();
static void ClearGmemGBuffer();
/////////////////////////////////////////////////////////////////////
// Log utility
static void Log(const char* pszMsg)
{
if (gRenDev->m_logFileHandle != AZ::IO::InvalidHandle && pszMsg)
{
gRenDev->Logv(SRendItem::m_RecurseLevel[gRenDev->m_pRT->GetThreadList()], pszMsg);
}
}
// Get current color matrix set up by global color parameters
Matrix44& GetColorMatrix();
////////////////////////////////////////////////////////////////////////////////////////////////////
// Math utils
////////////////////////////////////////////////////////////////////////////////////////////////////
// Linear interpolation
static float InterpolateLinear(float p1, float p2, float t)
{
return p1 + (p2 - p1) * t;
};
// Cubic interpolation
static float InterpolateCubic(float p1, float p2, float p3, float p4, float t)
{
float t2 = t * t;
return (((-p1 * 2.0f) + (p2 * 5.0f) - (p3 * 4.0f) + p4) / 6.0f) * t2 * t + (p1 + p3 - (2.0f * p2)) * t2 + (((-4.0f * p1) + p2 + (p3 * 4.0f) - p4) / 6.0f) * t + p2;
};
// Sine interpolation
static float InterpolateSine(float p1, float p2, float p3, float p4, float t)
{
return p2 + (t * (p3 - p2)) + (sinf(t * PI) * ((p2 + p2) - p1 - p3 + (t * (p1 - (p2 + p2 + p2) + (p3 + p3 + p3) - p4))) / 8.0f);
};
// Return normalized random number
static float randf()
{
return cry_random(0.0f, 1.0f);
}
// Return signed normalized random number
static float srandf()
{
return cry_random(-1.0f, 1.0f);
}
// Returns a quasi-random sequence of values; for 2d data (2, 3) is the recommended base
static float HaltonSequence(int index, int primeBase)
{
float invBase = 1.0f / (float)primeBase;
float f = invBase;
float result = 0;
for (int i = index; i > 0; i /= primeBase, f *= invBase)
{
result += f * (float)(i % primeBase);
}
return result;
}
// Returns closest power of 2 size
static int GetClosestPow2Size(int size)
{
float fPower = floorf(logf((float)size) / logf(2.0f));
int nResize = int(powf(2.0f, fPower));
// Clamp
if (nResize >= 512)
{
nResize = 512;
}
return nResize;
}
static void GetViewMatrix(Matrix44A& viewMatrix, bool bCameraSpace = false)
{
viewMatrix = gRenDev->m_ViewMatrix;
if (bCameraSpace)
{
viewMatrix.m30 = 0.0f;
viewMatrix.m31 = 0.0f;
viewMatrix.m32 = 0.0f;
}
}
static void GetTextureRect(CTexture* pTexture, RECT* pRect)
{
pRect->left = 0;
pRect->top = 0;
pRect->right = pTexture->GetWidth();
pRect->bottom = pTexture->GetHeight();
}
static float GaussianDistribution1D(float x, float rho)
{
float g = 1.0f / (rho * sqrtf(2.0f * PI));
g *= expf(-(x * x) / (2.0f * rho * rho));
return g;
}
static float GaussianDistribution2D(float x, float y, float rho)
{
float g = 1.0f / (2.0f * PI * rho * rho);
g *= expf(-(x * x + y * y) / (2 * rho * rho));
return g;
}
static CTexture* GetTemporalCurrentTarget()
{
return CTexture::s_ptexPrevBackBuffer[SPostEffectsUtils::m_iFrameCounter % 2][gRenDev->m_CurRenderEye];
}
static CTexture* GetTemporalHistoryTarget()
{
return CTexture::s_ptexPrevBackBuffer[(SPostEffectsUtils::m_iFrameCounter + 1) % 2][gRenDev->m_CurRenderEye];
}
static CTexture* GetCoCCurrentTarget()
{
return CTexture::s_ptexSceneCoCHistory[SPostEffectsUtils::m_iFrameCounter % 2];
}
static CTexture* GetCoCHistoryTarget()
{
return CTexture::s_ptexSceneCoCHistory[(SPostEffectsUtils::m_iFrameCounter + 1) % 2];
}
static CTexture* AcquireFinalCompositeTarget(bool bNeedHDRTarget)
{
if (bNeedHDRTarget)
{
m_UpscaleTarget = GetTemporalHistoryTarget();
}
else
{
m_UpscaleTarget = CTexture::s_ptexSceneDiffuse;
}
return m_UpscaleTarget;
}
static CTexture* GetFinalCompositeTarget()
{
return m_UpscaleTarget;
}
static CTexture* GetVelocityObjectRT()
{
return CTexture::s_ptexVelocityObjects[gRenDev->m_CurRenderEye];
}
static float GetOverscanBorderAspectRatio()
{
return m_fOverscanBorderAspectRatio;
}
public:
static SDepthTexture* m_pCurDepthSurface;
static RECT m_pScreenRect;
static ITimer* m_pTimer;
static int m_iFrameCounter;
static int m_nColorMatrixFrameID;
static CShader* m_pCurrShader;
Matrix44 m_pView;
Matrix44 m_pProj;
Matrix44 m_pViewProj;
Matrix44 m_pColorMat;
static Matrix44 m_pScaleBias;
static float m_fWaterLevel;
// frustrum corners
static Vec3 m_vRT, m_vLT, m_vLB, m_vRB;
static int m_nFrustrumFrameID;
protected:
SPostEffectsUtils()
{
m_pView.SetIdentity();
m_pProj.SetIdentity();
m_pViewProj.SetIdentity();
m_pColorMat.SetIdentity();
m_pCurDepthSurface = NULL;
m_pScreenRect.left = m_pScreenRect.top = 0;
m_pScreenRect.bottom = m_pScreenRect.right = 0;
m_pTimer = NULL;
m_iFrameCounter = 0;
m_nColorMatrixFrameID = -1;
m_pCurrShader = NULL;
m_fWaterLevel = 0.0;
m_vRT = m_vLT = m_vLB = m_vRB = Vec3(ZERO);
m_nFrustrumFrameID = -1;
}
virtual ~SPostEffectsUtils()
{
}
static float m_fOverscanBorderAspectRatio;
private:
static CTexture* m_UpscaleTarget;
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_POSTPROCESS_POSTPROCESSUTILS_H
@@ -0,0 +1,74 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "AbstractMeshElement.h"
#include "../../RenderDll/XRenderD3D9/DriverD3D.h"
#include "../../../CryCommon/VertexFormats.h"
void AbstractMeshElement::ApplyVert()
{
if (!GetVertCount())
{
return;
}
TempDynVB<SVF_P3F_C4B_T2F>::CreateFillAndBind(GetVertBufData(), GetVertCount(), 0);
gcpRendD3D->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F);
}
void AbstractMeshElement::ApplyIndices()
{
if (!GetIndexCount())
{
return;
}
TempDynIB16::CreateFillAndBind(GetIndexBufData(), GetIndexCount());
}
void AbstractMeshElement::ApplyMesh()
{
ApplyVert();
ApplyIndices();
}
void AbstractMeshElement::DrawMeshTriList()
{
int nVertexBufferCount = GetVertCount();
int nIndexBufferCount = GetIndexCount();
if (nVertexBufferCount <= 0 || nIndexBufferCount <= 0)
{
return;
}
gcpRendD3D->FX_Commit();
gcpRendD3D->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, nVertexBufferCount, 0, nIndexBufferCount);
}
void AbstractMeshElement::DrawMeshWireframe()
{
int nVertexBufferCount = GetVertCount();
int nIndexBufferCount = GetIndexCount();
if (nVertexBufferCount <= 0 || nIndexBufferCount <= 0)
{
return;
}
const int32 nState = gRenDev->m_RP.m_CurState;
gcpRendD3D->FX_SetState(nState | GS_WIREFRAME);
gcpRendD3D->FX_Commit();
gcpRendD3D->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, nVertexBufferCount, 0, nIndexBufferCount);
gcpRendD3D->FX_SetState(nState);
}
@@ -0,0 +1,76 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_ABSTRACTMESHELEMENT_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_ABSTRACTMESHELEMENT_H
#pragma once
struct SVF_P3F_C4B_T2F;
class AbstractMeshElement
{
protected:
std::vector<SVF_P3F_C4B_T2F> m_vertBuf;
std::vector<uint16> m_idxBuf;
bool m_meshDirty;
virtual void ApplyMesh();
virtual void ApplyVert();
virtual void ApplyIndices();
// Render the mesh. Must have ApplyMesh called before this to make sure
// all data are copied and all states are set.
void DrawMeshTriList();
// Render the mesh in wireframe mode. Primarily for debugging. NO FXCommit needed.
// Must have ApplyMesh called before this to make sure
// all data are copied and all states are set.
void DrawMeshWireframe();
// Custom Mesh Generation function.
// Force to generate the mesh only.
// This method doesn't alter the mark-dirty flag
virtual void GenMesh() = 0;
// Validate the internal mesh representation.
// This regenerates the mesh when the related data is modified
virtual void ValidateMesh()
{
if (m_meshDirty)
{
GenMesh();
m_meshDirty = false;
}
}
int GetMeshDataSize() const
{
return m_vertBuf.size() * sizeof(SVF_P3F_C4B_T2F) + m_idxBuf.size() * sizeof(uint16) + sizeof(bool);
}
public:
AbstractMeshElement()
: m_meshDirty(true)
{
}
virtual ~AbstractMeshElement() {}
SVF_P3F_C4B_T2F* GetVertBufData() { return &m_vertBuf[0]; }
int GetVertCount() { return m_vertBuf.size(); }
int GetVertBufSize() { return GetVertCount() * sizeof(SVF_P3F_C4B_T2F); }
uint16* GetIndexBufData() { return &m_idxBuf[0]; }
int GetIndexCount() { return m_idxBuf.size(); }
int GetIndexBufSize() { return GetIndexCount() * sizeof(uint16); }
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_ABSTRACTMESHELEMENT_H
@@ -0,0 +1,141 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "RendElement.h"
#include "I3DEngine.h"
void CREBeam::mfPrepare(bool bCheckOverflow)
{
CRenderer* rd = gRenDev;
if (bCheckOverflow)
{
rd->FX_CheckOverflow(0, 0, this);
}
CRenderObject* obj = rd->m_RP.m_pCurObject;
if (CRenderer::CV_r_beams == 0)
{
rd->m_RP.m_pRE = NULL;
rd->m_RP.m_RendNumIndices = 0;
rd->m_RP.m_RendNumVerts = 0;
}
else
{
const int nThreadID = rd->m_RP.m_nProcessThreadID;
SRenderObjData* pOD = obj->GetObjData();
if (pOD)
{
SRenderLight* pLight = rd->EF_GetDeferredLightByID(pOD->m_nLightID);
if (pLight && pLight->m_Flags & DLF_PROJECT)
{
rd->m_RP.m_pRE = this;
rd->m_RP.m_RendNumIndices = 0;
rd->m_RP.m_RendNumVerts = 0;
}
else
{
rd->m_RP.m_pRE = NULL;
rd->m_RP.m_RendNumIndices = 0;
rd->m_RP.m_RendNumVerts = 0;
}
}
else
{
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_WARNING, "Render object data is null. This may affect lighting.");
}
}
}
bool CREBeam::mfCompile([[maybe_unused]] CParserBin& Parser, [[maybe_unused]] SParserFrame& Frame)
{
return true;
}
void CREBeam::SetupGeometry(SVF_P3F_C4B_T2F* pVertices, uint16* pIndices, float fAngleCoeff, float fNear, float fFar)
{
const int nNumSides = BEAM_RE_CONE_SIDES;
Vec2 rotations[nNumSides];
float fIncrement = 1.0f / (float)nNumSides;
float fAngle = 0.0f;
for (uint32 i = 0; i < nNumSides; i++)
{
sincos_tpl(fAngle, &rotations[i].x, &rotations[i].y);
fAngle += fIncrement * gf_PI2;
}
float fScaleNear = fNear * fAngleCoeff;
float fScaleFar = fFar * fAngleCoeff;
UCol cBlack, cWhite;
cBlack.dcolor = 0;
cWhite.dcolor = 0xFFFFFFFF;
for (uint32 i = 0; i < nNumSides; i++) //Near Verts
{
pVertices[ i ].xyz = Vec3(fNear, rotations[i].x * fScaleNear, rotations[i].y * fScaleNear);
pVertices[ i ].color = cWhite;
pVertices[ i ].st = Vec2(rotations[i].x, rotations[i].y);
}
for (uint32 i = 0; i < (nNumSides); i++) // Far verts
{
pVertices[ i + nNumSides].xyz = Vec3(fFar, rotations[i].x * fScaleFar, rotations[i].y * fScaleFar);
pVertices[ i + nNumSides].color = cWhite;
pVertices[ i + nNumSides].st = Vec2(rotations[i].x, rotations[i].y);
}
uint32 nNearCapVert = nNumSides * 2;
uint32 nFarCapVert = nNumSides * 2 + 1;
//near cap vert
pVertices[ nNearCapVert ].xyz = Vec3(fNear, 0.0f, 0.0f);
pVertices[ nNearCapVert ].color = cBlack;
pVertices[ nNearCapVert ].st = Vec2(0, 0);
//far cap vert
pVertices[ nFarCapVert ].xyz = Vec3(fFar, 0.0f, 0.0f);
pVertices[ nFarCapVert ].color = cWhite;
pVertices[ nFarCapVert ].st = Vec2(0, 0);
for (uint32 i = 0; i < nNumSides; i++)
{
uint32 idx = i * 6;
pIndices[idx] = (i) % (nNumSides);
pIndices[idx + 1] = (i) % (nNumSides) + nNumSides;
pIndices[idx + 2] = (i + 1) % (nNumSides) + nNumSides;
pIndices[idx + 3] = (i + 1) % (nNumSides) + nNumSides;
pIndices[idx + 4] = (i + 1) % (nNumSides);
pIndices[idx + 5] = (i) % (nNumSides);
}
for (uint32 i = 0; i < nNumSides; i++) // cap plane near
{
uint32 idx = ((nNumSides) * 6) + (i * 3);
pIndices[idx] = nNearCapVert;
pIndices[idx + 1] = (i) % (nNumSides);
pIndices[idx + 2] = (i + 1) % (nNumSides);
}
for (uint32 i = 0; i < nNumSides; i++) // cap plane far
{
uint32 idx = ((nNumSides) * 9) + (i * 3);
pIndices[idx] = nFarCapVert;
pIndices[idx + 1] = (i + 1) % (nNumSides) + nNumSides;
pIndices[idx + 2] = (i) % (nNumSides) + nNumSides;
}
}
@@ -0,0 +1,76 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef __CREBEAM_H__
#define __CREBEAM_H__
#define BEAM_RE_CONE_SIDES 32
//=============================================================
class CREBeam
: public CRendElementBase
{
private:
CCryNameR m_eyePosInWSName;
CCryNameR m_projMatrixName;
CCryNameR m_invProjMatrixName;
CCryNameR m_shadowCoordsName;
CCryNameR m_lightParamsName;
CCryNameR m_sphereParamsName;
CCryNameR m_coneParamsName;
CCryNameR m_lightPosName;
CCryNameR m_miscOffsetsName;
CCryNameR m_sampleOffsetsName;
CCryNameR m_lightDiffuseName;
CCryNameR m_screenScaleName;
public:
CREBeam()
{
mfSetType(eDATA_Beam);
m_eyePosInWSName = CCryNameR("eyePosInWS");
m_projMatrixName = CCryNameR("projMatrix");
m_invProjMatrixName = CCryNameR("invProjMatrix");
m_shadowCoordsName = CCryNameR("shadowCoords");
m_lightParamsName = CCryNameR("lightParams");
m_sphereParamsName = CCryNameR("sphereParams");
m_coneParamsName = CCryNameR("coneParams");
m_lightPosName = CCryNameR("lightPos");
m_miscOffsetsName = CCryNameR("MiscParams");
m_sampleOffsetsName = CCryNameR("SampleOffsets");
m_lightDiffuseName = CCryNameR("lightDiffuse");
m_screenScaleName = CCryNameR("g_ScreenScale");
}
virtual ~CREBeam()
{
}
virtual void mfPrepare(bool bCheckOverflow);
virtual bool mfCompile(CParserBin& Parser, SParserFrame& Frame);
virtual bool mfDraw(CShader* ef, SShaderPass* sl);
virtual void mfExport([[maybe_unused]] struct SShaderSerializeContext& SC) {};
virtual void mfImport([[maybe_unused]] struct SShaderSerializeContext& SC, [[maybe_unused]] uint32& offset) {};
void SetupGeometry(SVF_P3F_C4B_T2F* pVertices, uint16* pIndices, float fAngleCoeff, float fNear, float fFar);
virtual void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
}
};
#endif // __CREBEAM_H__
@@ -0,0 +1,132 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : implementation of 3D Client polygons RE.
#include "RenderDll_precompiled.h"
//===============================================================
TArray<CREClientPoly*> CREClientPoly::m_PolysStorage[RT_COMMAND_BUF_COUNT][MAX_REND_RECURSION_LEVELS];
CRendElementBase* CREClientPoly::mfCopyConstruct(void)
{
CREClientPoly* cp = new CREClientPoly;
*cp = *this;
return cp;
}
void CREClientPoly::mfPrepare(bool bCheckOverflow)
{
CRenderer* rd = gRenDev;
CShader* ef = rd->m_RP.m_pShader;
int i, n;
rd->m_RP.m_CurVFormat = eVF_P3F_C4B_T2F;
rd->FX_StartMerging();
CREClientPoly::mRS.NumRendPolys++;
int savev = rd->m_RP.m_RendNumVerts;
int savei = rd->m_RP.m_RendNumIndices;
int nThreadID = rd->m_RP.m_nProcessThreadID;
int nVerts = 0;
int nInds = 0;
if (bCheckOverflow)
{
rd->FX_CheckOverflow(m_sNumVerts, m_sNumIndices, this, &nVerts, &nInds);
}
if (m_nOffsInd >= (int)(rd->m_RP.m_SysIndexPool[nThreadID].size()))
{
assert(0);
return;
}
uint16* pSrcInds = &rd->m_RP.m_SysIndexPool[nThreadID][m_nOffsInd];
n = rd->m_RP.m_RendNumVerts;
uint16* dinds = &rd->m_RP.m_RendIndices[gRenDev->m_RP.m_RendNumIndices];
for (i = 0; i < nInds; i++, dinds++, pSrcInds++)
{
*dinds = *pSrcInds + n;
}
rd->m_RP.m_RendNumIndices += i;
UVertStreamPtr ptr = rd->m_RP.m_NextStreamPtr;
byte* OffsTC, * OffsColor;
SVF_P3F_C4B_T2F* pSrc = (SVF_P3F_C4B_T2F*)&rd->m_RP.m_SysVertexPool[nThreadID][m_nOffsVert];
OffsTC = rd->m_RP.m_StreamOffsetTC + ptr.PtrB;
OffsColor = rd->m_RP.m_StreamOffsetColor + ptr.PtrB;
for (i = 0; i < nVerts; i++, ptr.PtrB += rd->m_RP.m_StreamStride, OffsTC += rd->m_RP.m_StreamStride, OffsColor += rd->m_RP.m_StreamStride)
{
*(float*)(ptr.PtrB + 0) = pSrc[i].xyz[0];
*(float*)(ptr.PtrB + 4) = pSrc[i].xyz[1];
*(float*)(ptr.PtrB + 8) = pSrc[i].xyz[2];
*(float*)(OffsTC) = pSrc[i].st[0];
*(float*)(OffsTC + 4) = pSrc[i].st[1];
*(uint32*)OffsColor = pSrc[i].color.dcolor;
}
rd->m_RP.m_NextStreamPtr = ptr;
if (m_nOffsTang >= 0)
{
UVertStreamPtr ptrTang = rd->m_RP.m_NextStreamPtrTang;
SPipTangents* pTangents = (SPipTangents*)&rd->m_RP.m_SysVertexPool[nThreadID][m_nOffsTang];
for (i = 0; i < nVerts; i++, ptrTang.PtrB += sizeof(SPipTangents))
{
*(SPipTangents*)(ptrTang.PtrB) = pTangents[i];
}
rd->m_RP.m_NextStreamPtrTang = ptrTang;
}
rd->m_RP.m_RendNumVerts += nVerts;
CREClientPoly::mRS.NumVerts += rd->m_RP.m_RendNumVerts - savev;
CREClientPoly::mRS.NumIndices += rd->m_RP.m_RendNumIndices - savei;
}
//=======================================================================
SClientPolyStat CREClientPoly::mRS;
void CREClientPoly::mfPrintStat()
{
/* char str[1024];
*gpCurPrX = 4;
sprintf(str, "Num Indices: %i\n", mRS.NumIndices);
gRenDev->mfPrintString (str, PS_TRANSPARENT | PS_UP);
*gpCurPrX = 4;
sprintf(str, "Num Verts: %i\n", mRS.NumVerts);
gRenDev->mfPrintString (str, PS_TRANSPARENT | PS_UP);
*gpCurPrX = 4;
sprintf(str, "Num Render Client Polys: %i\n", mRS.NumRendPolys);
gRenDev->mfPrintString (str, PS_TRANSPARENT | PS_UP);
*gpCurPrX = 4;
sprintf(str, "Num Occluded Client Polys: %i\n", mRS.NumOccPolys);
gRenDev->mfPrintString (str, PS_TRANSPARENT | PS_UP);
*gpCurPrX = 4;
gRenDev->mfPrintString ("\nClient Polygons status info:\n", PS_TRANSPARENT | PS_UP);*/
}
@@ -0,0 +1,72 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef __CRECLIENTPOLY_H__
#define __CRECLIENTPOLY_H__
//=============================================================
struct SClientPolyStat
{
int NumOccPolys;
int NumRendPolys;
int NumVerts;
int NumIndices;
};
class CREClientPoly
: public CRendElementBase
{
public:
enum eFlags
{
efAfterWater = 1 << 0,
efShadowGen = 1 << 1,
};
SShaderItem m_Shader;
CRenderObject* m_pObject;
short m_sNumVerts;
short m_sNumIndices;
byte m_nCPFlags;
int m_nOffsVert;
int m_nOffsTang;
int m_nOffsInd;
SRendItemSorter rendItemSorter;
static SClientPolyStat mRS;
static void mfPrintStat();
public:
CREClientPoly()
{
mfSetType(eDATA_ClientPoly);
m_sNumVerts = 0;
m_nCPFlags = 0;
mfUpdateFlags(FCEF_TRANSFORM);
}
virtual ~CREClientPoly() {};
virtual void mfPrepare(bool bCheckOverflow);
virtual CRendElementBase* mfCopyConstruct(void);
virtual void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
pSizer->AddObject(m_PolysStorage);
}
static TArray<CREClientPoly*> m_PolysStorage[RT_COMMAND_BUF_COUNT][MAX_REND_RECURSION_LEVELS];
};
#endif // __CRECLIENTPOLY2D_H__
@@ -0,0 +1,364 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "RendElement.h"
#include "CRECloud.h"
#include "../Textures/TextureManager.h"
#include <I3DEngine.h>
uint32 CRECloud::m_siShadeResolution = 32;
float CRECloud::m_sfAlbedo = 0.9f;
float CRECloud::m_sfExtinction = 80.0f;
float CRECloud::m_sfTransparency = exp(-m_sfExtinction);
float CRECloud::m_sfScatterFactor = m_sfAlbedo * m_sfExtinction * (1.0f / (4.0f * (float)M_PI));
float CRECloud::m_sfSortAngleErrorTolerance = 0.8f;
float CRECloud::m_sfSortSquareDistanceTolerance = 100.0f;
void CRECloud::SortParticles(const Vec3& vViewDir, const Vec3& vSortPoint, ESortDirection eDir)
{
Vec3 partPos;
for (uint32 i = 0; i < m_particles.size(); ++i)
{
partPos = m_particles[i]->GetPosition();
partPos -= vSortPoint;
m_particles[i]->SetSquareSortDistance(partPos * vViewDir);
}
switch (eDir)
{
case eSort_TOWARD:
std::sort(m_particles.begin(), m_particles.end(), m_towardComparator);
break;
case eSort_AWAY:
std::sort(m_particles.begin(), m_particles.end(), m_awayComparator);
break;
default:
break;
}
}
void CRECloud::GetIllumParams(ColorF& specColor, ColorF& diffColor)
{
CShaderResources* pRes = gRenDev->m_RP.m_pShaderResources;
if (pRes && pRes->HasLMConstants())
{
specColor = pRes->GetColorValue(EFTT_SPECULAR);
diffColor = pRes->GetColorValue(EFTT_DIFFUSE);
}
else
{
ColorF col = gRenDev->m_RP.m_pSunLight->m_Color;
float fLum = col.Luminance();
col.NormalizeCol(diffColor);
specColor.a = 1.0f;
specColor = specColor * fLum / 1.5f;
diffColor = gRenDev->m_RP.m_pCurObject->m_II.m_AmbColor / 5.0f;
}
}
void CRECloud::ShadeCloud([[maybe_unused]] Vec3 vPos)
{
ColorF specColor, diffColor;
if (gRenDev->m_RP.m_pSunLight)
{
GetIllumParams(specColor, diffColor);
//IlluminateCloud(gRenDev->m_RP.m_pSunLight->m_Origin, vPos, difColor, ambColor, true);
m_CurSpecColor = specColor;
m_CurDiffColor = diffColor;
m_bReshadeCloud = false;
if (gRenDev->m_RP.m_pCurObject && gRenDev->m_RP.m_pCurObject->GetRE())
{
CREImposter* pRE = (CREImposter*)gRenDev->m_RP.m_pCurObject->GetRE();
pRE->m_bScreenImposter = true;
}
}
}
void CRECloud::UpdateWorldSpaceBounds(CRenderObject* pObj)
{
CREImposter* pRE = (CREImposter*)pObj->GetRE();
assert(pRE);
if (!pRE)
{
return;
}
pRE->m_WorldSpaceBV = m_boundingBox;
if (m_Flags & FCEF_OLD)
{
Matrix34 mScale = Matrix34::CreateScale(Vec3(m_fScale, m_fScale, m_fScale));
pRE->m_WorldSpaceBV.Transform(mScale);
}
pRE->m_WorldSpaceBV.Transform(pObj->m_II.m_Matrix);
}
void CRECloud::mfPrepare(bool bCheckOverflow)
{
CRenderer* rd = gRenDev;
if (bCheckOverflow)
{
rd->FX_CheckOverflow(0, 0, this);
}
CRenderObject* pObj = rd->m_RP.m_pCurObject;
CREImposter* pRE = (CREImposter*)pObj->GetRE();
SRenderObjData* pOD = pObj->GetObjData();
assert(pOD);
if (!pOD)
{
return;
}
if (!pRE)
{
pRE = new CREImposter;
pObj->m_pRE = pRE;
pRE->m_State = GS_BLSRC_ONE | GS_BLDST_ONEMINUSSRCALPHA | GS_ALPHATEST_GREATER;
pRE->m_AlphaRef = 0;
}
if (pOD->m_fTempVars[0] != pOD->m_fTempVars[1])
{
pOD->m_fTempVars[1] = pOD->m_fTempVars[0];
m_bReshadeCloud = true;
}
if (m_Flags & FCEF_OLD)
{
float fCloudRadius = m_boundingBox.GetRadius();
m_fScale = pOD->m_fTempVars[0] / fCloudRadius;
}
else
{
m_fScale = pOD->m_fTempVars[0];
}
ColorF specColor, diffColor;
GetIllumParams(specColor, diffColor);
if (specColor != m_CurSpecColor || diffColor != m_CurDiffColor)
{
m_bReshadeCloud = true;
}
UpdateWorldSpaceBounds(pObj);
Vec3 vPos = pRE->GetPosition();
{
if (m_bReshadeCloud)
{
ShadeCloud(vPos);
}
UpdateImposter(pObj);
}
rd->m_RP.m_pCurObject = pObj;
rd->m_RP.m_pRE = this;
rd->m_RP.m_RendNumIndices = 0;
rd->m_RP.m_RendNumVerts = 4;
rd->m_RP.m_FirstVertex = 0;
}
bool CRECloud::mfLoadCloud(const string& name, float fScale, [[maybe_unused]] bool bLocal)
{
uint32 i;
AZ::IO::HandleType fileHandle = gEnv->pCryPak->FOpen(name.c_str(), "rb");
if (fileHandle == AZ::IO::InvalidHandle)
{
return false;
}
uint32 iNumParticles;
mfSetFlags(FCEF_OLD);
gEnv->pCryPak->FRead(&iNumParticles, 1, fileHandle);
if (iNumParticles == 0x238c)
{
char fTexName[128];
char texName[256];
gEnv->pCryPak->FRead(&iNumParticles, 1, fileHandle);
int n = 0;
int ch;
do
{
ch = gEnv->pCryPak->Getc(fileHandle);
fTexName[n++] = ch;
if (n > 128)
{
fTexName[127] = ch;
break;
}
} while (ch != 0);
fpStripExtension(fTexName, fTexName);
sprintf_s(texName, "Textures/Clouds/%s.dds", fTexName);
m_pTexParticle = CTexture::ForName(texName, 0, eTF_Unknown);
gEnv->pCryPak->FRead(&m_nNumColorGradients, 1, fileHandle);
//m_pColorGradients = new SColorLevel [m_nNumColorGradients];
for (i = 0; i < m_nNumColorGradients; i++)
{
float fLevel;
gEnv->pCryPak->FRead(&fLevel, 1, fileHandle);
//m_pColorGradients[i].m_fLevel /= 100.0f;
uint32 iColor;
gEnv->pCryPak->FRead(&iColor, 1, fileHandle);
//m_pColorGradients[i].m_vColor = ColorF(iColor);
}
for (i = 0; i < iNumParticles; ++i)
{
Vec3 vPosition;
short nShadingNum;
short nGroupNum;
short nWidthMin, nWidthMax;
short nLengthMin, nLengthMax;
short nRotMin, nRotMax;
Vec2 vUV[2];
gEnv->pCryPak->FRead(&vPosition, 1, fileHandle);
gEnv->pCryPak->FRead(&nShadingNum, 1, fileHandle);
gEnv->pCryPak->FRead(&nGroupNum, 1, fileHandle);
gEnv->pCryPak->FRead(&nWidthMin, 1, fileHandle);
gEnv->pCryPak->FRead(&nWidthMax, 1, fileHandle);
gEnv->pCryPak->FRead(&nLengthMin, 1, fileHandle);
gEnv->pCryPak->FRead(&nLengthMax, 1, fileHandle);
gEnv->pCryPak->FRead(&nRotMin, 1, fileHandle);
gEnv->pCryPak->FRead(&nRotMax, 1, fileHandle);
gEnv->pCryPak->FRead(&vUV[0], 1, fileHandle);
gEnv->pCryPak->FRead(&vUV[1], 1, fileHandle);
vPosition *= 0.001f;
float fWidth = (float)nWidthMin * 0.001f;
float fHeight = (float)nLengthMin * 0.001f;
float fRotMin = (float)nRotMin;
float fRotMax = (float)nRotMax;
Exchange(vPosition.y, vPosition.z);
vUV[0].y = 1.0f - vUV[0].y;
vUV[1].y = 1.0f - vUV[1].y;
Exchange(vUV[0].x, vUV[1].x);
/*int nX = nShadingNum & 0x3;
int nY = nShadingNum >> 2;
vUV[0].x = (float)nX * 0.25f;
vUV[1].x = vUV[0].x + 0.25f;
vUV[0].y = (float)nY * 0.25f;
vUV[1].y = vUV[0].y + 0.25f;*/
SCloudParticle* pParticle = new SCloudParticle(vPosition, fWidth, fHeight, fRotMin, fRotMax, vUV);
Vec3 vMin = pParticle->GetPosition() - Vec3(fWidth, fWidth, fHeight);
Vec3 vMax = pParticle->GetPosition() + Vec3(fWidth, fWidth, fHeight);
m_boundingBox.AddPoint(vMin);
m_boundingBox.AddPoint(vMax);
m_particles.push_back(pParticle);
}
Vec3 vCenter = m_boundingBox.GetCenter();
if (vCenter != Vec3(0, 0, 0))
{
m_boundingBox.Clear();
for (i = 0; i < iNumParticles; i++)
{
SCloudParticle* pParticle = m_particles[i];
pParticle->SetPosition(pParticle->GetPosition() - vCenter);
float fWidth = pParticle->GetRadiusX();
float fHeight = pParticle->GetRadiusY();
Vec3 vMin = pParticle->GetPosition() - Vec3(fWidth, fWidth, fHeight);
Vec3 vMax = pParticle->GetPosition() + Vec3(fWidth, fWidth, fHeight);
m_boundingBox.AddPoint(vMin);
m_boundingBox.AddPoint(vMax);
}
}
}
else
{
Vec3 vCenter = Vec3(0, 0, 0);
gEnv->pCryPak->FRead(&vCenter[0], 1, fileHandle);
vCenter = Vec3(0, 0, 0);
Vec3* pParticlePositions = new Vec3[iNumParticles];
float* pParticleRadii = new float[iNumParticles];
ColorF* pParticleColors = new ColorF[iNumParticles];
gEnv->pCryPak->FRead(pParticlePositions, iNumParticles, fileHandle);
gEnv->pCryPak->FRead(pParticleRadii, iNumParticles, fileHandle);
gEnv->pCryPak->FRead(pParticleColors, iNumParticles, fileHandle);
for (i = 0; i < iNumParticles; ++i)
{
if (pParticleRadii[i] < 0.8f)
{
continue;
}
pParticleRadii[i] *= 1.25f;
Exchange(pParticlePositions[i].y, pParticlePositions[i].z);
SCloudParticle* pParticle = new SCloudParticle((pParticlePositions[i] + vCenter) * fScale, pParticleRadii[i] * fScale, pParticleColors[i]);
float fRadiusX = pParticle->GetRadiusX();
float fRadiusY = pParticle->GetRadiusX();
Vec3 vRadius = Vec3(fRadiusX, fRadiusX, fRadiusY);
//Vec3 Mins = pParticle->GetPosition() - vRadius;
//Vec3 Maxs = pParticle->GetPosition() + vRadius;
//m_boundingBox.AddPoint(Mins);
//m_boundingBox.AddPoint(Maxs);
m_boundingBox.AddPoint(pParticle->GetPosition());
m_particles.push_back(pParticle);
}
SAFE_DELETE_ARRAY(pParticleColors);
SAFE_DELETE_ARRAY(pParticleRadii);
SAFE_DELETE_ARRAY(pParticlePositions);
m_pTexParticle = CTextureManager::Instance()->GetWhiteTexture();
}
gEnv->pCryPak->FClose(fileHandle);
return true;
}
bool CRECloud::mfCompile(CParserBin& Parser, SParserFrame& Frame)
{
SParserFrame OldFrame = Parser.BeginFrame(Frame);
FX_BEGIN_TOKENS
FX_TOKEN(ParticlesFile)
FX_TOKEN(Scale)
FX_END_TOKENS
bool bRes = true;
float fScale = 1.0f;
string pname;
ColorF col;
while (Parser.ParseObject(sCommands))
{
EToken eT = Parser.GetToken();
switch (eT)
{
case eT_ParticlesFile:
pname = Parser.GetString(Parser.m_Data);
break;
case eT_Scale:
fScale = Parser.GetFloat(Parser.m_Data);
break;
}
}
if (!pname.empty())
{
mfLoadCloud(pname, fScale, false);
}
m_bReshadeCloud = true;
Parser.EndFrame(OldFrame);
return bRes;
}
@@ -0,0 +1,173 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef __CRECLOUD_H__
#define __CRECLOUD_H__
//=============================================================
#define FCEF_OLD 0x1000
class CRECloud
: public CREBaseCloud
{
friend class CREImposter;
protected: // datatypes
typedef std::vector<SCloudParticle*> ParticleArray;
typedef ParticleArray::iterator ParticleIterator;
typedef ParticleArray::const_iterator ParticleConstIterator;
typedef std::vector<Vec3> DirectionArray;
typedef DirectionArray::iterator DirectionIterator;
class ParticleAwayComparator
{
public:
bool operator()(SCloudParticle* pA, SCloudParticle* pB)
{
return ((*pA) < (*pB));
}
};
class ParticleTowardComparator
{
public:
bool operator()(SCloudParticle* pA, SCloudParticle* pB)
{
return ((*pA) > (*pB));
}
};
protected: // data
enum ESortDirection
{
eSort_TOWARD,
eSort_AWAY
};
ParticleArray m_particles; // cloud particles
// particle sorting functors for STL sort.
ParticleTowardComparator m_towardComparator;
ParticleAwayComparator m_awayComparator;
DirectionArray m_lightDirections;// light directions in cloud space (cached)
SMinMaxBox m_boundingBox; // bounds
bool m_bUseAnisoLighting;
Vec3 m_vLastSortViewDir;
Vec3 m_vLastSortCamPos;
Vec3 m_vSortPos;
float m_fSplitDistance;
bool m_bReshadeCloud;
bool m_bEnabled;
float m_fScale;
CTexture* m_pTexParticle;
uint32 m_nNumPlanes;
uint32 m_nNumColorGradients;
ColorF m_CurSpecColor;
ColorF m_CurDiffColor;
float m_fCloudColorScale; // needed for HDR (>=1)
static uint32 m_siShadeResolution;// the resolution of the viewport used for shading
static float m_sfAlbedo; // the cloud albedo
static float m_sfExtinction; // the extinction of the clouds
static float m_sfTransparency;// the transparency of the clouds
static float m_sfScatterFactor;// How much the clouds scatter
static float m_sfSortAngleErrorTolerance;// how far the view must turn to cause a resort.
static float m_sfSortSquareDistanceTolerance;// how far the view must move to cause a resort.
protected:
void SortParticles(const Vec3& vViewDir, const Vec3& vSortPoint, ESortDirection eDir);
void GetIllumParams(ColorF& specColor, ColorF& diffColor);
void ShadeCloud(Vec3 vPos);
void IlluminateCloud(Vec3 vLightPos, Vec3 vObjPos, ColorF cLightColor, ColorF cAmbColor, bool bReset);
void DisplayWithoutImpostor(const CameraViewParameters& camera);
bool mfDisplay(bool bDisplayFrontOfSplit);
void UpdateWorldSpaceBounds(CRenderObject* pObj);
inline float GetScale() { return m_fScale; }
bool UpdateImposter(CRenderObject* pObj);
bool mfLoadCloud(const string& name, float fScale, bool bLocal);
void ClearParticles()
{
size_t size = m_particles.size();
for (size_t i(0); i < size; ++i)
{
delete m_particles[i];
}
m_particles.resize(0);
}
public:
CRECloud()
: CREBaseCloud()
, m_bUseAnisoLighting(true)
, m_bReshadeCloud(true)
, m_bEnabled(true)
, m_fScale(1.0f)
, m_vLastSortViewDir(Vec3(0, 0, 0))
, m_vLastSortCamPos(Vec3(0, 0, 0))
, m_CurSpecColor(Col_White)
, m_CurDiffColor(Col_White)
, m_pTexParticle(NULL)
, m_nNumPlanes(0)
, m_nNumColorGradients(0)
, m_fCloudColorScale(1)
{
mfSetType(eDATA_Cloud);
mfSetFlags(FCEF_TRANSFORM);
}
virtual ~CRECloud()
{
ClearParticles();
}
virtual bool mfCompile(CParserBin& Parser, SParserFrame& Frame);
virtual void mfPrepare(bool bCheckOverflow);
virtual bool mfDraw(CShader* ef, SShaderPass* sl);
virtual void SetParticles(SCloudParticle* pParticles, int nNumParticles)
{
m_bReshadeCloud = true;
m_boundingBox.Clear();
ClearParticles();
m_particles.reserve(nNumParticles);
for (int i = 0; i < nNumParticles; i++)
{
SCloudParticle* pPart = new SCloudParticle;
*pPart = pParticles[i];
float rx = pPart->GetRadiusX();
Vec3 vMin = pPart->GetPosition() - Vec3(rx, rx, rx);
Vec3 vMax = pPart->GetPosition() + Vec3(rx, rx, rx);
m_boundingBox.AddPoint(vMin);
m_boundingBox.AddPoint(vMax);
m_particles.push_back(pPart);
}
}
bool GenerateCloudImposter(CShader* pShader, CShaderResources* pRes, CRenderObject* pObject);
};
#endif // __CRECLOUD_H__
@@ -0,0 +1,50 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Deferred shading processing render element
#include "RenderDll_precompiled.h"
// constructor/destructor
CREDeferredShading::CREDeferredShading()
{
// setup screen process renderer type
mfSetType(eDATA_DeferredShading);
mfUpdateFlags(FCEF_TRANSFORM);
}
CREDeferredShading::~CREDeferredShading()
{
};
// prepare screen processing
void CREDeferredShading:: mfPrepare(bool bCheckOverflow)
{
if (bCheckOverflow)
{
gRenDev->FX_CheckOverflow(0, 0, this);
}
gRenDev->m_RP.m_pRE = this;
gRenDev->m_RP.m_RendNumIndices = 0;
gRenDev->m_RP.m_RendNumVerts = 0;
}
void CREDeferredShading::mfReset()
{
}
void CREDeferredShading::mfActivate([[maybe_unused]] int iProcess)
{
}
@@ -0,0 +1,52 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Deferred shading processing render element
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CREDEFERREDSHADING_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CREDEFERREDSHADING_H
#pragma once
class CREDeferredShading
: public CRendElementBase
{
friend class CD3D9Renderer;
friend class CGLRenderer;
public:
// constructor/destructor
CREDeferredShading();
virtual ~CREDeferredShading();
// prepare screen processing
virtual void mfPrepare(bool bCheckOverflow);
// render screen processing
virtual bool mfDraw(CShader* ef, SShaderPass* sfm);
// begin screen processing
virtual void mfActivate(int iProcess);
// reset
virtual void mfReset(void);
virtual void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
}
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CREDEFERREDSHADING_H
@@ -0,0 +1,63 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "CREFogVolume.h"
#include <IEntityRenderState.h> // <> required for Interfuscator
CREFogVolume::CREFogVolume()
: CRendElementBase()
, m_center(0.0f, 0.0f, 0.0f)
, m_viewerInsideVolume(0)
, m_stencilRef(0)
, m_reserved(0)
, m_localAABB(Vec3(-1, -1, -1), Vec3(1, 1, 1))
, m_matWSInv()
, m_fogColor(1, 1, 1, 1)
, m_globalDensity(1)
, m_softEdgesLerp(1, 0)
, m_heightFallOffDirScaled(0, 0, 1)
, m_heightFallOffBasePoint(0, 0, 0)
, m_eyePosInWS(0, 0, 0)
, m_eyePosInOS(0, 0, 0)
, m_rampParams(0, 0, 0)
, m_windOffset(0, 0, 0)
, m_noiseScale(0)
, m_noiseFreq(1, 1, 1)
, m_noiseOffset(0)
, m_noiseElapsedTime(0)
{
mfSetType(eDATA_FogVolume);
mfUpdateFlags(FCEF_TRANSFORM);
m_matWSInv.SetIdentity();
}
CREFogVolume::~CREFogVolume()
{
}
void CREFogVolume::mfPrepare(bool bCheckOverflow)
{
if (bCheckOverflow)
{
gRenDev->FX_CheckOverflow(0, 0, this);
}
gRenDev->m_RP.m_pRE = this;
gRenDev->m_RP.m_RendNumIndices = 0;
gRenDev->m_RP.m_RendNumVerts = 0;
}
@@ -0,0 +1,57 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Render element that uses the IREGameEffect interface for its functionality
#include "RenderDll_precompiled.h"
#include "CREGameEffect.h"
//--------------------------------------------------------------------------------------------------
// Name: CREGameEffect
// Desc: Constructor
//--------------------------------------------------------------------------------------------------
CREGameEffect::CREGameEffect()
{
m_pImpl = NULL;
mfSetType(eDATA_GameEffect);
mfUpdateFlags(FCEF_TRANSFORM);
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: ~CREGameEffect
// Desc: Destructor
//--------------------------------------------------------------------------------------------------
CREGameEffect::~CREGameEffect()
{
SAFE_DELETE(m_pImpl);
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: mfPrepare
// Desc: Prepares rendering
//--------------------------------------------------------------------------------------------------
void CREGameEffect::mfPrepare(bool bCheckOverflow)
{
if (bCheckOverflow)
{
gRenDev->FX_CheckOverflow(0, 0, this);
}
gRenDev->m_RP.m_pRE = this;
gRenDev->m_RP.m_RendNumIndices = 0;
gRenDev->m_RP.m_RendNumVerts = 0;
if (m_pImpl)
{
m_pImpl->mfPrepare(false);
}
}//-------------------------------------------------------------------------------------------------
@@ -0,0 +1,243 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Backend part of geometry cache rendering
#include "RenderDll_precompiled.h"
#include <Common/RendererDefs.h>
#include <Cry_Math.h>
#if defined(USE_GEOM_CACHES)
#include "RendElement.h"
#include "CREGeomCache.h"
#include "I3DEngine.h"
#include "../Renderer.h"
#include "../Common/PostProcess/PostEffects.h"
StaticInstance<CREGeomCache::UpdateList> CREGeomCache::sm_updateList[2];
CREGeomCache::CREGeomCache()
: m_geomCacheVertexFormat(eVF_P3F_C4B_T2F)
{
m_bUpdateFrame[0] = false;
m_bUpdateFrame[1] = false;
m_transformUpdateState[0] = 0;
m_transformUpdateState[1] = 0;
mfSetType(eDATA_GeomCache);
mfUpdateFlags(FCEF_TRANSFORM);
}
CREGeomCache::~CREGeomCache()
{
CryAutoLock<CryCriticalSection> lock1(sm_updateList[0]->m_mutex);
CryAutoLock<CryCriticalSection> lock2(sm_updateList[1]->m_mutex);
stl::find_and_erase(sm_updateList[0]->m_geoms, this);
stl::find_and_erase(sm_updateList[1]->m_geoms, this);
}
void CREGeomCache::InitializeRenderElement(const uint numMeshes, _smart_ptr<IRenderMesh>* pMeshes, uint16 materialId)
{
m_bUpdateFrame[0] = false;
m_bUpdateFrame[1] = false;
m_meshFillData[0].clear();
m_meshFillData[1].clear();
m_meshRenderData.clear();
m_meshFillData[0].reserve(numMeshes);
m_meshFillData[1].reserve(numMeshes);
m_meshRenderData.reserve(numMeshes);
for (uint i = 0; i < numMeshes; ++i)
{
SMeshRenderData meshRenderData;
meshRenderData.m_pRenderMesh = pMeshes[i];
m_meshRenderData.push_back(meshRenderData);
m_meshFillData[0].push_back(meshRenderData);
m_meshFillData[1].push_back(meshRenderData);
}
m_materialId = materialId;
}
void CREGeomCache::mfPrepare(bool bCheckOverflow)
{
FUNCTION_PROFILER_RENDER_FLAT
CRenderer* const pRenderer = gRenDev;
if (bCheckOverflow)
{
pRenderer->FX_CheckOverflow(0, 0, this);
}
pRenderer->m_RP.m_CurVFormat = GetVertexFormat();
pRenderer->m_RP.m_pRE = this;
pRenderer->m_RP.m_FirstVertex = 0;
pRenderer->m_RP.m_FirstIndex = 0;
pRenderer->m_RP.m_RendNumIndices = 0;
pRenderer->m_RP.m_RendNumVerts = 0;
}
void CREGeomCache::SetupMotionBlur(CRenderObject* pRenderObject, const SRenderingPassInfo& passInfo)
{
CMotionBlur::SetupObject(pRenderObject, passInfo);
if (pRenderObject->m_fDistance < CRenderer::CV_r_MotionBlurMaxViewDist)
{
pRenderObject->m_ObjFlags |= FOB_VERTEX_VELOCITY | FOB_MOTION_BLUR;
}
}
bool CREGeomCache::Update(const int flags, const bool bTessellation)
{
FUNCTION_PROFILER_RENDER_FLAT
// Wait until render node update has finished
const int threadId = gRenDev->m_RP.m_nProcessThreadID;
while (m_transformUpdateState[threadId])
{
CrySleep(0);
}
// Check if update was successful and if so copy data to render buffer
if (m_bUpdateFrame[threadId])
{
m_meshRenderData = m_meshFillData[threadId];
}
const uint numMeshes = m_meshFillData[threadId].size();
bool bRet = true;
for (uint nMesh = 0; nMesh < numMeshes; ++nMesh)
{
SMeshRenderData& meshData = m_meshFillData[threadId][nMesh];
CRenderMesh* const pRenderMesh = static_cast<CRenderMesh*>(meshData.m_pRenderMesh.get());
if (pRenderMesh && pRenderMesh->m_Modified[threadId].linked())
{
// Sync the async render mesh update. This waits for the fill thread started from main thread if it's still running.
// We need to do this manually, because geom caches don't use CREMesh.
pRenderMesh->SyncAsyncUpdate(threadId);
CRenderMesh* pVertexContainer = pRenderMesh->_GetVertexContainer();
bool bSucceed = pRenderMesh->RT_CheckUpdate(pVertexContainer, flags | VSM_MASK, bTessellation);
if (bSucceed)
{
pRenderMesh->m_Modified[threadId].erase();
}
if (!bSucceed || !pVertexContainer->_HasVBStream(VSF_GENERAL))
{
bRet = false;
}
}
}
return bRet;
}
void CREGeomCache::UpdateModified()
{
FUNCTION_PROFILER_RENDER_FLAT
const int threadId = gRenDev->m_RP.m_nProcessThreadID;
AZ_Assert(threadId >= 0 && threadId <= 2, "Container is not expecting this index");
CryAutoLock<CryCriticalSection> lock(sm_updateList[threadId]->m_mutex);
for (auto iter = sm_updateList[threadId]->m_geoms.begin();
iter != sm_updateList[threadId]->m_geoms.end(); iter = sm_updateList[threadId]->m_geoms.erase(iter))
{
CREGeomCache* pRenderElement = *iter;
pRenderElement->Update(0, false);
}
}
bool CREGeomCache::mfUpdate(int Flags, bool bTessellation)
{
const bool bRet = Update(Flags, bTessellation);
const int threadId = gRenDev->m_RP.m_nProcessThreadID;
CryAutoLock<CryCriticalSection> lock(sm_updateList[threadId]->m_mutex);
stl::find_and_erase(sm_updateList[threadId]->m_geoms, this);
m_Flags &= ~FCEF_DIRTY;
return bRet;
}
volatile int* CREGeomCache::SetAsyncUpdateState(int& threadId)
{
FUNCTION_PROFILER_RENDER_FLAT
ASSERT_IS_MAIN_THREAD(gRenDev->m_pRT);
threadId = gRenDev->m_RP.m_nFillThreadID;
m_bUpdateFrame[threadId] = false;
CryAutoLock<CryCriticalSection> lock(sm_updateList[threadId]->m_mutex);
stl::push_back_unique(sm_updateList[threadId]->m_geoms, this);
CryInterlockedIncrement(&m_transformUpdateState[threadId]);
return &m_transformUpdateState[threadId];
}
DynArray<CREGeomCache::SMeshRenderData>* CREGeomCache::GetMeshFillDataPtr()
{
FUNCTION_PROFILER_RENDER_FLAT
assert(gEnv->IsEditor() || !gRenDev->m_pRT->IsRenderThread(true));
const int threadId = gRenDev->m_RP.m_nFillThreadID;
return &m_meshFillData[threadId];
}
DynArray<CREGeomCache::SMeshRenderData>* CREGeomCache::GetRenderDataPtr()
{
FUNCTION_PROFILER_RENDER_FLAT
assert(gEnv->IsEditor() || !gRenDev->m_pRT->IsRenderThread(true));
return &m_meshRenderData;
}
void CREGeomCache::DisplayFilledBuffer(const int threadId)
{
if (m_bUpdateFrame[threadId])
{
// You need to call SetAsyncUpdateState before DisplayFilledBuffer
__debugbreak();
}
m_bUpdateFrame[threadId] = true;
}
AZ::Vertex::Format CREGeomCache::GetVertexFormat() const
{
return m_geomCacheVertexFormat;
}
bool CREGeomCache::GetGeometryInfo(SGeometryInfo &streams)
{
ZeroStruct(streams);
streams.vertexFormat = GetVertexFormat();
streams.nFirstIndex = 0;
streams.nFirstVertex = 0;
streams.nNumIndices = 0;
streams.primitiveType = eptTriangleList;
streams.streamMask = 0;
return true;
}
#endif
@@ -0,0 +1,50 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : HDR processing render element
#include "RenderDll_precompiled.h"
// constructor/destructor
CREHDRProcess::CREHDRProcess()
{
// setup screen process renderer type
mfSetType(eDATA_HDRProcess);
mfUpdateFlags(FCEF_TRANSFORM);
}
CREHDRProcess::~CREHDRProcess()
{
};
// prepare screen processing
void CREHDRProcess:: mfPrepare(bool bCheckOverflow)
{
if (bCheckOverflow)
{
gRenDev->FX_CheckOverflow(0, 0, this);
}
gRenDev->m_RP.m_pRE = this;
gRenDev->m_RP.m_RendNumIndices = 0;
gRenDev->m_RP.m_RendNumVerts = 0;
}
void CREHDRProcess::mfReset()
{
}
void CREHDRProcess::mfActivate([[maybe_unused]] int iProcess)
{
}
@@ -0,0 +1,52 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : HDR processing render element
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CREHDRPROCESS_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CREHDRPROCESS_H
#pragma once
// screen processing render element
class CREHDRProcess
: public CRendElementBase
{
friend class CD3D9Renderer;
friend class CGLRenderer;
public:
// constructor/destructor
CREHDRProcess();
virtual ~CREHDRProcess();
// prepare screen processing
virtual void mfPrepare(bool bCheckOverflow);
// render screen processing
virtual bool mfDraw(CShader* ef, SShaderPass* sfm);
// begin screen processing
virtual void mfActivate(int iProcess);
// reset
virtual void mfReset(void);
virtual void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
}
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CREHDRPROCESS_H
@@ -0,0 +1,186 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "RendElement.h"
#include "CREImposter.h"
#include "I3DEngine.h"
int CREImposter::m_MemUpdated;
int CREImposter::m_MemPostponed;
int CREImposter::m_PrevMemUpdated;
int CREImposter::m_PrevMemPostponed;
IDynTexture* CREImposter::m_pScreenTexture = NULL;
bool CREImposter::IsImposterValid(const CameraViewParameters& cam, [[maybe_unused]] float fRadiusX, [[maybe_unused]] float fRadiusY, [[maybe_unused]] float fCamRadiusX, [[maybe_unused]] float fCamRadiusY,
const int iRequiredLogResX, const int iRequiredLogResY, const uint32 dwBestEdge)
{
if (dwBestEdge != m_nLastBestEdge)
{
return false;
}
float fTransparency = gRenDev->m_RP.m_pCurObject->m_II.m_AmbColor.a;
if (gRenDev->m_RP.m_pShaderResources)
{
fTransparency *= gRenDev->m_RP.m_pShaderResources->GetStrengthValue(EFTT_OPACITY);
}
if (m_fCurTransparency != fTransparency)
{
m_fCurTransparency = fTransparency;
return false;
}
// screen impostors should always be updated
if (m_bScreenImposter)
{
m_vFarPoint = Vec3(0, 0, 0);
m_vNearPoint = Vec3(0, 0, 0);
return false;
}
if (m_bSplit)
{
return false;
}
Vec3 vEye = m_vPos - cam.vOrigin;
float fDistance = vEye.GetLength();
if (fDistance < 0.0001f)
{
return false; // to avoid float exceptions
}
vEye /= fDistance;
Vec3 vOldEye = m_vFarPoint - m_LastViewParameters.vOrigin;
float fOldEyeDist = vOldEye.GetLength();
if (fOldEyeDist < 0.0001f)
{
return false; // to avoid float exceptions
}
vOldEye /= fOldEyeDist;
float fCosAlpha = vEye * vOldEye; // dot product of normalized vectors = cosine
if (fCosAlpha < m_fErrorToleranceCosAngle)
{
return false;
}
Vec3 curSunDir(gEnv->p3DEngine->GetSunDir().GetNormalized());
if (m_vLastSunDir.Dot(curSunDir) < 0.995)
{
return false;
}
// equal pow-of-2 size comparison for consistent look
if (iRequiredLogResX != m_nLogResolutionX)
{
return false;
}
if (iRequiredLogResY != m_nLogResolutionY)
{
return false;
}
if (gRenDev->m_nFrameReset != m_nFrameReset)
{
return false;
}
return true;
}
void CREImposter::ReleaseResources()
{
SAFE_DELETE(m_pTexture);
SAFE_DELETE(m_pScreenTexture);
SAFE_DELETE(m_pFrontTexture);
SAFE_DELETE(m_pTextureDepth);
}
int IntersectRayAABB(Vec3 p, Vec3 d, SMinMaxBox a, Vec3& q)
{
float tmin = 0;
float tmax = FLT_MAX;
int i;
const Vec3& min = a.GetMin();
const Vec3& max = a.GetMax();
for (i = 0; i < 3; i++)
{
if (fabs(d[i]) < 0.001f)
{
if (p[i] < min[i] || p[i] > max[i])
{
return 0;
}
}
else
{
float ood = 1.0f / d[i];
float t1 = (min[i] - p[i]) * ood;
float t2 = (max[i] - p[i]) * ood;
if (t1 > t2)
{
Exchange(t1, t2);
}
if (t1 > tmin)
{
tmin = t1;
}
if (t2 > tmax)
{
tmax = t2;
}
}
}
q = p + d * tmin;
return 1;
}
Vec3 CREImposter::GetPosition()
{
Vec3 vNearest = m_WorldSpaceBV.GetCenter();
return vNearest;
}
void CREImposter::mfPrepare(bool bCheckOverflow)
{
CRenderer* rd = gRenDev;
if (bCheckOverflow)
{
rd->FX_CheckOverflow(0, 0, this);
}
CRenderObject* pObj = rd->m_RP.m_pCurObject;
CShaderResources* pRes = rd->m_RP.m_pShaderResources;
CShader* pShader = rd->m_RP.m_pShader;
int nTech = rd->m_RP.m_nShaderTechnique;
UpdateImposter();
rd->FX_Start(pShader, nTech, pRes, this);
rd->m_RP.m_pCurObject = pObj;
rd->m_RP.m_pRE = this;
rd->m_RP.m_RendNumIndices = 0;
rd->m_RP.m_RendNumVerts = 4;
rd->m_RP.m_FirstVertex = 0;
}
@@ -0,0 +1,36 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CRELENSOPTICS_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CRELENSOPTICS_H
#pragma once
class CRELensOptics
: public CRendElementBase
{
public:
CRELensOptics(void);
~CRELensOptics(void);
virtual bool mfCompile(CParserBin& Parser, SParserFrame& Frame);
virtual void mfPrepare(bool bCheckOverflow);
virtual bool mfDraw(CShader* ef, SShaderPass* sfm);
virtual void mfExport([[maybe_unused]] struct SShaderSerializeContext& SC) {};
virtual void mfImport([[maybe_unused]] struct SShaderSerializeContext& SC, [[maybe_unused]] uint32& offset) {};
void ProcessGlobalAction();
static void ClearResources();
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CRELENSOPTICS_H
@@ -0,0 +1,346 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "CREMeshImpl.h"
#if !defined(NULL_RENDERER)
#include "XRenderD3D9/DriverD3D.h"
#endif
void CREMeshImpl::mfReset()
{
}
void CREMeshImpl::mfCenter(Vec3& Pos, CRenderObject* pObj)
{
Vec3 Mins = m_pRenderMesh->m_vBoxMin;
Vec3 Maxs = m_pRenderMesh->m_vBoxMax;
Pos = (Mins + Maxs) * 0.5f;
if (pObj)
{
Pos += pObj->GetTranslation();
}
}
void CREMeshImpl::mfGetBBox(Vec3& vMins, Vec3& vMaxs)
{
vMins = m_pRenderMesh->_GetVertexContainer()->m_vBoxMin;
vMaxs = m_pRenderMesh->_GetVertexContainer()->m_vBoxMax;
}
///////////////////////////////////////////////////////////////////
void CREMeshImpl::mfPrepare(bool bCheckOverflow)
{
DETAILED_PROFILE_MARKER("CREMeshImpl::mfPrepare");
CRenderer* rd = gRenDev;
if (bCheckOverflow)
{
rd->FX_CheckOverflow(0, 0, this);
}
IF (!m_pRenderMesh, 0)
{
return;
}
rd->m_RP.m_CurVFormat = m_pChunk->m_vertexFormat;
{
rd->m_RP.m_pRE = this;
rd->m_RP.m_FirstVertex = m_nFirstVertId;
rd->m_RP.m_FirstIndex = m_nFirstIndexId;
rd->m_RP.m_RendNumIndices = m_nNumIndices;
rd->m_RP.m_RendNumVerts = m_nNumVerts;
if (rd->m_RP.m_TI[rd->m_RP.m_nProcessThreadID].m_PersFlags & (RBPF_SHADOWGEN) && (gRenDev->m_RP.m_PersFlags2 & RBPF2_DISABLECOLORWRITES))
{
_smart_ptr<IMaterial> pMaterial = (gRenDev->m_RP.m_pCurObject) ? (gRenDev->m_RP.m_pCurObject->m_pCurrMaterial) : NULL;
m_pRenderMesh->AddShadowPassMergedChunkIndicesAndVertices(m_pChunk, pMaterial, rd->m_RP.m_RendNumVerts, rd->m_RP.m_RendNumIndices);
}
}
}
TRenderChunkArray* CREMeshImpl::mfGetMatInfoList()
{
return &m_pRenderMesh->m_Chunks;
}
int CREMeshImpl::mfGetMatId()
{
return m_pChunk->m_nMatID;
}
CRenderChunk* CREMeshImpl::mfGetMatInfo()
{
return m_pChunk;
}
void CREMeshImpl::mfPrecache(const SShaderItem& SH)
{
DETAILED_PROFILE_MARKER("CREMeshImpl::mfPrecache");
CShader* pSH = (CShader*)SH.m_pShader;
IF (!pSH, 0)
{
return;
}
IF (!m_pRenderMesh, 0)
{
return;
}
IF (m_pRenderMesh->_HasVBStream(VSF_GENERAL), 0)
{
return;
}
mfCheckUpdate(VSM_TANGENTS, gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nFillThreadID].m_nFrameUpdateID);
}
bool CREMeshImpl::mfUpdate(int Flags, bool bTessellation)
{
DETAILED_PROFILE_MARKER("CREMeshImpl::mfUpdate");
FUNCTION_PROFILER_RENDER_FLAT
IF (m_pRenderMesh == NULL, 0)
{
return false;
}
CRenderer* rd = gRenDev;
const int threadId = rd->m_RP.m_nProcessThreadID;
bool bSucceed = true;
CRenderMesh* pVContainer = m_pRenderMesh->_GetVertexContainer();
m_pRenderMesh->m_nFlags &= ~FRM_SKINNEDNEXTDRAW;
if (m_pRenderMesh->m_Modified[threadId].linked() || bTessellation) // TODO: use the modified list also for tessellated meshes
{
m_pRenderMesh->SyncAsyncUpdate(gRenDev->m_RP.m_nProcessThreadID);
bSucceed = m_pRenderMesh->RT_CheckUpdate(pVContainer, Flags | VSM_MASK, bTessellation);
if (bSucceed)
{
m_pRenderMesh->m_Modified[threadId].erase();
}
}
if (!bSucceed || !pVContainer->_HasVBStream(VSF_GENERAL))
{
return false;
}
bool bSkinned = (m_pRenderMesh->m_nFlags & (FRM_SKINNED | FRM_SKINNEDNEXTDRAW)) != 0;
if ((Flags | VSM_MASK) & VSM_TANGENTS)
{
if (bSkinned && pVContainer->_HasVBStream(VSF_QTANGENTS))
{
rd->m_RP.m_FlagsStreams_Stream &= ~VSM_TANGENTS;
rd->m_RP.m_FlagsStreams_Decl &= ~VSM_TANGENTS;
rd->m_RP.m_FlagsStreams_Stream |= (1 << VSF_QTANGENTS);
rd->m_RP.m_FlagsStreams_Decl |= (1 << VSF_QTANGENTS);
}
}
rd->m_RP.m_CurVFormat = m_pChunk->m_vertexFormat;
m_Flags &= ~FCEF_DIRTY;
return true;
}
void* CREMeshImpl::mfGetPointer(ESrcPointer ePT, int* Stride, [[maybe_unused]] EParamType Type, [[maybe_unused]] ESrcPointer Dst, [[maybe_unused]] int Flags)
{
DETAILED_PROFILE_MARKER("CREMeshImpl::mfGetPointer");
CRenderMesh* pRM = m_pRenderMesh->_GetVertexContainer();
byte* pD = NULL;
IRenderMesh::ThreadAccessLock lock(pRM);
switch (ePT)
{
case eSrcPointer_Vert:
pD = pRM->GetPosPtr(*Stride, FSL_READ);
break;
case eSrcPointer_Tex:
pD = pRM->GetUVPtr(*Stride, FSL_READ);
break;
case eSrcPointer_Normal:
pD = pRM->GetNormPtr(*Stride, FSL_READ);
break;
case eSrcPointer_Tangent:
pD = pRM->GetTangentPtr(*Stride, FSL_READ);
break;
case eSrcPointer_Color:
pD = pRM->GetColorPtr(*Stride, FSL_READ);
break;
default:
assert(false);
break;
}
if (m_nFirstVertId && pD)
{
pD += m_nFirstVertId * (*Stride);
}
return pD;
}
void CREMeshImpl::mfGetPlane(Plane& pl)
{
CRenderMesh* pRM = m_pRenderMesh->_GetVertexContainer();
// fixme: plane orientation based on biggest bbox axis
Vec3 pMin, pMax;
mfGetBBox(pMin, pMax);
Vec3 p0 = pMin;
Vec3 p1 = Vec3(pMax.x, pMin.y, pMin.z);
Vec3 p2 = Vec3(pMin.x, pMax.y, pMin.z);
pl.SetPlane(p2, p0, p1);
}
AZ::Vertex::Format CREMeshImpl::GetVertexFormat() const
{
if (m_pChunk)
{
return m_pChunk->m_vertexFormat;
}
else if (m_pRenderMesh)
{
return m_pRenderMesh->_GetVertexContainer()->_GetVertexFormat();
}
return AZ::Vertex::Format(eVF_Unknown);
}
bool CREMeshImpl::GetGeometryInfo(SGeometryInfo &geomInfo)
{
if (!m_pRenderMesh)
return false;
CRenderMesh *pVContainer = m_pRenderMesh->_GetVertexContainer();
geomInfo.nFirstIndex = m_nFirstIndexId;
geomInfo.nFirstVertex = m_nFirstVertId;
geomInfo.nNumVertices = m_nNumVerts;
geomInfo.nNumIndices = m_nNumIndices;
geomInfo.vertexFormat = pVContainer->_GetVertexFormat();
geomInfo.primitiveType = pVContainer->GetPrimitiveType();
geomInfo.streamMask = 0;
const bool bSkinned = (m_pRenderMesh->m_nFlags & (FRM_SKINNED | FRM_SKINNEDNEXTDRAW)) != 0;
if (bSkinned && pVContainer->_HasVBStream(VSF_QTANGENTS))
geomInfo.streamMask |= BIT(VSF_QTANGENTS);
{
// Check if needs updating.
//TODO Fix constant | 0x80000000
//bool bTessEnabled = (pso->m_ShaderFlags_RT & g_HWSR_MaskBit[HWSR_NO_TESSELLATION]) != 0;
bool bTessEnabled = false;
uint32 streamMask = 0;
uint16 nFrameId = gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nFillThreadID].m_nFrameUpdateID;
if (!mfCheckUpdate((uint32)streamMask | 0x80000000, (uint16)nFrameId, bTessEnabled))
return false;
}
if (!m_pRenderMesh->FillGeometryInfo(geomInfo))
return false;
return true;
}
bool CREMeshImpl::BindRemappedSkinningData([[maybe_unused]] uint32 guid)
{
#if !defined(NULL_RENDERER)
CD3D9Renderer *rd = gcpRendD3D;
SGeometryStreamInfo streamInfo;
CRenderMesh *pRM = m_pRenderMesh->_GetVertexContainer();
if (pRM->GetRemappedSkinningData(guid, streamInfo))
{
rd->FX_SetVStream(VSF_HWSKIN_INFO, streamInfo.pStream, streamInfo.nOffset, streamInfo.nStride);
return true;
}
#endif
return false;
}
#if !defined(NULL_RENDERER)
bool CREMeshImpl::mfPreDraw([[maybe_unused]] SShaderPass *sl)
{
DETAILED_PROFILE_MARKER("CREMeshImpl::mfPreDraw");
IF(!m_pRenderMesh, 0)
return false;
CRenderMesh *pRM = m_pRenderMesh->_GetVertexContainer();
pRM->PrefetchVertexStreams();
// Should never happen. Video buffer is missing
if (!pRM->_HasVBStream(VSF_GENERAL) || !m_pRenderMesh->_HasIBStream())
return false;
CD3D9Renderer *rd = gcpRendD3D;
m_pRenderMesh->BindStreamsToRenderPipeline();
m_Flags |= FCEF_PRE_DRAW_DONE;
return true;
}
#if !defined(_RELEASE)
inline bool CREMeshImpl::ValidateDraw(EShaderType shaderType)
{
bool ret = true;
if (shaderType != eST_General &&
shaderType != eST_PostProcess &&
shaderType != eST_FX &&
shaderType != eST_Glass &&
shaderType != eST_Water)
{
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "Incorrect shader set for mesh type: %s : %d", m_pRenderMesh->GetSourceName(), shaderType);
ret = false;
}
if (!(m_Flags&FCEF_PRE_DRAW_DONE))
{
CryWarning(VALIDATOR_MODULE_RENDERER, VALIDATOR_ERROR, "PreDraw not called for mesh: %s", m_pRenderMesh->GetSourceName());
ret = false;
}
return ret;
}
#endif
bool CREMeshImpl::mfDraw(CShader *ef, [[maybe_unused]] SShaderPass *sl)
{
DETAILED_PROFILE_MARKER("CREMeshImpl::mfDraw");
FUNCTION_PROFILER_RENDER_FLAT
CD3D9Renderer *r = gcpRendD3D;
#if !defined(_RELEASE)
if (!ValidateDraw(ef->m_eShaderType))
{
return false;
}
#endif
CRenderMesh *pRM = m_pRenderMesh;
if (ef->m_HWTechniques.Num() && pRM->CanRender())
{
r->FX_DrawIndexedMesh(r->m_RP.m_RendNumGroup >= 0 ? eptHWSkinGroups : pRM->GetPrimitiveType());
}
return true;
}
#endif
@@ -0,0 +1,72 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates, or
* a third party where indicated.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
class CREMeshImpl
: public CREMesh
{
#if !defined(NULL_RENDERER)
public:
// Constant buffer used for tessellation. It has just one constant which tells the hull shader how it needs to offset iPrimitiveID that comes from HW.
WrappedDX11Buffer m_tessCB;
#endif
public:
virtual struct CRenderChunk* mfGetMatInfo();
virtual TRenderChunkArray* mfGetMatInfoList();
virtual int mfGetMatId();
virtual bool mfPreDraw(SShaderPass* sl);
virtual bool mfIsHWSkinned()
{
return (m_Flags & FCEF_SKINNED) != 0;
}
virtual void mfGetPlane(Plane& pl);
virtual void mfPrepare(bool bCheckOverflow);
virtual void mfReset();
virtual void mfCenter(Vec3& Pos, CRenderObject* pObj);
virtual bool mfDraw(CShader* ef, SShaderPass* sfm);
virtual void* mfGetPointer(ESrcPointer ePT, int* Stride, EParamType Type, ESrcPointer Dst, int Flags);
virtual bool mfUpdate(int Flags, bool bTessellation = false);
virtual void mfGetBBox(Vec3& vMins, Vec3& vMaxs);
virtual void mfPrecache(const SShaderItem& SH);
virtual int Size()
{
int nSize = sizeof(*this);
return nSize;
}
virtual void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
}
bool BindRemappedSkinningData(uint32 guid);
CREMeshImpl()
{
}
virtual ~CREMeshImpl()
{
}
#if !defined(_RELEASE)
inline bool ValidateDraw(EShaderType shaderType);
#endif
virtual bool GetGeometryInfo(SGeometryInfo &geomInfo) override;
virtual AZ::Vertex::Format GetVertexFormat() const override;
//protected:
// CREMeshImpl(CREMeshImpl&);
// CREMeshImpl& operator=(CREMeshImpl&);
};
@@ -0,0 +1,44 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "RendElement.h"
void CREOcclusionQuery::mfPrepare(bool bCheckOverflow)
{
if (bCheckOverflow)
{
gRenDev->FX_CheckOverflow(0, 0, this);
}
mfSetType(eDATA_OcclusionQuery);
mfUpdateFlags(FCEF_TRANSFORM);
// m_matWSInv.SetIdentity();
gRenDev->m_RP.m_pRE = this;
gRenDev->m_RP.m_RendNumIndices = 0;
gRenDev->m_RP.m_FirstVertex = 0;
gRenDev->m_RP.m_RendNumVerts = 4;
if (m_pRMBox && m_pRMBox->m_Chunks.size())
{
CRenderChunk* pChunk = &m_pRMBox->m_Chunks[0];
if (pChunk)
{
gRenDev->m_RP.m_RendNumIndices = pChunk->nNumIndices;
gRenDev->m_RP.m_FirstVertex = 0;
gRenDev->m_RP.m_RendNumVerts = pChunk->nNumVerts;
}
}
}
@@ -0,0 +1,145 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Post processing RenderElement
#include "RenderDll_precompiled.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
CREPostProcess::CREPostProcess()
{
mfSetType(eDATA_PostProcess);
mfUpdateFlags(FCEF_TRANSFORM);
}
CREPostProcess::~CREPostProcess()
{
}
void CREPostProcess:: mfPrepare(bool bCheckOverflow)
{
if (bCheckOverflow)
{
gRenDev->FX_CheckOverflow(0, 0, this);
}
gRenDev->m_RP.m_pRE = this;
gRenDev->m_RP.m_RendNumIndices = 0;
gRenDev->m_RP.m_RendNumVerts = 0;
if (CRenderer::CV_r_PostProcessReset)
{
CRenderer::CV_r_PostProcessReset = 0;
mfReset();
}
}
void CREPostProcess::Reset(bool bOnSpecChange)
{
if (PostEffectMgr())
{
PostEffectMgr()->Reset(bOnSpecChange);
}
}
int CREPostProcess:: mfSetParameter(const char* pszParam, float fValue, bool bForceValue) const
{
assert((pszParam) && "mfSetParameter: null parameter");
CEffectParam* pParam = PostEffectMgr()->GetByName(pszParam);
if (!pParam)
{
return 0;
}
pParam->SetParam(fValue, bForceValue);
return 1;
}
void CREPostProcess:: mfGetParameter(const char* pszParam, float& fValue) const
{
assert((pszParam) && "mfGetParameter: null parameter");
CEffectParam* pParam = PostEffectMgr()->GetByName(pszParam);
if (!pParam)
{
return;
}
fValue = pParam->GetParam();
}
int CREPostProcess:: mfSetParameterVec4(const char* pszParam, const Vec4& pValue, bool bForceValue) const
{
assert((pszParam) && "mfSetParameter: null parameter");
CEffectParam* pParam = PostEffectMgr()->GetByName(pszParam);
if (!pParam)
{
return 0;
}
pParam->SetParamVec4(pValue, bForceValue);
return 1;
}
void CREPostProcess:: mfGetParameterVec4(const char* pszParam, Vec4& pValue) const
{
assert((pszParam) && "mfGetParameter: null parameter");
CEffectParam* pParam = PostEffectMgr()->GetByName(pszParam);
if (!pParam)
{
return;
}
pValue = pParam->GetParamVec4();
}
int CREPostProcess::mfSetParameterString(const char* pszParam, const char* pszArg) const
{
assert((pszParam || pszArg) && "mfSetParameter: null parameter");
CEffectParam* pParam = PostEffectMgr()->GetByName(pszParam);
if (!pParam)
{
return 0;
}
pParam->SetParamString(pszArg);
return 1;
}
void CREPostProcess::mfGetParameterString(const char* pszParam, const char*& pszArg) const
{
assert((pszParam) && "mfGetParameter: null parameter");
CEffectParam* pParam = PostEffectMgr()->GetByName(pszParam);
if (!pParam)
{
return;
}
pszArg = pParam->GetParamString();
}
int32 CREPostProcess::mfGetPostEffectID(const char* pPostEffectName) const
{
assert(pPostEffectName && "mfGetParameter: null parameter");
return PostEffectMgr()->GetEffectID(pPostEffectName);
}
@@ -0,0 +1,41 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#if !defined(EXCLUDE_DOCUMENTATION_PURPOSE)
#include "CREPrismObject.h"
#include <IEntityRenderState.h> // <> required for Interfuscator
CREPrismObject::CREPrismObject()
: CRendElementBase()
, m_center(0, 0, 0)
{
mfSetType(eDATA_PrismObject);
mfUpdateFlags(FCEF_TRANSFORM);
}
void CREPrismObject::mfPrepare(bool bCheckOverflow)
{
if (bCheckOverflow)
{
gRenDev->FX_CheckOverflow(0, 0, this);
}
gRenDev->m_RP.m_pRE = this;
gRenDev->m_RP.m_RendNumIndices = 0;
gRenDev->m_RP.m_RendNumVerts = 0;
}
#endif // EXCLUDE_DOCUMENTATION_PURPOSE
@@ -0,0 +1,304 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "RendElement.h"
#include "CRESky.h"
#include "Stars.h"
#include "I3DEngine.h"
#include <Common/RenderCapabilities.h>
#include <Pak/CryPakUtils.h>
#if !defined(NULL_RENDERER)
#include "../../XRenderD3D9/DriverD3D.h"
#endif
CRESky::CRESky()
: m_skyVertexFormat(eVF_P3F_C4B_T2F)
{
mfSetType(eDATA_Sky);
mfUpdateFlags(FCEF_TRANSFORM);
m_fTerrainWaterLevel = 0;
m_fAlpha = 1;
m_nSphereListId = 0;
m_fSkyBoxStretching = 1.f;
}
void CRESky::mfPrepare(bool bCheckOverflow)
{
if (bCheckOverflow)
{
gRenDev->FX_CheckOverflow(0, 0, this);
}
gRenDev->m_RP.m_pRE = this;
gRenDev->m_RP.m_RendNumIndices = 0;
gRenDev->m_RP.m_RendNumVerts = 0;
}
AZ::Vertex::Format CRESky::GetVertexFormat() const
{
return m_skyVertexFormat;
}
bool CRESky::GetGeometryInfo(SGeometryInfo &streams)
{
ZeroStruct(streams);
streams.vertexFormat = GetVertexFormat();
streams.primitiveType = eptTriangleList;
return true;
}
CRESky::~CRESky()
{
}
//////////////////////////////////////////////////////////////////////////
// HDR Sky
//////////////////////////////////////////////////////////////////////////
CREHDRSky::CREHDRSky()
: m_pRenderParams(0)
, m_skyDomeTextureLastTimeStamp(-1)
, m_frameReset(0)
, m_pStars(0)
, m_pSkyDomeTextureMie(0)
, m_pSkyDomeTextureRayleigh(0)
, m_hdrSkyVertexFormat(eVF_P3F_C4B_T2F)
{
mfSetType(eDATA_HDRSky);
mfUpdateFlags(FCEF_TRANSFORM);
Init();
}
void CREHDRSky::GenerateSkyDomeTextures([[maybe_unused]] int32 width, [[maybe_unused]] int32 height)
{
SAFE_RELEASE(m_pSkyDomeTextureMie);
SAFE_RELEASE(m_pSkyDomeTextureRayleigh);
#if !defined(NULL_RENDERER)
int creationFlags = FT_STATE_CLAMP | FT_NOMIPS;
m_pSkyDomeTextureMie = CTexture::Create2DTexture("$SkyDomeTextureMie", width, height, 1, creationFlags, 0, eTF_R16G16B16A16F, eTF_R16G16B16A16F);
m_pSkyDomeTextureMie->SetFilterMode(FILTER_LINEAR);
m_pSkyDomeTextureMie->SetClampingMode(0, 1, 1);
m_pSkyDomeTextureMie->UpdateTexStates();
m_pSkyDomeTextureRayleigh = CTexture::Create2DTexture("$SkyDomeTextureRayleigh", width, height, 1, creationFlags, 0, eTF_R16G16B16A16F, eTF_R16G16B16A16F);
m_pSkyDomeTextureRayleigh->SetFilterMode(FILTER_LINEAR);
m_pSkyDomeTextureRayleigh->SetClampingMode(0, 1, 1);
m_pSkyDomeTextureRayleigh->UpdateTexStates();
#endif
}
void CREHDRSky::Init()
{
// The drivers in Qualcomm devices running Android 4.4 and OpenGL ES 3.0 crash
// when running the "Stars" vertex shader. The problem is a combination of using gl_VertexID
// and accessing global arrays. Disabling it for GLES 3.0 devices for now.
if (!m_pStars && GetShaderLanguage() != eSL_GLES3_0)
{
m_pStars = new CStars;
}
//No longer defer texture creation, MT resource creation now supported
//gRenDev->m_pRT->RC_GenerateSkyDomeTextures(this, SSkyLightRenderParams::skyDomeTextureWidth, SSkyLightRenderParams::skyDomeTextureHeight);
GenerateSkyDomeTextures(SSkyLightRenderParams::skyDomeTextureWidth, SSkyLightRenderParams::skyDomeTextureHeight);
}
void CREHDRSky::mfPrepare(bool bCheckOverflow)
{
if (bCheckOverflow)
{
gRenDev->FX_CheckOverflow(0, 0, this);
}
//gRenDev->FX_CheckOverflow( 0, 0, this );
gRenDev->m_RP.m_pRE = this;
gRenDev->m_RP.m_RendNumIndices = 0;
gRenDev->m_RP.m_RendNumVerts = 0;
}
AZ::Vertex::Format CREHDRSky::GetVertexFormat() const
{
return m_hdrSkyVertexFormat;
}
bool CREHDRSky::GetGeometryInfo(SGeometryInfo &streams)
{
ZeroStruct(streams);
streams.vertexFormat = GetVertexFormat();
streams.primitiveType = eptTriangleList;
return true;
}
CREHDRSky::~CREHDRSky()
{
SAFE_DELETE(m_pStars);
SAFE_RELEASE(m_pSkyDomeTextureMie);
SAFE_RELEASE(m_pSkyDomeTextureRayleigh);
}
void CREHDRSky::SetCommonMoonParams(CShader* ef, bool bUseMoon)
{
I3DEngine* p3DEngine(gEnv->p3DEngine);
Vec3 mr;
p3DEngine->GetGlobalParameter(E3DPARAM_SKY_MOONROTATION, mr);
float moonLati = -gf_PI + gf_PI * mr.x / 180.0f;
float moonLong = 0.5f * gf_PI - gf_PI * mr.y / 180.0f;
float sinLonR = sinf(-0.5f * gf_PI);
float cosLonR = cosf(-0.5f * gf_PI);
float sinLatR = sinf(moonLati + 0.5f * gf_PI);
float cosLatR = cosf(moonLati + 0.5f * gf_PI);
Vec3 moonTexGenRight(sinLonR * cosLatR, sinLonR * sinLatR, cosLonR);
Vec4 nsMoonTexGenRight(moonTexGenRight, 0);
static CCryNameR ParamNameTGR("SkyDome_NightMoonTexGenRight");
ef->FXSetVSFloat(ParamNameTGR, &nsMoonTexGenRight, 1);
float sinLonU = sinf(moonLong + 0.5f * gf_PI);
float cosLonU = cosf(moonLong + 0.5f * gf_PI);
float sinLatU = sinf(moonLati);
float cosLatU = cosf(moonLati);
Vec3 moonTexGenUp(sinLonU * cosLatU, sinLonU * sinLatU, cosLonU);
Vec4 nsMoonTexGenUp(moonTexGenUp, 0);
static CCryNameR ParamNameTGU("SkyDome_NightMoonTexGenUp");
ef->FXSetVSFloat(ParamNameTGU, &nsMoonTexGenUp, 1);
Vec3 nightMoonDirection;
p3DEngine->GetGlobalParameter(E3DPARAM_NIGHSKY_MOON_DIRECTION, nightMoonDirection);
float nightMoonSize(25.0f - 24.0f * clamp_tpl(p3DEngine->GetGlobalParameter(E3DPARAM_NIGHSKY_MOON_SIZE), 0.0f, 1.0f));
Vec4 nsMoonDirSize(nightMoonDirection, bUseMoon ? nightMoonSize : 9999.0f);
static CCryNameR ParamNameDirSize("SkyDome_NightMoonDirSize");
ef->FXSetVSFloat(ParamNameDirSize, &nsMoonDirSize, 1);
ef->FXSetPSFloat(ParamNameDirSize, &nsMoonDirSize, 1);
}
//////////////////////////////////////////////////////////////////////////
// Stars
//////////////////////////////////////////////////////////////////////////
CStars::CStars()
: m_numStars(0)
, m_pStarMesh(0)
, m_pShader(0)
{
if (LoadData())
{
#ifndef NULL_RENDERER
gRenDev->m_cEF.mfRefreshSystemShader("Stars", gRenDev->m_cEF.s_ShaderStars);
m_pShader = gRenDev->m_cEF.s_ShaderStars;
#endif
}
}
CStars::~CStars()
{
m_pStarMesh = NULL;
}
bool CStars::LoadData()
{
const uint32 c_fileTag(0x52415453); // "STAR"
const uint32 c_fileVersion(0x00010001);
const char c_fileName[] = "engineassets/sky/stars.dat";
auto pPak(gEnv->pCryPak);
if (pPak)
{
CInMemoryFileLoader file(pPak);
if (file.FOpen(c_fileName, "rb"))
{
// read and validate header
size_t itemsRead(0);
uint32 fileTag(0);
itemsRead = file.FRead(&fileTag, 1);
if (itemsRead != 1 || fileTag != c_fileTag)
{
file.FClose();
return false;
}
uint32 fileVersion(0);
itemsRead = file.FRead(&fileVersion, 1);
if (itemsRead != 1 || fileVersion != c_fileVersion)
{
file.FClose();
return false;
}
// read in stars
file.FRead(&m_numStars, 1);
SVF_P3S_C4B_T2S* pData(new SVF_P3S_C4B_T2S[6 * m_numStars]);
for (unsigned int i(0); i < m_numStars; ++i)
{
float ra(0);
file.FRead(&ra, 1);
float dec(0);
file.FRead(&dec, 1);
uint8 r(0);
file.FRead(&r, 1);
uint8 g(0);
file.FRead(&g, 1);
uint8 b(0);
file.FRead(&b, 1);
uint8 mag(0);
file.FRead(&mag, 1);
Vec3 v;
v.x = -cosf(DEG2RAD(dec)) * sinf(DEG2RAD(ra * 15.0f));
v.y = cosf(DEG2RAD(dec)) * cosf(DEG2RAD(ra * 15.0f));
v.z = sinf(DEG2RAD(dec));
for (int k = 0; k < 6; k++)
{
pData[6 * i + k].xyz = v;
pData[6 * i + k].color.dcolor = (mag << 24) + (b << 16) + (g << 8) + r;
}
}
m_pStarMesh = gRenDev->CreateRenderMeshInitialized(pData, 6 * m_numStars, eVF_P3S_C4B_T2S, 0, 0, prtTriangleList, "Stars", "Stars");
delete [] pData;
// check if we read entire file
long curPos(file.FTell());
file.FSeek(0, SEEK_END);
long endPos(file.FTell());
if (curPos != endPos)
{
file.FClose();
return false;
}
file.FClose();
return true;
}
}
return false;
}
@@ -0,0 +1,191 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "CREVolumeObject.h"
#include <IEntityRenderState.h> // <> required for Interfuscator
#include <AzCore/std/containers/vector.h>
#if !defined(NULL_RENDERER)
#include "../../XRenderD3D9/DriverD3D.h"
#endif
//////////////////////////////////////////////////////////////////////////
//
class CVolumeTexture
: public IVolumeTexture
{
public:
void Release() override;
bool Create(unsigned int width, unsigned int height, unsigned int depth, unsigned char* pData) override;
bool Update(unsigned int width, unsigned int height, unsigned int depth, const unsigned char* pData) override;
int GetTexID() const override;
uint32 GetWidth() const override { return m_width; }
uint32 GetHeight() const override { return m_height; }
uint32 GetDepth() const override { return m_depth; }
CTexture* GetTexture() const override { return m_pTex; }
CVolumeTexture();
~CVolumeTexture();
private:
unsigned int m_width;
unsigned int m_height;
unsigned int m_depth;
static const size_t StagingBufferFrameCount = 2;
AZStd::vector<uint8_t> m_StagingData;
uint8_t m_FrameIndex;
inline uint8_t* GetCurrentStagingData()
{
const size_t sliceSize = m_StagingData.size() / StagingBufferFrameCount;
return &m_StagingData[m_FrameIndex * sliceSize];
}
CTexture* m_pTex;
};
CVolumeTexture::CVolumeTexture()
: m_width(0)
, m_height(0)
, m_depth(0)
, m_pTex(0)
, m_FrameIndex(0)
{
}
CVolumeTexture::~CVolumeTexture()
{
if (m_pTex)
{
gRenDev->RemoveTexture(m_pTex->GetTextureID());
}
}
void CVolumeTexture::Release()
{
delete this;
}
bool CVolumeTexture::Create(unsigned int width, unsigned int height, unsigned int depth, unsigned char* pData)
{
assert(!m_pTex);
if (!m_pTex)
{
char name[128];
name[sizeof(name) - 1] = '\0';
azsnprintf(name, sizeof(name) - 1, "$VolObj_%d", gRenDev->m_TexGenID++);
const uint32_t totalByteCount = width * height * depth;
m_StagingData.resize(totalByteCount * StagingBufferFrameCount);
if (pData)
{
uint8_t* currentStagingData = GetCurrentStagingData();
memcpy(currentStagingData, pData, totalByteCount);
pData = currentStagingData;
}
int flags(FT_DONT_STREAM);
m_pTex = CTexture::Create3DTexture(name, width, height, depth, 1, flags, pData, eTF_A8, eTF_A8);
m_width = width;
m_height = height;
m_depth = depth;
}
return m_pTex != 0;
}
bool CVolumeTexture::Update([[maybe_unused]] unsigned int width, [[maybe_unused]] unsigned int height, [[maybe_unused]] unsigned int depth, [[maybe_unused]] const unsigned char* pData)
{
if (!CTexture::IsTextureExist(m_pTex))
{
return false;
}
m_FrameIndex ^= m_FrameIndex;
uint8_t* stagingData = GetCurrentStagingData();
#if !defined(NULL_RENDERER)
unsigned int cpyWidth = min(width, m_width);
unsigned int cpyHeight = min(height, m_height);
unsigned int cpyDepth = min(depth, m_depth);
memcpy(stagingData, pData, cpyWidth * cpyHeight * cpyDepth);
m_pTex->UpdateTextureRegion(stagingData, 0, 0, 0, cpyWidth, cpyHeight, cpyDepth, m_pTex->GetDstFormat());
#endif
return true;
}
int CVolumeTexture::GetTexID() const
{
return m_pTex ? m_pTex->GetTextureID() : 0;
}
//////////////////////////////////////////////////////////////////////////
//
CREVolumeObject::CREVolumeObject()
: CRendElementBase()
, m_center(0, 0, 0)
, m_matInv()
, m_eyePosInWS(0, 0, 0)
, m_eyePosInOS(0, 0, 0)
, m_volumeTraceStartPlane(Vec3(0, 0, 1), 0)
, m_renderBoundsOS(Vec3(-1, -1, -1), Vec3(1, 1, 1))
, m_viewerInsideVolume(false)
, m_nearPlaneIntersectsVolume(false)
, m_alpha(1)
, m_scale(1)
, m_pDensVol(0)
, m_pShadVol(0)
, m_pHullMesh(0)
{
mfSetType(eDATA_VolumeObject);
mfUpdateFlags(FCEF_TRANSFORM);
m_matInv.SetIdentity();
}
CREVolumeObject::~CREVolumeObject()
{
}
void CREVolumeObject::mfPrepare(bool bCheckOverflow)
{
if (bCheckOverflow)
{
gRenDev->FX_CheckOverflow(0, 0, this);
}
gRenDev->m_RP.m_pRE = this;
gRenDev->m_RP.m_RendNumIndices = 0;
gRenDev->m_RP.m_RendNumVerts = 0;
gRenDev->m_RP.m_CurVFormat = eVF_P3F;
}
IVolumeTexture* CREVolumeObject::CreateVolumeTexture() const
{
return new CVolumeTexture();
}
@@ -0,0 +1,97 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "CREWaterOcean.h"
#include "I3DEngine.h"
CREWaterOcean::CREWaterOcean()
: CRendElementBase()
{
mfSetType(eDATA_WaterOcean);
mfUpdateFlags(FCEF_TRANSFORM);
m_nVerticesCount = 0;
m_nIndicesCount = 0;
m_pVertDecl = 0;
m_pVertices = 0;
m_pIndices = 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
CREWaterOcean::~CREWaterOcean()
{
ReleaseOcean();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
void CREWaterOcean::mfGetPlane([[maybe_unused]] Plane& pl)
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
void CREWaterOcean::mfPrepare(bool bCheckOverflow)
{
if (bCheckOverflow)
{
gRenDev->FX_CheckOverflow(0, 0, this);
}
gRenDev->m_RP.m_pRE = this;
gRenDev->m_RP.m_RendNumIndices = 0;
gRenDev->m_RP.m_RendNumVerts = 0;
gRenDev->m_RP.m_CurVFormat = eVF_P3F_C4B_T2F;
FrameUpdate();
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
Vec3 CREWaterOcean ::GetPositionAt(float x, float y) const
{
//assert( m_pWaterSim );
if (WaterSimMgr())
{
return WaterSimMgr()->GetPositionAt((int)x, (int)y);
}
return Vec3(0, 0, 0);
}
Vec4* CREWaterOcean::GetDisplaceGrid() const
{
//assert( m_pWaterSim );
if (WaterSimMgr())
{
return WaterSimMgr()->GetDisplaceGrid();
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
void CREWaterOcean::UpdateFFT()
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -0,0 +1,60 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "CREWaterVolume.h"
CREWaterVolume::CREWaterVolume()
: CRendElementBase()
, m_pParams(0)
, m_pOceanParams(0)
, m_drawWaterSurface(false)
, m_drawFastPath(false)
{
mfSetType(eDATA_WaterVolume);
mfUpdateFlags(FCEF_TRANSFORM);
}
CREWaterVolume::~CREWaterVolume()
{
}
void CREWaterVolume::mfGetPlane(Plane& pl)
{
pl = m_pParams->m_fogPlane;
pl.d = -pl.d;
}
void CREWaterVolume::mfCenter(Vec3& vCenter, CRenderObject* pObj)
{
vCenter = m_pParams->m_center;
if (pObj)
{
vCenter += pObj->GetTranslation();
}
}
void CREWaterVolume::mfPrepare(bool bCheckOverflow)
{
if (bCheckOverflow)
{
gRenDev->FX_CheckOverflow(0, 0, this);
}
gRenDev->m_RP.m_pRE = this;
gRenDev->m_RP.m_RendNumIndices = 0;
gRenDev->m_RP.m_RendNumVerts = 0;
gRenDev->m_RP.m_CurVFormat = eVF_P3F_C4B_T2F;
}
@@ -0,0 +1,406 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "MeshUtil.h"
#include "CameraOrbs.h"
#include "../Textures/Texture.h"
#include "../Textures/TextureManager.h"
#include "../../RenderDll/XRenderD3D9/DriverD3D.h"
class ScreenTile
: public AbstractMeshElement
{
public:
ScreenTile()
{
ValidateMesh();
}
void GenMesh()
{
const int rowCount = 15;
const int colCount = 25;
MeshUtil::GenScreenTile(-1, -1, 1, 1, ColorF(1, 1, 1, 1), rowCount, colCount, m_vertBuf, m_idxBuf);
}
void Draw()
{
ApplyMesh();
gcpRendD3D->FX_Commit();
DrawMeshTriList();
}
};
#if defined(FLARES_SUPPORT_EDITING)
#define MFPtr(FUNC_NAME) (Optics_MFPtr)(&CameraOrbs::FUNC_NAME)
void CameraOrbs::InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups)
{
COpticsElement::InitEditorParamGroups(groups);
FuncVariableGroup camGroup;
camGroup.SetName("CameraOrbs", "Camera Orbs");
camGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Illum range", "Illum range", this, MFPtr(SetIllumRange), MFPtr(GetIllumRange)));
camGroup.AddVariable(new OpticsMFPVariable(e_TEXTURE2D, "Orb Texture", "The texture for orbs", this, MFPtr(SetOrbTex), MFPtr(GetOrbTex)));
camGroup.AddVariable(new OpticsMFPVariable(e_TEXTURE2D, "Lens Texture", "The texture for lens", this, MFPtr(SetLensTex), MFPtr(GetLensTex)));
camGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Enable lens texture", "Enable lens texture", this, MFPtr(SetUseLensTex), MFPtr(GetUseLensTex)));
camGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Enable lens detail shading", "Enable lens detail shading", this, MFPtr(SetEnableLensDetailShading), MFPtr(GetEnableLensDetailShading)));
camGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Lens texture strength", "Lens texture strength", this, MFPtr(SetLensTexStrength), MFPtr(GetLensTexStrength)));
camGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Lens detail shading strength", "Lens detail shading strength", this, MFPtr(SetLensDetailShadingStrength), MFPtr(GetLensDetailShadingStrength)));
camGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Lens detail bumpiness", "Lens detail bumpiness", this, MFPtr(SetLensDetailBumpiness), MFPtr(GetLensDetailBumpiness)));
camGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Enable orb detail shading", "Enable orb detail shading", this, MFPtr(SetEnableOrbDetailShading), MFPtr(GetEnableOrbDetailShading)));
groups.push_back(camGroup);
FuncVariableGroup genGroup;
genGroup.SetName("Generator");
genGroup.AddVariable(new OpticsMFPVariable(e_INT, "Number of orbs", "Number of orbs", this, MFPtr(SetNumOrbs), MFPtr(GetNumOrbs), 0, 1000.0f));
genGroup.AddVariable(new OpticsMFPVariable(e_INT, "Noise seed", "Noise seed", this, MFPtr(SetNoiseSeed), MFPtr(GetNoiseSeed), -255.0f, 255.0f));
genGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Color variation", "Color variation", this, MFPtr(SetColorNoise), MFPtr(GetColorNoise)));
genGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Size variation", "Size variation", this, MFPtr(SetSizeNoise), MFPtr(GetSizeNoise)));
genGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Rotation variation", "Rotation variation", this, MFPtr(SetRotationNoise), MFPtr(GetRotationNoise)));
groups.push_back(genGroup);
FuncVariableGroup advShadingGroup;
advShadingGroup.SetName("AdvancedShading", "Advanced Shading");
advShadingGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Enable adv shading", "Enable advanced shading mode", this, MFPtr(SetEnableAdvancdShading), MFPtr(GetEnableAdvancedShading)));
advShadingGroup.AddVariable(new OpticsMFPVariable(e_COLOR, "Ambient Diffuse", "Ambient diffuse light (RGBK)", this, MFPtr(SetAmbientDiffuseRGBK), MFPtr(GetAmbientDiffuseRGBK)));
advShadingGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Absorptance", "Absorptance of on-lens dirt", this, MFPtr(SetAbsorptance), MFPtr(GetAbsorptance)));
advShadingGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Transparency", "Transparency of on-lens dirt", this, MFPtr(SetTransparency), MFPtr(GetTransparency)));
advShadingGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Scattering", "Subsurface Scattering of on-lens dirt", this, MFPtr(SetScatteringStrength), MFPtr(GetScatteringStrength)));
groups.push_back(advShadingGroup);
}
#undef MFPtr
#endif
void CameraOrbs::Load(IXmlNode* pNode)
{
COpticsElement::Load(pNode);
XmlNodeRef pCameraOrbsNode = pNode->findChild("CameraOrbs");
if (pCameraOrbsNode)
{
float fIllumRadius(m_fIllumRadius);
if (pCameraOrbsNode->getAttr("Illumrange", fIllumRadius))
{
SetIllumRange(fIllumRadius);
}
const char* orbTextureName(NULL);
if (pCameraOrbsNode->getAttr("OrbTexture", &orbTextureName))
{
if (orbTextureName && orbTextureName[0])
{
ITexture* pTexture = gEnv->pRenderer->EF_LoadTexture(orbTextureName);
SetOrbTex((CTexture*)pTexture);
if (pTexture)
{
pTexture->Release();
}
}
}
const char* lensTextureName(NULL);
if (pCameraOrbsNode->getAttr("LensTexture", &lensTextureName))
{
if (lensTextureName && lensTextureName[0])
{
ITexture* pTexture = gEnv->pRenderer->EF_LoadTexture(lensTextureName);
SetLensTex((CTexture*)pTexture);
if (pTexture)
{
pTexture->Release();
}
}
}
bool bUseLensTex(m_bUseLensTex);
if (pCameraOrbsNode->getAttr("Enablelenstexture", bUseLensTex))
{
SetUseLensTex(bUseLensTex);
}
bool bLensDetailShading(m_bLensDetailShading);
if (pCameraOrbsNode->getAttr("Enablelensdetailshading", bLensDetailShading))
{
SetEnableLensDetailShading(bLensDetailShading);
}
float fLensTexStrength(m_fLensTexStrength);
if (pCameraOrbsNode->getAttr("Lenstexturestrength", fLensTexStrength))
{
SetLensTexStrength(fLensTexStrength);
}
float fLensDetailShadingStrength(m_fLensDetailShadingStrength);
if (pCameraOrbsNode->getAttr("Lensdetailshadingstrength", fLensDetailShadingStrength))
{
SetLensDetailShadingStrength(fLensDetailShadingStrength);
}
float fLensDetailBumpiness(m_fLensDetailBumpiness);
if (pCameraOrbsNode->getAttr("Lensdetailbumpiness", fLensDetailBumpiness))
{
SetLensDetailBumpiness(fLensDetailBumpiness);
}
bool bOrbDetailShading(m_bOrbDetailShading);
if (pCameraOrbsNode->getAttr("Enableorbdetailshading", bOrbDetailShading))
{
SetEnableOrbDetailShading(bOrbDetailShading);
}
}
XmlNodeRef pGeneratorNode = pNode->findChild("Generator");
if (pGeneratorNode)
{
int numOfOrbs(m_nNumOrbs);
if (pGeneratorNode->getAttr("Numberoforbs", numOfOrbs))
{
SetNumOrbs(numOfOrbs);
}
int nNoiseSeed(m_iNoiseSeed);
if (pGeneratorNode->getAttr("Noiseseed", nNoiseSeed))
{
SetNoiseSeed(nNoiseSeed);
}
float fColorNoise(m_fClrNoise);
if (pGeneratorNode->getAttr("Colorvariation", fColorNoise))
{
SetColorNoise(fColorNoise);
}
float fSizeNoise(m_fSizeNoise);
if (pGeneratorNode->getAttr("Sizevariation", fSizeNoise))
{
SetSizeNoise(fSizeNoise);
}
float fRotNoise(m_fRotNoise);
if (pGeneratorNode->getAttr("Rotationvariation", fRotNoise))
{
SetRotationNoise(fRotNoise);
}
}
XmlNodeRef pAdvancedShading = pNode->findChild("AdvancedShading");
if (pAdvancedShading)
{
bool bAdvancedShading(m_bAdvancedShading);
if (pAdvancedShading->getAttr("Enableadvshading", bAdvancedShading))
{
SetEnableAdvancdShading(bAdvancedShading);
}
Vec3 vColor(m_cAmbientDiffuse.r, m_cAmbientDiffuse.g, m_cAmbientDiffuse.b);
int nAlpha((int)(m_cAmbientDiffuse.a * 255.0f));
if (pAdvancedShading->getAttr("AmbientDiffuse", vColor) && pAdvancedShading->getAttr("AmbientDiffuse.alpha", nAlpha))
{
SetAmbientDiffuseRGBK(ColorF(vColor.x, vColor.y, vColor.z, (float)nAlpha / 255.0f));
}
float fAbsorptance(m_fAbsorptance);
if (pAdvancedShading->getAttr("Absorptance", fAbsorptance))
{
SetAbsorptance(fAbsorptance);
}
float fTransparency(m_fTransparency);
if (pAdvancedShading->getAttr("Transparency", fTransparency))
{
SetTransparency(fTransparency);
}
float fScatteringStrength(m_fScatteringStrength);
if (pAdvancedShading->getAttr("Scattering", fScatteringStrength))
{
SetScatteringStrength(fScatteringStrength);
}
}
}
void CameraOrbs::GenMesh()
{
ScatterOrbs();
int iTempX, iTempY, iWidth, iHeight;
gcpRendD3D->GetViewport(&iTempX, &iTempY, &iWidth, &iHeight);
MeshUtil::GenSprites(m_OrbsList, iWidth / (float)iHeight, true, m_vertBuf, m_idxBuf);
MeshUtil::TrianglizeQuadIndices(m_OrbsList.size(), m_idxBuf);
}
void CameraOrbs::ScatterOrbs()
{
stable_rand::setSeed(m_iNoiseSeed);
for (uint32 i = 0; i < m_OrbsList.size(); i++)
{
SpritePoint& sprite = m_OrbsList[i];
Vec2& p = sprite.pos;
p.x = stable_rand::randUnit();
p.y = stable_rand::randUnit();
sprite.rotation = m_fRotation * stable_rand::randBias(GetRotationNoise()) * 2 * PI;
sprite.size = m_globalSize * stable_rand::randBias(GetSizeNoise());
sprite.brightness = m_globalFlareBrightness * stable_rand::randBias(GetBrightnessNoise());
ColorF& clr = sprite.color;
ColorF variation(stable_rand::randBias(m_fClrNoise), stable_rand::randBias(m_fClrNoise), stable_rand::randBias(m_fClrNoise));
clr = variation;
float clrMax = clr.Max();
clr /= clrMax;
clr.a = m_globalColor.a;
}
}
CTexture* CameraOrbs::GetOrbTex()
{
if (!m_pOrbTex)
{
m_pOrbTex = CTexture::ForName("EngineAssets/Textures/flares/orb_01.tif", FT_DONT_STREAM, eTF_Unknown);
}
return m_pOrbTex;
}
CTexture* CameraOrbs::GetLensTex()
{
if (!m_pLensTex)
{
m_pLensTex = CTexture::ForName("EngineAssets/Textures/flares/lens_dirtyglass.tif", FT_DONT_STREAM, eTF_Unknown);
}
return m_pLensTex;
}
void CameraOrbs::ApplyOrbFlags([[maybe_unused]] CShader* shader, bool detailShading) const
{
if (detailShading)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE4];
}
}
void CameraOrbs::ApplyLensDetailParams(CShader* shader, float texStength, float detailStrength, float bumpiness) const
{
static CCryNameR lensDetailName("lensDetailParams");
const Vec4 lensDetailParam(texStength, detailStrength, bumpiness, 0);
shader->FXSetPSFloat(lensDetailName, &lensDetailParam, 1);
}
void CameraOrbs::ApplyAdvancedShadingFlag([[maybe_unused]] CShader* shader) const
{
if (m_bAdvancedShading)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE2];
}
}
void CameraOrbs::ApplyAdvancedShadingParams(CShader* shader, const ColorF& ambDiffuseRGBK, float absorptance, float transparency, float scattering) const
{
static CCryNameR ambDiffuseRGBKName("ambientDiffuseRGBK");
static CCryNameR advShadingName("advShadingParams");
static STexState pointTS(FILTER_POINT, true);
CTexture* pAmbTex = CTexture::s_ptexSceneTarget;
pAmbTex->Apply(1, CTexture::GetTexState(pointTS));
const Vec4 ambDiffuseRGBKParam(ambDiffuseRGBK.r, ambDiffuseRGBK.g, ambDiffuseRGBK.b, ambDiffuseRGBK.a);
const Vec4 advShadingParam(absorptance, transparency, scattering, 0);
shader->FXSetPSFloat(ambDiffuseRGBKName, &ambDiffuseRGBKParam, 1);
shader->FXSetPSFloat(advShadingName, &advShadingParam, 1);
}
void CameraOrbs::Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux)
{
static ScreenTile screenTile;
if (!IsVisible())
{
return;
}
PROFILE_LABEL_SCOPE("CameraOrbs");
gRenDev->m_RP.m_FlagsShader_RT = 0;
static CCryNameTSCRC pCameraOrbsTechName("CameraOrbs");
static CCryNameR lightColorName("lightColorInfo");
static STexState bilinearTS(FILTER_LINEAR, true);
bilinearTS.SetBorderColor(0);
bilinearTS.SetClampMode(TADDR_BORDER, TADDR_BORDER, TADDR_BORDER);
vSrcProjPos = computeOrbitPos(vSrcProjPos, m_globalOrbitAngle);
shader->FXSetTechnique(pCameraOrbsTechName);
uint nPass;
shader->FXBegin(&nPass, FEF_DONTSETTEXTURES);
ApplyGeneralFlags(shader);
ApplyAdvancedShadingFlag(shader);
ApplyOcclusionBokehFlag(shader);
ApplyOrbFlags(shader, m_bOrbDetailShading);
shader->FXBeginPass(0);
const float x = computeMovementLocationX(vSrcProjPos);
const float y = computeMovementLocationY(vSrcProjPos);
ApplyCommonVSParams(shader, vSrcWorldPos, vSrcProjPos);
ApplyVSParam_LightProjPos(shader, Vec3(x, y, aux.linearDepth));
const ColorF lightColor = m_globalFlareBrightness * m_globalColor * m_globalColor.a;
const Vec4 lightColorParam(lightColor.r, lightColor.g, lightColor.b, m_fIllumRadius);
shader->FXSetVSFloat(lightColorName, &lightColorParam, 1);
ApplyLensDetailParams(shader, 1, 1, GetLensDetailBumpiness());
if (m_globalOcclusionBokeh)
{
ApplyOcclusionPattern(shader);
}
else
{
CTextureManager::Instance()->GetBlackTexture()->Apply(5, CTexture::GetTexState(bilinearTS));
}
if (m_bAdvancedShading)
{
ApplyAdvancedShadingParams(shader, GetAmbientDiffuseRGBK(), GetAbsorptance(), GetTransparency(), GetScatteringStrength());
}
CTexture* pOrbTex = GetOrbTex() ? GetOrbTex() : CTextureManager::Instance()->GetBlackTexture();
pOrbTex->Apply(0, CTexture::GetTexState(bilinearTS));
ValidateMesh();
ApplyMesh();
DrawMeshTriList();
shader->FXEndPass();
if (m_bUseLensTex)
{
gRenDev->m_RP.m_FlagsShader_RT = 0;
ApplyOrbFlags(shader, m_bLensDetailShading);
shader->FXBeginPass(1);
if (m_bAdvancedShading)
{
ApplyAdvancedShadingParams(shader, GetAmbientDiffuseRGBK(), GetAbsorptance(), GetTransparency(), GetScatteringStrength());
}
ApplyLensDetailParams(shader, GetLensTexStrength(), GetLensDetailShadingStrength(), GetLensDetailBumpiness());
CTexture* pLensTex = GetLensTex() ? GetLensTex() : CTextureManager::Instance()->GetBlackTexture();
pLensTex->Apply(2, CTexture::GetTexState(bilinearTS));
screenTile.Draw();
shader->FXEndPass();
}
shader->FXEnd();
}
@@ -0,0 +1,225 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CAMERAORBS_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CAMERAORBS_H
#pragma once
#include "OpticsElement.h"
#include "AbstractMeshElement.h"
class CTexture;
class CameraOrbs
: public COpticsElement
, public AbstractMeshElement
{
private:
_smart_ptr<CTexture> m_pOrbTex;
_smart_ptr<CTexture> m_pLensTex;
bool m_bUseLensTex : 1;
bool m_bOrbDetailShading : 1;
bool m_bLensDetailShading : 1;
float m_fLensTexStrength;
float m_fLensDetailShadingStrength;
float m_fLensDetailBumpiness;
bool m_bAdvancedShading : 1;
ColorF m_cAmbientDiffuse;
float m_fAbsorptance;
float m_fTransparency;
float m_fScatteringStrength;
int m_nNumOrbs;
float m_fIllumRadius;
float m_fRotation;
unsigned int m_iNoiseSeed;
float m_fSizeNoise;
float m_fBrightnessNoise;
float m_fRotNoise;
float m_fClrNoise;
std::vector<SpritePoint> m_OrbsList;
static const int MAX_ORBS_NUMBER = 10000;
protected:
#if defined(FLARES_SUPPORT_EDITING)
void InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups);
#endif
void GenMesh();
void DrawMesh(uint32 vOffset, uint32 iOffset);
void Invalidate()
{
m_meshDirty = true;
}
public:
CameraOrbs (const char* name, const int numOrbs = 100)
: COpticsElement(name, 0.19f)
, m_fSizeNoise(0.8f)
, m_fBrightnessNoise(0.4f)
, m_fRotNoise(0.8f)
, m_fClrNoise(0.5f)
, m_fIllumRadius(1.f)
, m_bUseLensTex(0)
, m_bOrbDetailShading(0)
, m_bLensDetailShading(0)
, m_fLensTexStrength(1.f)
, m_fLensDetailShadingStrength(0.157f)
, m_fLensDetailBumpiness(0.073f)
, m_bAdvancedShading(false)
, m_cAmbientDiffuse(LensOpConst::_LO_DEF_CLR_BLK)
, m_fAbsorptance(4.0f)
, m_fTransparency(0.37f)
, m_fScatteringStrength(1.0f)
, m_iNoiseSeed(0)
{
m_Color.a = 1.f;
SetPerspectiveFactor(0.f);
SetRotation(0.7f);
SetNumOrbs(numOrbs);
m_meshDirty = true;
}
protected:
void ApplyOrbFlags(CShader* shader, bool detailShading) const;
void ApplyLensDetailParams(CShader* shader, float texStength, float detailStrength, float bumpiness) const;
void ApplyAdvancedShadingFlag(CShader* shader) const;
void ApplyAdvancedShadingParams(CShader* shader, const ColorF& ambDiffuseRGBK, float absorptance, float transparency, float scattering) const;
public:
void ScatterOrbs();
int GetNumOrbs() const { return m_OrbsList.size(); }
void SetNumOrbs(int n)
{
n = clamp_tpl<int>(n, 0, MAX_ORBS_NUMBER);
if (n != m_nNumOrbs)
{
m_nNumOrbs = n;
if (m_nNumOrbs > 0)
{
m_OrbsList.resize(m_nNumOrbs);
}
m_meshDirty = true;
}
}
EFlareType GetType() { return eFT_CameraOrbs; }
void PreRender([[maybe_unused]] CShader* shader, [[maybe_unused]] Vec3 vSrcWorldPos, [[maybe_unused]] Vec3 vSrcProjPos, [[maybe_unused]] SAuxParams& aux){}
void Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux);
void PostRender([[maybe_unused]] CShader* shader, [[maybe_unused]] Vec3 vSrcWorldPos, [[maybe_unused]] Vec3 vSrcProjPos, [[maybe_unused]] SAuxParams& aux){}
void Load(IXmlNode* pNode);
CTexture* GetOrbTex();
CTexture* GetLensTex();
void SetOrbTex(CTexture* tex) { m_pOrbTex = tex; }
void SetLensTex(CTexture* tex) { m_pLensTex = tex; }
void SetUseLensTex(bool b) { m_bUseLensTex = b; }
bool GetUseLensTex() { return m_bUseLensTex; }
void SetEnableOrbDetailShading(bool b) { m_bOrbDetailShading = b; }
bool GetEnableOrbDetailShading() { return m_bOrbDetailShading; }
void SetEnableLensDetailShading(bool b) { m_bLensDetailShading = b; }
bool GetEnableLensDetailShading() { return m_bLensDetailShading; }
void SetSize(float s)
{
COpticsElement::SetSize(s);
m_meshDirty = true;
}
float GetLensTexStrength() const { return m_fLensTexStrength; }
void SetLensTexStrength(float strength) { m_fLensTexStrength = strength; }
float GetLensDetailShadingStrength() const { return m_fLensDetailShadingStrength; }
void SetLensDetailShadingStrength(float strength) { m_fLensDetailShadingStrength = strength; }
float GetLensDetailBumpiness() const { return m_fLensDetailBumpiness; }
void SetLensDetailBumpiness(float bumpiness) { m_fLensDetailBumpiness = bumpiness; }
float GetRotation() { return m_fRotation; }
void SetRotation(float rot)
{
m_fRotation = rot;
m_meshDirty = true;
}
int GetNoiseSeed() const { return m_iNoiseSeed; }
void SetNoiseSeed(int s)
{
m_iNoiseSeed = s;
m_meshDirty = true;
}
float GetSizeNoise() { return m_fSizeNoise; }
void SetSizeNoise(float s)
{
m_fSizeNoise = s;
m_meshDirty = true;
}
float GetBrightnessNoise() { return m_fBrightnessNoise; }
void SetBrightnessNoise(float b)
{
m_fBrightnessNoise = b;
m_meshDirty = true;
}
float GetRotationNoise() { return m_fRotNoise; }
void SetRotationNoise(float r)
{
m_fRotNoise = r;
m_meshDirty = true;
}
float GetColorNoise() { return m_fClrNoise; }
void SetColorNoise(float clrNoise)
{
m_fClrNoise = clrNoise;
m_meshDirty = true;
}
float GetIllumRange() { return m_fIllumRadius; }
void SetIllumRange(float range)
{
m_fIllumRadius = range;
}
bool GetEnableAdvancedShading() const { return m_bAdvancedShading; }
void SetEnableAdvancdShading(bool b) { m_bAdvancedShading = b; }
ColorF GetAmbientDiffuseRGBK() const { return m_cAmbientDiffuse; }
void SetAmbientDiffuseRGBK(ColorF amb) { m_cAmbientDiffuse = amb; }
float GetAbsorptance() const { return m_fAbsorptance; }
void SetAbsorptance(float a) { m_fAbsorptance = a; }
float GetTransparency() const { return m_fTransparency; }
void SetTransparency(float t) { m_fTransparency = t; }
float GetScatteringStrength() const { return m_fScatteringStrength; }
void SetScatteringStrength(float s) { m_fScatteringStrength = s; }
void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this) + GetMeshDataSize());
}
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CAMERAORBS_H
@@ -0,0 +1,198 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "ChromaticRing.h"
#include "../Textures/Texture.h"
#include "../CryNameR.h"
#include "../../RenderDll/XRenderD3D9/DriverD3D.h"
#if defined(FLARES_SUPPORT_EDITING)
#define MFPtr(FUNC_NAME) (Optics_MFPtr)(&ChromaticRing::FUNC_NAME)
void ChromaticRing::InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups)
{
COpticsElement::InitEditorParamGroups(groups);
FuncVariableGroup crGroup;
crGroup.SetName("ChromaticRing", "Chromatic Ring");
crGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Lock to light", "Lock to light", this, MFPtr(SetLockMovement), MFPtr(IsLockMovement)));
crGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Thickness", "Thickness", this, MFPtr(SetWidth), MFPtr(GetWidth)));
crGroup.AddVariable(new OpticsMFPVariable(e_INT, "Polygon complexity", "Polygon complexity", this, MFPtr(SetPolyComplexity), MFPtr(GetPolyComplexity), 0, 1024.0f));
crGroup.AddVariable(new OpticsMFPVariable(e_TEXTURE2D, "Gradient Texture", "Gradient Texture", this, MFPtr(SetSpectrumTex), MFPtr(GetSpectrumTex)));
crGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Enable Gradient Texture", "Enable Gradient Texture", this, MFPtr(SetUsingSpectrumTex), MFPtr(IsUsingSpectrumTex)));
crGroup.AddVariable(new OpticsMFPVariable(e_INT, "Noise seed", "Noise seed", this, MFPtr(SetNoiseSeed), MFPtr(GetNoiseSeed), -255.0f, 255.0f));
crGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Noise strength", "Noise strength", this, MFPtr(SetNoiseStrength), MFPtr(GetNoiseStrength)));
crGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Completion fading", "the fading ratio at the ends of this arc", this, MFPtr(SetCompletionFading), MFPtr(GetCompletionFading)));
crGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Completion span angle", "The span of this arc in degree", this, MFPtr(SetCompletionSpanAngle), MFPtr(GetCompletionSpanAngle)));
crGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Completion rotation", "The rotation of this arc", this, MFPtr(SetCompletionRotation), MFPtr(GetCompletionRotation)));
groups.push_back(crGroup);
}
#undef MFPtr
#endif
void ChromaticRing::Load(IXmlNode* pNode)
{
COpticsElement::Load(pNode);
XmlNodeRef pCameraOrbsNode = pNode->findChild("ChromaticRing");
if (pCameraOrbsNode)
{
bool bLockMovement(m_bLockMovement);
if (pCameraOrbsNode->getAttr("Locktolight", bLockMovement))
{
SetLockMovement(bLockMovement);
}
float fWidth(m_fWidth);
if (pCameraOrbsNode->getAttr("Thickness", fWidth))
{
SetWidth(fWidth);
}
int nPolyComplexity(m_nPolyComplexity);
if (pCameraOrbsNode->getAttr("Polygoncomplexity", nPolyComplexity))
{
SetPolyComplexity(nPolyComplexity);
}
const char* gradientTexName = NULL;
if (pCameraOrbsNode->getAttr("GradientTexture", &gradientTexName))
{
if (gradientTexName && gradientTexName[0])
{
ITexture* pTexture = gEnv->pRenderer->EF_LoadTexture(gradientTexName);
SetSpectrumTex((CTexture*)pTexture);
if (pTexture)
{
pTexture->Release();
}
}
}
bool bUseSpectrumTex(m_bUseSpectrumTex);
if (pCameraOrbsNode->getAttr("EnableGradientTexture", bUseSpectrumTex))
{
SetUsingSpectrumTex(bUseSpectrumTex);
}
int nNoiseSeed(m_nNoiseSeed);
if (pCameraOrbsNode->getAttr("Noiseseed", nNoiseSeed))
{
SetNoiseSeed(nNoiseSeed);
}
float fNoiseStrength(m_fNoiseStrength);
if (pCameraOrbsNode->getAttr("Noisestrength", fNoiseStrength))
{
SetNoiseStrength(fNoiseStrength);
}
float fCompletionFading(m_fCompletionFading);
if (pCameraOrbsNode->getAttr("Completionfading", fCompletionFading))
{
SetCompletionFading(fCompletionFading);
}
float fTotalAngle(0);
if (pCameraOrbsNode->getAttr("Completionspanangle", fTotalAngle))
{
SetCompletionSpanAngle(fTotalAngle);
}
float fCompletionRotation(0);
if (pCameraOrbsNode->getAttr("Completionrotation", fCompletionRotation))
{
SetCompletionRotation(fCompletionRotation);
}
}
}
void ChromaticRing::DrawMesh()
{
gcpRendD3D->FX_Commit();
DrawMeshTriList();
DrawMeshWireframe();
}
float ChromaticRing::computeDynamicSize(const Vec3& vSrcProjPos, const float maxSize)
{
Vec2 dir(vSrcProjPos.x - 0.5f, vSrcProjPos.y - 0.5f);
float len = dir.GetLength();
const float hoopDistFactor = 2.3f;
return len * hoopDistFactor * maxSize;
}
void ChromaticRing::Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, [[maybe_unused]] SAuxParams& aux)
{
if (!IsVisible())
{
return;
}
PROFILE_LABEL_SCOPE("ChromaticRing");
gRenDev->m_RP.m_FlagsShader_RT = 0;
vSrcProjPos = computeOrbitPos(vSrcProjPos, m_globalOrbitAngle);
static CCryNameTSCRC pChromaticRingTechName("ChromaticRing");
shader->FXSetTechnique(pChromaticRingTechName);
uint nPass;
shader->FXBegin(&nPass, FEF_DONTSETTEXTURES);
ApplyGeneralFlags(shader);
ApplySpectrumTexFlag(shader, m_bUseSpectrumTex);
shader->FXBeginPass(0);
float newSize = computeDynamicSize(vSrcProjPos, m_globalSize);
float oldSize = m_globalSize;
m_globalSize = newSize;
ApplyCommonVSParams(shader, vSrcWorldPos, vSrcProjPos);
m_globalSize = oldSize;
ApplyExternTintAndBrightnessVS(shader, m_globalColor, m_globalFlareBrightness);
static CCryNameR meshCenterName("meshCenterAndBrt");
float x, y;
if (m_bLockMovement)
{
x = vSrcProjPos.x;
y = vSrcProjPos.y;
}
else
{
x = computeMovementLocationX(vSrcProjPos);
y = computeMovementLocationY(vSrcProjPos);
}
const Vec4 meshCenterParam(x, y, vSrcProjPos.z, m_globalFlareBrightness);
shader->FXSetVSFloat(meshCenterName, &meshCenterParam, 1);
static STexState bilinearTS(FILTER_LINEAR, true);
bilinearTS.SetBorderColor(0);
bilinearTS.SetClampMode(TADDR_BORDER, TADDR_BORDER, TADDR_BORDER);
if (m_pSpectrumTex == NULL)
{
m_pSpectrumTex = CTexture::ForName("EngineAssets/Textures/flares/spectrum_full.tif", FT_DONT_STREAM, eTF_Unknown);
}
m_pSpectrumTex->Apply(0, CTexture::GetTexState(bilinearTS));
ValidateMesh();
ApplyMesh();
DrawMesh();
shader->FXEndPass();
shader->FXEnd();
}
@@ -0,0 +1,197 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CHROMATICRING_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CHROMATICRING_H
#pragma once
#include "OpticsElement.h"
#include "AbstractMeshElement.h"
#include "MeshUtil.h"
class CTexture;
class ChromaticRing
: public COpticsElement
, public AbstractMeshElement
{
private:
bool m_bLockMovement : 1;
_smart_ptr<CTexture> m_pSpectrumTex;
bool m_bUseSpectrumTex : 1;
int m_nPolyComplexity;
int m_nColorComplexity;
float m_fWidth;
float m_fNoiseStrength;
int m_nNoiseSeed;
float m_fCompletionStart;
float m_fCompletionEnd;
float m_fCompletionFading;
protected:
#if defined(FLARES_SUPPORT_EDITING)
void InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups);
#endif
void GenMesh()
{
ColorF c(1, 1, 1, 1);
int polyComplexity(m_nPolyComplexity);
if (CRenderer::CV_r_FlaresTessellationRatio < 1 && CRenderer::CV_r_FlaresTessellationRatio > 0)
{
polyComplexity = (int)((float)m_nPolyComplexity * CRenderer::CV_r_FlaresTessellationRatio);
}
MeshUtil::GenHoop(
m_fSize, polyComplexity, m_fWidth, 2, c,
m_fNoiseStrength * m_fSize, m_nNoiseSeed, m_fCompletionStart, m_fCompletionEnd, m_fCompletionFading,
m_vertBuf, m_idxBuf);
}
void DrawMesh();
void Invalidate()
{
m_meshDirty = true;
}
static float computeDynamicSize(const Vec3& vSrcProjPos, const float maxSize);
public:
ChromaticRing(const char* name)
: COpticsElement(name)
, m_bUseSpectrumTex(false)
, m_fWidth(0.5f)
, m_nPolyComplexity(160)
, m_nColorComplexity(2)
, m_fNoiseStrength(0.0f)
, m_fCompletionStart(90.f)
, m_fCompletionEnd(270.f)
, m_fCompletionFading(45.f)
{
SetSize(0.9f);
SetAutoRotation(true);
SetAspectRatioCorrection(false);
m_meshDirty = true;
}
EFlareType GetType() { return eFT_ChromaticRing; }
void Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux);
void Load(IXmlNode* pNode);
void SetSize(float s)
{
COpticsElement::SetSize(s);
m_meshDirty = true;
}
bool IsLockMovement() const { return m_bLockMovement; }
void SetLockMovement(bool b) { m_bLockMovement = b; }
int GetPolyComplexity() { return m_nPolyComplexity; }
void SetPolyComplexity(int polyCplx)
{
if (polyCplx <= 0)
{
polyCplx = 1;
}
else if (polyCplx > 1024)
{
polyCplx = 1024;
}
m_nPolyComplexity = polyCplx;
m_meshDirty = true;
}
int GetColorComplexity() { return m_nColorComplexity; }
void SetColorComplexity(int clrCplx)
{
if (clrCplx <= 0)
{
clrCplx = 1;
}
m_nColorComplexity = clrCplx;
m_meshDirty = true;
}
CTexture* GetSpectrumTex() { return m_pSpectrumTex; }
void SetSpectrumTex(CTexture* tex)
{
m_pSpectrumTex = tex;
}
bool IsUsingSpectrumTex() { return m_bUseSpectrumTex; }
void SetUsingSpectrumTex(bool b)
{
m_bUseSpectrumTex = b;
}
int GetNoiseSeed() { return m_nNoiseSeed; }
void SetNoiseSeed(int seed)
{
m_nNoiseSeed = seed;
m_meshDirty = true;
}
float GetWidth() { return m_fWidth; }
void SetWidth(float w)
{
m_fWidth = w;
m_meshDirty = true;
}
float GetNoiseStrength() { return m_fNoiseStrength; }
void SetNoiseStrength(float noise)
{
m_fNoiseStrength = noise;
m_meshDirty = true;
}
float GetCompletionFading() { return m_fCompletionFading; }
void SetCompletionFading(float f)
{
m_fCompletionFading = f;
m_meshDirty = true;
}
float GetCompletionSpanAngle() { return (m_fCompletionEnd - m_fCompletionStart); }
void SetCompletionSpanAngle(float totalAngle)
{
float rotAngle = GetCompletionRotation();
float halfTotalAngle = totalAngle / 2;
m_fCompletionStart = rotAngle - halfTotalAngle;
m_fCompletionEnd = rotAngle + halfTotalAngle;
m_meshDirty = true;
}
float GetCompletionRotation() { return (m_fCompletionStart + m_fCompletionEnd) * 0.5f; }
void SetCompletionRotation(float rot)
{
float oldRotAngle = GetCompletionRotation();
float rotDiff = rot - oldRotAngle;
m_fCompletionStart += rotDiff;
m_fCompletionEnd += rotDiff;
m_meshDirty = true;
}
void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this) + GetMeshDataSize());
}
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_CHROMATICRING_H
@@ -0,0 +1,444 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "FlareSoftOcclusionQuery.h"
#include "../CryNameR.h"
#include "../../XRenderD3D9/DriverD3D.h"
#include "../Textures/Texture.h"
#include "I3DEngine.h"
unsigned char CFlareSoftOcclusionQuery::s_paletteRawCache[s_nIDMax * 4];
char CFlareSoftOcclusionQuery::s_idHashTable[s_nIDMax];
int CFlareSoftOcclusionQuery::s_idCount = 0;
int CFlareSoftOcclusionQuery::s_ringReadIdx = 1;
int CFlareSoftOcclusionQuery::s_ringWriteIdx = 0;
int CFlareSoftOcclusionQuery::s_ringSize = MAX_OCCLUSION_READBACK_TEXTURES;
static bool g_bCreatedGlobalResources = false;
const float CFlareSoftOcclusionQuery::s_fSectorWidth = (float)s_nGatherEachSectorWidth / (float)s_nGatherTextureWidth;
const float CFlareSoftOcclusionQuery::s_fSectorHeight = (float)s_nGatherEachSectorHeight / (float)s_nGatherTextureHeight;
float CSoftOcclusionVisiblityFader::UpdateVisibility(const float newTargetVisibility, const float duration)
{
m_TimeLine.duration = duration;
if (fabs(newTargetVisibility - m_fTargetVisibility) > 0.1f)
{
m_TimeLine.startValue = m_TimeLine.GetPrevYValue();
m_fTargetVisibility = newTargetVisibility;
m_TimeLine.rewind();
}
else if (newTargetVisibility < 0.05f)
{
m_fTargetVisibility = newTargetVisibility;
m_TimeLine.endValue = newTargetVisibility;
}
else
{
m_TimeLine.endValue = m_fTargetVisibility;
}
// Fade in fixed time (in ms), fade out user controlled
const float fadeInTime = m_TimeLine.duration * (1.0f / 0.15f);
const float fadeOutTime = 1e3f;
float dt = (newTargetVisibility > m_fVisibilityFactor) ? fadeInTime : fadeOutTime;
m_fVisibilityFactor = m_TimeLine.step(gEnv->pTimer->GetFrameTime() * dt); // interpolate
return m_fVisibilityFactor;
}
void ReportIDPoolOverflow(int idCount, int idMax)
{
iLog->Log("Number of soft occlusion queries [%d] exceeds current allowed range %d", idCount, idMax);
}
int CFlareSoftOcclusionQuery::GenID()
{
int hashCode = s_idCount % s_nIDMax;
while (hashCode < s_nIDMax && s_idHashTable[hashCode])
{
hashCode++;
}
if (hashCode >= s_nIDMax)
{
ReportIDPoolOverflow(s_idCount + 1, s_nIDMax);
hashCode = 0;
}
s_idHashTable[hashCode] = (char)1;
s_idCount++;
return hashCode;
}
void CFlareSoftOcclusionQuery::ReleaseID(int id)
{
if (id < s_nIDMax)
{
s_idHashTable[id] = (char)0;
}
}
void CFlareSoftOcclusionQuery::InitGlobalResources()
{
if (g_bCreatedGlobalResources)
{
return;
}
const uint32 numGPUs = (gRenDev->GetActiveGPUCount() <= MAX_OCCLUSION_READBACK_TEXTURES / 2) ? gRenDev->GetActiveGPUCount() : 1;
s_ringWriteIdx = 0;
s_ringReadIdx = numGPUs;
s_ringSize = MAX_OCCLUSION_READBACK_TEXTURES;
memset(s_idHashTable, 0, sizeof(s_idHashTable));
memset(s_paletteRawCache, 0, sizeof(s_paletteRawCache));
g_bCreatedGlobalResources = true;
}
void CFlareSoftOcclusionQuery::GetDomainInTexture(float& out_x0, float& out_y0, float& out_x1, float& out_y1)
{
out_x0 = (m_nID % s_nIDColMax) * s_fSectorWidth;
out_y0 = (m_nID / s_nIDColMax) * s_fSectorHeight;
out_x1 = out_x0 + s_fSectorWidth;
out_y1 = out_y0 + s_fSectorHeight;
}
bool CFlareSoftOcclusionQuery::ComputeProjPos(const Vec3& vWorldPos, const Matrix44A& viewMat, const Matrix44A& projMat, Vec3& outProjPos)
{
static int vp[] = {0, 0, 1, 1};
if (mathVec3Project(&outProjPos, &vWorldPos, vp, &projMat, &viewMat, &gRenDev->m_IdentityMatrix) == 0.0f)
{
return false;
}
return true;
}
void CFlareSoftOcclusionQuery::GetSectorSize(float& width, float& height)
{
width = s_fSectorWidth;
height = s_fSectorWidth;
}
void CFlareSoftOcclusionQuery::GetOcclusionSectorInfo(SOcclusionSectorInfo& out_Info)
{
Vec3 vProjectedPos;
if (ComputeProjPos(m_PosToBeChecked, gRenDev->m_ViewMatrix, gRenDev->m_ProjMatrix, vProjectedPos) == false)
{
return;
}
out_Info.lineardepth = clamp_tpl(ComputeLinearDepth(m_PosToBeChecked, gRenDev->m_CameraMatrix, gRenDev->GetViewParameters().fNear, gRenDev->GetViewParameters().fFar), -1.0f, 0.99f);
out_Info.u0 = vProjectedPos.x - m_fOccPlaneWidth / 2;
out_Info.v0 = vProjectedPos.y - m_fOccPlaneHeight / 2;
out_Info.u1 = vProjectedPos.x + m_fOccPlaneWidth / 2;
out_Info.v1 = vProjectedPos.y + m_fOccPlaneHeight / 2;
if (out_Info.u0 < 0)
{
out_Info.u0 = 0;
}
if (out_Info.v0 < 0)
{
out_Info.v0 = 0;
}
if (out_Info.u1 > 1)
{
out_Info.u1 = 1;
}
if (out_Info.v1 > 1)
{
out_Info.v1 = 1;
}
GetDomainInTexture(out_Info.x0, out_Info.y0, out_Info.x1, out_Info.y1);
out_Info.x0 = out_Info.x0 * 2.0f - 1;
out_Info.y0 = -(out_Info.y0 * 2.0f - 1.0f);
out_Info.x1 = out_Info.x1 * 2.0f - 1;
out_Info.y1 = -(out_Info.y1 * 2.0f - 1.0f);
}
float CFlareSoftOcclusionQuery::ComputeLinearDepth(const Vec3& worldPos, const Matrix44A& cameraMat, float nearDist, float farDist)
{
Vec4 out, wPos4;
wPos4.x = worldPos.x;
wPos4.y = worldPos.y;
wPos4.z = worldPos.z;
wPos4.w = 1;
mathVec4Transform((f32*)&out, (f32*)(&cameraMat), (f32*)&wPos4);
if (out.w == 0.0f)
{
return 0;
}
const CameraViewParameters& rc = gRenDev->GetViewParameters();
float linearDepth = (-out.z - rc.fNear) / (farDist - nearDist);
return linearDepth;
}
void CFlareSoftOcclusionQuery::UpdateCachedResults()
{
int cacheIdx = 4 * m_nID;
m_fOccResultCache = s_paletteRawCache[cacheIdx + 0] / 255.0f;
m_fDirResultCache = (s_paletteRawCache[cacheIdx + 3] / 255.0f) * 2.0f * PI;
sincos_tpl(m_fDirResultCache, &m_DirVecResultCache.y, &m_DirVecResultCache.x);
}
CTexture* CFlareSoftOcclusionQuery::GetGatherTexture() const
{
return CTexture::s_ptexFlaresGather;
}
void CFlareSoftOcclusionQuery::BatchReadResults()
{
if (!g_bCreatedGlobalResources)
{
return;
}
CTexture::s_ptexFlaresOcclusionRing[s_ringWriteIdx]->GetDevTexture()->AccessCurrStagingResource(0, false, [=](void* pData, uint32 rowPitch, [[maybe_unused]] uint32 slicePitch)
{
unsigned char* pTexBuf = reinterpret_cast<unsigned char*>(pData);
int validLineStrideBytes = s_nIDColMax * 4;
for (int i = 0; i < s_nIDRowMax; i++)
{
memcpy(s_paletteRawCache + i * validLineStrideBytes, pTexBuf + i * rowPitch, validLineStrideBytes);
}
return true;
});
}
void CFlareSoftOcclusionQuery::ReadbackSoftOcclQuery()
{
CTexture::s_ptexFlaresOcclusionRing[s_ringWriteIdx]->GetDevTexture()->DownloadToStagingResource(0);
// sync point. Move to next texture to read and write
s_ringReadIdx = (s_ringReadIdx + 1) % s_ringSize;
s_ringWriteIdx = (s_ringWriteIdx + 1) % s_ringSize;
}
CTexture* CFlareSoftOcclusionQuery::GetOcclusionTex()
{
return CTexture::s_ptexFlaresOcclusionRing[s_ringWriteIdx];
}
void CSoftOcclusionManager::ComputeVisibility()
{
static STexState ShadowTexState(FILTER_POINT, TADDR_BORDER, TADDR_BORDER, TADDR_BORDER, 0);
CShader* pShader = CShaderMan::s_ShaderSoftOcclusionQuery;
gcpRendD3D->FX_ClearTarget(CTexture::s_ptexFlaresGather, Clr_Transparent);
gcpRendD3D->FX_PushRenderTarget(0, CTexture::s_ptexFlaresGather, NULL);
pShader->FXBeginPass(0);
const uint32 vertexCount = GetSize() * 4;
TempDynVB<SVF_P3F_C4B_T2F> vb(gcpRendD3D);
vb.Allocate(vertexCount);
SVF_P3F_C4B_T2F* pDeviceVBAddr = vb.Lock();
for (int i(0), iSoftOcclusionListSize(GetSize()); i < iSoftOcclusionListSize; ++i)
{
CFlareSoftOcclusionQuery* pSoftOcclusion = GetSoftOcclusionQuery(i);
if (pSoftOcclusion == NULL)
{
continue;
}
int offset = i * 4;
CFlareSoftOcclusionQuery::SOcclusionSectorInfo sInfo;
pSoftOcclusion->GetOcclusionSectorInfo(sInfo);
for (int k = 0; k < 4; ++k)
{
pDeviceVBAddr[offset + k].color.dcolor = 0xFFFFFFFF;
}
pDeviceVBAddr[offset + 0].st = Vec2(sInfo.u0 * gcpRendD3D->m_CurViewportScale.x, sInfo.v0 * gcpRendD3D->m_CurViewportScale.y);
pDeviceVBAddr[offset + 1].st = Vec2(sInfo.u1 * gcpRendD3D->m_CurViewportScale.x, sInfo.v0 * gcpRendD3D->m_CurViewportScale.y);
pDeviceVBAddr[offset + 2].st = Vec2(sInfo.u1 * gcpRendD3D->m_CurViewportScale.x, sInfo.v1 * gcpRendD3D->m_CurViewportScale.y);
pDeviceVBAddr[offset + 3].st = Vec2(sInfo.u0 * gcpRendD3D->m_CurViewportScale.x, sInfo.v1 * gcpRendD3D->m_CurViewportScale.y);
pDeviceVBAddr[offset + 0].xyz = Vec3(sInfo.x0, sInfo.y1, sInfo.lineardepth);
pDeviceVBAddr[offset + 1].xyz = Vec3(sInfo.x1, sInfo.y1, sInfo.lineardepth);
pDeviceVBAddr[offset + 2].xyz = Vec3(sInfo.x1, sInfo.y0, sInfo.lineardepth);
pDeviceVBAddr[offset + 3].xyz = Vec3(sInfo.x0, sInfo.y0, sInfo.lineardepth);
}
vb.Unlock();
vb.Bind(0);
vb.Release();
if (pDeviceVBAddr && m_bSuccessGenerateIB)
{
CTexture::s_ptexZTargetScaled->Apply(0, CTexture::GetTexState(ShadowTexState));
gcpRendD3D->FX_Commit();
if (SUCCEEDED(gcpRendD3D->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F)))
{
gcpRendD3D->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, vertexCount, 0, m_IndexBufferCount);
}
}
pShader->FXEndPass();
gcpRendD3D->FX_PopRenderTarget(0);
}
bool CSoftOcclusionManager::GenerateIndexBuffer()
{
m_IndexBufferCount = GetSize() * 2 * 3;
if (m_IndexBufferCount <= 0)
{
return false;
}
TempDynIB16 ib(gcpRendD3D);
ib.Allocate(m_IndexBufferCount);
uint16* pDeviceIBAddr = ib.Lock();
for (int i(0), iSoftOcclusionListSize(GetSize()); i < iSoftOcclusionListSize; ++i)
{
CFlareSoftOcclusionQuery* pSoftOcclusion = GetSoftOcclusionQuery(i);
if (pSoftOcclusion == NULL)
{
continue;
}
int offset0 = i * 6;
int offset1 = i * 4;
pDeviceIBAddr[offset0 + 0] = offset1 + 0;
pDeviceIBAddr[offset0 + 1] = offset1 + 1;
pDeviceIBAddr[offset0 + 2] = offset1 + 2;
pDeviceIBAddr[offset0 + 3] = offset1 + 2;
pDeviceIBAddr[offset0 + 4] = offset1 + 3;
pDeviceIBAddr[offset0 + 5] = offset1 + 0;
}
ib.Unlock();
m_IndexBufferOffset = 0;
ib.Bind();
ib.Release();
return true;
}
void CSoftOcclusionManager::GatherOcclusions()
{
CShader* pShader = CShaderMan::s_ShaderSoftOcclusionQuery;
static STexState GatherTexState(FILTER_POINT, true);
gcpRendD3D->FX_ClearTarget(CFlareSoftOcclusionQuery::GetOcclusionTex(), Clr_Transparent);
gcpRendD3D->FX_PushRenderTarget(0, CFlareSoftOcclusionQuery::GetOcclusionTex(), NULL);
pShader->FXBeginPass(1);
float x0 = 0, y0 = 0, x1 = 0, y1 = 0;
const uint32 vertexCount = GetSize() * 4;
TempDynVB<SVF_P3F_C4B_T2F> vb(gcpRendD3D);
vb.Allocate(vertexCount);
SVF_P3F_C4B_T2F* pDeviceVBAddr = vb.Lock();
for (int i = 0, iSoftOcclusionListSize(GetSize()); i < iSoftOcclusionListSize; ++i)
{
CFlareSoftOcclusionQuery* pSoftOcclusion = GetSoftOcclusionQuery(i);
if (pSoftOcclusion == NULL)
{
continue;
}
int offset = i * 4;
pSoftOcclusion->GetDomainInTexture(x0, y0, x1, y1);
for (int k = 0; k < 4; ++k)
{
pDeviceVBAddr[offset + k].st = Vec2((x0 + x1) * 0.5f * gcpRendD3D->m_CurViewportScale.x, (y0 + y1) * 0.5f * gcpRendD3D->m_CurViewportScale.y);
pDeviceVBAddr[offset + k].color.dcolor = 0xFFFFFFFF;
}
x0 = x0 * 2.0f - 1.0f;
y0 = -(y0 * 2.0f - 1.0f);
x1 = x1 * 2.0f - 1.0f;
y1 = -(y1 * 2.0f - 1.0f);
pDeviceVBAddr[offset + 0].xyz = Vec3(x0, y1, 1);
pDeviceVBAddr[offset + 1].xyz = Vec3(x1, y1, 1);
pDeviceVBAddr[offset + 2].xyz = Vec3(x1, y0, 1);
pDeviceVBAddr[offset + 3].xyz = Vec3(x0, y0, 1);
}
vb.Unlock();
vb.Bind(0);
vb.Release();
if (pDeviceVBAddr && m_bSuccessGenerateIB)
{
static CCryNameR occlusionNormalizedSizeName("occlusionNormalizedSize");
const Vec4 occlusionSizeParam(CFlareSoftOcclusionQuery::s_fSectorWidth, CFlareSoftOcclusionQuery::s_fSectorHeight, 0, 0);
pShader->FXSetPSFloat(occlusionNormalizedSizeName, &occlusionSizeParam, 1);
CTexture::s_ptexFlaresGather->Apply(0, CTexture::GetTexState(GatherTexState));
gcpRendD3D->FX_Commit();
if (SUCCEEDED(gcpRendD3D->FX_SetVertexDeclaration(0, eVF_P3F_C4B_T2F)))
{
gcpRendD3D->FX_DrawIndexedPrimitive(eptTriangleList, 0, 0, vertexCount, 0, m_IndexBufferCount);
}
}
pShader->FXEndPass();
gcpRendD3D->FX_PopRenderTarget(0);
}
CFlareSoftOcclusionQuery* CSoftOcclusionManager::GetSoftOcclusionQuery(int nIndex) const
{
if (nIndex >= CFlareSoftOcclusionQuery::s_nIDMax)
{
return NULL;
}
return m_SoftOcclusionQueries[nIndex];
}
void CSoftOcclusionManager::AddSoftOcclusionQuery(CFlareSoftOcclusionQuery* pQuery, const Vec3& vPos)
{
if (m_nPos < CFlareSoftOcclusionQuery::s_nIDMax)
{
pQuery->SetPosToBeChecked(vPos);
m_SoftOcclusionQueries[m_nPos++] = pQuery;
}
}
bool CSoftOcclusionManager::Begin()
{
if (GetSize() > 0)
{
m_bSuccessGenerateIB = GenerateIndexBuffer();
return true;
}
return false;
}
void CSoftOcclusionManager::End()
{
m_nPos = 0;
}
void CSoftOcclusionManager::ClearResources()
{
for (int i = 0; i < CFlareSoftOcclusionQuery::s_nIDMax; ++i)
{
m_SoftOcclusionQueries[i] = NULL;
}
}
@@ -0,0 +1,218 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_FLARESOFTOCCLUSIONQUERY_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_FLARESOFTOCCLUSIONQUERY_H
#pragma once
#include "IFlares.h"
#include "Cry_Vector2.h"
#include "Timeline.h"
class CTexture;
class CShader;
class RootOpticsElement;
class CSoftOcclusionVisiblityFader
{
public:
CSoftOcclusionVisiblityFader()
: m_fTargetVisibility(-1.0f)
, m_fVisibilityFactor(1.0f)
{
}
float UpdateVisibility(const float newTargetVisibility, const float duration);
TimelineFloat m_TimeLine;
float m_fTargetVisibility;
float m_fVisibilityFactor;
};
class CFlareSoftOcclusionQuery
: public ISoftOcclusionQuery
{
public:
static const int s_nIDColMax = 32;
static const int s_nIDRowMax = 32;
static const int s_nIDMax = s_nIDColMax * s_nIDRowMax;
static const int s_nGatherEachSectorWidth = 8;
static const int s_nGatherEachSectorHeight = 8;
static const int s_nGatherTextureWidth = s_nGatherEachSectorWidth * s_nIDColMax;
static const int s_nGatherTextureHeight = s_nGatherEachSectorHeight * s_nIDRowMax;
static const float s_fSectorWidth;
static const float s_fSectorHeight;
private:
static int s_idCount;
static char s_idHashTable[s_nIDMax];
static unsigned char s_paletteRawCache[s_nIDMax * 4];
static int s_ringReadIdx;
static int s_ringWriteIdx;
static int s_ringSize;
private:
static int GenID();
static void ReleaseID(int id);
public:
CFlareSoftOcclusionQuery(const uint8 numFaders = 0)
: m_fOccPlaneWidth(0.02f)
, m_fOccPlaneHeight(0.02f)
, m_PosToBeChecked(0, 0, 0)
, m_fOccResultCache(1)
, m_numVisibilityFaders(numFaders)
, m_pVisbilityFaders(NULL)
, m_refCount(1)
{
InitGlobalResources();
m_nID = GenID();
if (m_numVisibilityFaders > 0)
{
m_pVisbilityFaders = new CSoftOcclusionVisiblityFader[m_numVisibilityFaders];
}
}
~CFlareSoftOcclusionQuery()
{
CRY_ASSERT(m_refCount == 0);
ReleaseID(m_nID);
m_numVisibilityFaders = 0;
SAFE_DELETE_ARRAY(m_pVisbilityFaders);
}
// Manage multi-thread references
virtual void AddRef()
{
CryInterlockedIncrement(&m_refCount);
}
virtual void Release()
{
if (CryInterlockedDecrement(&m_refCount) <= 0)
{
delete this;
}
}
static void InitGlobalResources();
static void BatchReadResults();
static void ReadbackSoftOcclQuery();
static CTexture* GetOcclusionTex();
void GetDomainInTexture(float& out_x0, float& out_y0, float& out_x1, float& out_y1);
void GetSectorSize(float& width, float& height);
struct SOcclusionSectorInfo
{
float x0, y0, x1, y1;
float u0, v0, u1, v1;
float lineardepth;
};
void GetOcclusionSectorInfo(SOcclusionSectorInfo& out_occlusionSector);
void UpdateCachedResults();
int GetID()
{
return m_nID;
}
float GetVisibility() const
{
return m_fOccResultCache;
}
float GetOccResult() const { return m_fOccResultCache; }
float GetDirResult() const { return m_fDirResultCache; }
const Vec2& GetDirVecResult() const {return m_DirVecResultCache; }
bool IsVisible() const { return m_fOccResultCache > 0; }
void SetPosToBeChecked(const Vec3& vPos)
{
m_PosToBeChecked = vPos;
}
CSoftOcclusionVisiblityFader* GetVisibilityFader(const uint8 index) const
{
return (m_pVisbilityFaders && index < m_numVisibilityFaders) ? &m_pVisbilityFaders[index] : NULL;
}
void SetOccPlaneSizeRatio(const Vec2& vRatio) { m_fOccPlaneWidth = vRatio.x; m_fOccPlaneHeight = vRatio.y; }
float GetOccPlaneWidth() const { return m_fOccPlaneWidth; }
float GetOccPlaneHeight() const { return m_fOccPlaneHeight; }
CTexture* GetGatherTexture() const;
static bool ComputeProjPos(const Vec3& vWorldPos, const Matrix44A& viewMat, const Matrix44A& projMat, Vec3& outProjPos);
static float ComputeLinearDepth(const Vec3& worldPos, const Matrix44A& cameraMat, float nearDist, float farDist);
private:
uint8 m_numVisibilityFaders;
CSoftOcclusionVisiblityFader* m_pVisbilityFaders;
int m_nID;
float m_fOccResultCache;
float m_fDirResultCache;
Vec2 m_DirVecResultCache;
Vec3 m_PosToBeChecked;
float m_fOccPlaneWidth;
float m_fOccPlaneHeight;
volatile int m_refCount;
};
class CSoftOcclusionManager
{
public:
CSoftOcclusionManager()
{
m_nPos = 0;
m_IndexBufferOffset = 0;
m_IndexBufferCount = 0;
m_bSuccessGenerateIB = false;
}
void AddSoftOcclusionQuery(CFlareSoftOcclusionQuery* pQuery, const Vec3& vPos);
bool Begin();
void End();
int GetSize()
{
return m_nPos;
}
CFlareSoftOcclusionQuery* GetSoftOcclusionQuery(int nIndex) const;
void GatherOcclusions();
void ComputeVisibility();
void ClearResources();
private:
bool GenerateIndexBuffer();
bool m_bSuccessGenerateIB;
uint32 m_IndexBufferOffset;
uint32 m_IndexBufferCount;
int m_nPos;
_smart_ptr<CFlareSoftOcclusionQuery> m_SoftOcclusionQueries[CFlareSoftOcclusionQuery::s_nIDMax];
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_FLARESOFTOCCLUSIONQUERY_H
@@ -0,0 +1,307 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "Ghost.h"
#include "MeshUtil.h"
#include "../Textures/TextureManager.h"
#include "../../RenderDll/XRenderD3D9/DriverD3D.h"
#if defined(FLARES_SUPPORT_EDITING)
#define MFPtr(FUNC_NAME) (Optics_MFPtr)(&CLensGhost::FUNC_NAME)
void CLensGhost::InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups)
{
COpticsElement::InitEditorParamGroups(groups);
FuncVariableGroup ghostGroup;
ghostGroup.SetName("LensGhost", "Lens Ghost");
ghostGroup.AddVariable(new OpticsMFPVariable(e_TEXTURE2D, "Texture", "The texture for lens ghosts", this, MFPtr(SetTexture), MFPtr(GetTexture)));
groups.push_back(ghostGroup);
}
#undef MFPtr
#endif
void CLensGhost::Load(IXmlNode* pNode)
{
COpticsElement::Load(pNode);
XmlNodeRef pLensGhost = pNode->findChild("LensGhost");
if (pLensGhost)
{
const char* textureName(NULL);
if (pLensGhost->getAttr("Texture", &textureName))
{
if (textureName && textureName[0])
{
ITexture* pTexture = gEnv->pRenderer->EF_LoadTexture(textureName);
SetTexture((CTexture*)pTexture);
//Release this reference because we're no longer going to reference the texture from this pointer
if (pTexture)
{
pTexture->Release();
}
}
}
}
}
CTexture* CLensGhost::GetTexture()
{
if (!m_pTex)
{
m_pTex = CTexture::ForName("EngineAssets/Textures/flares/ghost_grey.tif", FT_DONT_RELEASE | FT_DONT_STREAM, eTF_Unknown);
}
return m_pTex;
}
void CLensGhost::Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, [[maybe_unused]] SAuxParams& aux)
{
if (!IsVisible())
{
return;
}
PROFILE_LABEL_SCOPE("Ghost");
gRenDev->m_RP.m_FlagsShader_RT = 0;
vSrcProjPos = computeOrbitPos(vSrcProjPos, m_globalOrbitAngle);
CD3D9Renderer* rd = gcpRendD3D;
static CCryNameTSCRC pGhostTechName("Ghost");
static CCryNameR texSizeName("baseTexSize");
static CCryNameR tileInfoName("ghostTileInfo");
static STexState bilinearTS(FILTER_LINEAR, true);
bilinearTS.SetBorderColor(0);
bilinearTS.SetClampMode(TADDR_BORDER, TADDR_BORDER, TADDR_BORDER);
shader->FXSetTechnique(pGhostTechName);
uint nPass;
shader->FXBegin(&nPass, FEF_DONTSETTEXTURES);
ApplyGeneralFlags(shader);
ApplyOcclusionBokehFlag(shader);
shader->FXBeginPass(0);
CTexture* tex = GetTexture() ? GetTexture() : CTextureManager::Instance()->GetBlackTexture();
tex->Apply(0, CTexture::GetTexState(bilinearTS));
const Vec4 texSizeParam((float)tex->GetWidth(), (float)tex->GetHeight(), 0, 0);
shader->FXSetVSFloat(texSizeName, &texSizeParam, 1);
if (m_globalOcclusionBokeh)
{
ApplyOcclusionPattern(shader);
}
else
{
CTextureManager::Instance()->GetBlackTexture()->Apply(5, CTexture::GetTexState(bilinearTS));
}
shader->FXSetVSFloat(tileInfoName, &m_vTileDefinition, 1);
ApplyCommonVSParams(shader, vSrcWorldPos, vSrcProjPos);
float x = computeMovementLocationX(vSrcProjPos);
float y = computeMovementLocationY(vSrcProjPos);
rd->DrawQuad(x, y, x, y, m_globalColor, m_globalFlareBrightness);
shader->FXEndPass();
shader->FXEnd();
}
const int CMultipleGhost::MAX_COUNT = 1000;
#if defined(FLARES_SUPPORT_EDITING)
#define MFPtr(FUNC_NAME) (Optics_MFPtr)(&CMultipleGhost::FUNC_NAME)
void CMultipleGhost::InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups)
{
COpticsElement::InitEditorParamGroups(groups);
FuncVariableGroup ghostGroup;
ghostGroup.SetName("MultiGhost", "Multi Ghost");
ghostGroup.AddVariable(new OpticsMFPVariable(e_TEXTURE2D, "Texture", "The texture for lens ghosts", this, MFPtr(SetTexture), MFPtr(GetTexture)));
ghostGroup.AddVariable(new OpticsMFPVariable(e_INT, "Count", "The number of ghosts", this, MFPtr(SetCount), MFPtr(GetCount), 0, static_cast<float>(MAX_COUNT)));
ghostGroup.AddVariable(new OpticsMFPVariable(e_INT, "Random Seed", "The Seed of random generator", this, MFPtr(SetRandSeed), MFPtr(GetRandSeed), -255.0f, 255.0f));
ghostGroup.AddVariable(new OpticsMFPVariable(e_VEC2, "Scattering range", "The scattering range for sub ghosts", this, MFPtr(SetRange), MFPtr(GetRange)));
ghostGroup.AddVariable(new OpticsMFPVariable(e_VEC2, "position factor", "multiplier of position", this, MFPtr(SetPositionFactor), MFPtr(GetPositionFactor)));
ghostGroup.AddVariable(new OpticsMFPVariable(e_VEC2, "position offset", "offset of position", this, MFPtr(SetPositionOffset), MFPtr(GetPositionOffset)));
ghostGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "X-axis noise", "the noise of scattering on x-axis", this, MFPtr(SetXOffsetNoise), MFPtr(GetXOffsetNoise)));
ghostGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Y-axis noise", "the noise of scattering on y-axis", this, MFPtr(SetYOffsetNoise), MFPtr(GetYOffsetNoise)));
ghostGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Size Variation", "The strength for size variation", this, MFPtr(SetSizeNoise), MFPtr(GetSizeNoise)));
ghostGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Brightness Variation", "The strength for brightness variation", this, MFPtr(SetBrightnessNoise), MFPtr(GetBrightnessNoise)));
ghostGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Color Variation", "The strength for color variation", this, MFPtr(SetColorNoise), MFPtr(GetColorNoise)));
groups.push_back(ghostGroup);
}
#undef MFPtr
#endif
void CMultipleGhost::Load(IXmlNode* pNode)
{
COpticsElement::Load(pNode);
XmlNodeRef pMultiGhostNode = pNode->findChild("MultiGhost");
if (pMultiGhostNode)
{
const char* textureName(NULL);
if (pMultiGhostNode->getAttr("Texture", &textureName))
{
if (textureName && textureName[0])
{
ITexture* pTexture = gEnv->pRenderer->EF_LoadTexture(textureName);
SetTexture((CTexture*)pTexture);
if (pTexture)
{
pTexture->Release();
}
}
}
int nCount(0);
if (pMultiGhostNode->getAttr("Count", nCount))
{
SetCount(nCount);
}
int nRandSeed(0);
if (pMultiGhostNode->getAttr("RandomSeed", nRandSeed))
{
SetRandSeed(nRandSeed);
}
Vec2 vRange(m_vRange);
if (pMultiGhostNode->getAttr("Scatteringrange", vRange))
{
SetRange(vRange);
}
Vec2 vPositionFactor(m_vPositionFactor);
if (pMultiGhostNode->getAttr("positionfactor", vPositionFactor))
{
SetPositionFactor(vPositionFactor);
}
Vec2 vPositionOffset(m_vPositionOffset);
if (pMultiGhostNode->getAttr("positionoffset", vPositionOffset))
{
SetPositionOffset(vPositionOffset);
}
float xOffsetNoise(m_fXOffsetNoise);
if (pMultiGhostNode->getAttr("X-axisnoise", xOffsetNoise))
{
SetXOffsetNoise(xOffsetNoise);
}
float yOffsetNoise(m_fYOffsetNoise);
if (pMultiGhostNode->getAttr("Y-axisnoise", yOffsetNoise))
{
SetYOffsetNoise(yOffsetNoise);
}
float fSizeNoise(m_fSizeNoise);
if (pMultiGhostNode->getAttr("SizeVariation", fSizeNoise))
{
SetSizeNoise(fSizeNoise);
}
float fBrightnessNoise(m_fBrightnessNoise);
if (pMultiGhostNode->getAttr("BrightnessVariation", fBrightnessNoise))
{
SetBrightnessNoise(fBrightnessNoise);
}
float fColorNoise(m_fColorNoise);
if (pMultiGhostNode->getAttr("ColorVariation", fColorNoise))
{
SetColorNoise(fColorNoise);
}
}
}
void CMultipleGhost::SetCount(int count)
{
if (count < 0)
{
return;
}
m_nCount = min(count, MAX_COUNT);
RemoveAll();
for (int i = 0; i < m_nCount; i++)
{
CLensGhost* ghost = new CLensGhost("SubGhost");
ghost->SetAutoRotation(true);
ghost->SetAspectRatioCorrection(true);
ghost->SetOccBokehEnabled(true);
ghost->SetSensorSizeFactor(1);
ghost->SetSensorBrightnessFactor(1);
Add(ghost);
}
m_bContentDirty = true;
}
void CMultipleGhost::GenGhosts(SAuxParams& aux)
{
stable_rand::setSeed(GetRandSeed());
float rangeStart = m_vRange.x;
float rangeEnd = m_vRange.y;
float span = rangeEnd - rangeStart;
float halfXNoiseRange = span / 2 * m_fXOffsetNoise;
float halfYNoiseRange = span / 2 * m_fYOffsetNoise;
if ((uint)GetCount() != children.size())
{
SetCount(GetCount());
}
for (uint i = 0; i < children.size(); i++)
{
CLensGhost* ghost = (CLensGhost*)&*(children[i]);
ghost->SetTexture(GetTexture());
Vec2 pos;
float axisPos = stable_rand::randPositive() * span + rangeStart;
pos.x = stable_rand::randUnit() * halfXNoiseRange + axisPos * m_vPositionFactor.x + m_vPositionOffset.x;
pos.y = stable_rand::randUnit() * halfYNoiseRange + axisPos * m_vPositionFactor.y + m_vPositionOffset.y;
ghost->SetMovement(pos);
ghost->SetSize(stable_rand::randBias(GetSizeNoise()));
ghost->SetBrightness(stable_rand::randBias(GetBrightnessNoise()));
ColorF variation(stable_rand::randBias(GetColorNoise()), stable_rand::randBias(GetColorNoise()), stable_rand::randBias(GetColorNoise()));
ghost->SetColor(variation);
ghost->SetDynamicsEnabled(GetDynamicsEnabled());
ghost->SetDynamicsInvert(GetDynamicsInvert());
ghost->SetDynamicsOffset(GetDynamicsOffset());
ghost->SetDynamicsRange(GetDynamicsRange());
}
validateChildrenGlobalVars(aux);
m_bContentDirty = false;
}
void CMultipleGhost::Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux)
{
if (!IsVisible())
{
return;
}
PROFILE_LABEL_SCOPE("MultiGhost");
if (m_bContentDirty)
{
GenGhosts(aux);
}
COpticsGroup::Render(shader, vSrcWorldPos, vSrcProjPos, aux);
}
@@ -0,0 +1,239 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_GHOST_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_GHOST_H
#pragma once
#include "OpticsElement.h"
#include "OpticsGroup.h"
class CLensGhost
: public COpticsElement
{
_smart_ptr<CTexture> m_pTex;
Vec4 m_vTileDefinition;
protected:
#if defined(FLARES_SUPPORT_EDITING)
void InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups);
#endif
public:
CLensGhost(const char* name, CTexture* externalTex = NULL)
: COpticsElement(name)
, m_pTex(externalTex)
{
}
virtual IOpticsElementBase* Clone()
{
return new CLensGhost(*this);
}
EFlareType GetType() { return eFT_Ghost; }
void Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux);
void Load(IXmlNode* pNode);
CTexture* GetTexture();
void SetTexture(CTexture* tex) { m_pTex = tex; }
int GetTileIndex() { return (int)m_vTileDefinition.w; }
int GetTotalTileCount() { return (int)m_vTileDefinition.z; }
int GetTileCountX() { return (int)m_vTileDefinition.x; }
int GetTileCountY() { return (int)m_vTileDefinition.y; }
void SetTileIndex(int idx)
{
if (idx >= 0 && idx <= GetTotalTileCount())
{
m_vTileDefinition.w = (float)idx;
}
}
void SetTileCountX(int n)
{
int totalCount = GetTotalTileCount();
if (totalCount > n * GetTileCountY())
{
totalCount = n * GetTileCountY();
}
SetTileDefinition(n, GetTileCountY(), totalCount, GetTileIndex());
}
void SetTileCountY(int n)
{
int totalCount = GetTotalTileCount();
if (totalCount > GetTileCountX() * n)
{
totalCount = GetTileCountX() * n;
}
SetTileDefinition(GetTileCountX(), n, totalCount, GetTileIndex());
}
void SetTotalTileCount(int t)
{
SetTileDefinition(GetTileCountX(), GetTileCountY(), t, GetTileIndex());
}
void SetTileDefinition(int countX, int countY, int totalCount, int index)
{
if (totalCount > countX * countY)
{
return;
}
m_vTileDefinition.x = (float)countX;
m_vTileDefinition.y = (float)countY;
m_vTileDefinition.z = (float)totalCount;
m_vTileDefinition.w = (float)index;
}
void SetTileDefinition(Vec4 df)
{
SetTileDefinition((int)df.x, (int)df.y, (int)df.z, (int)df.w);
}
};
class CMultipleGhost
: public COpticsGroup
{
protected:
_smart_ptr<CTexture> m_pTex;
Vec2 m_vRange;
float m_fXOffsetNoise;
float m_fYOffsetNoise;
Vec2 m_vPositionFactor;
Vec2 m_vPositionOffset;
int m_nCount;
int m_nRandSeed;
float m_fSizeNoise;
float m_fBrightnessNoise;
float m_fColorNoise;
bool m_bContentDirty : 1;
protected:
void InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups);
public:
CMultipleGhost(const char* name)
: COpticsGroup(name)
, m_nCount(0)
, m_nRandSeed(0)
, m_bContentDirty(true)
, m_fXOffsetNoise(0)
, m_fYOffsetNoise(0)
, m_fSizeNoise(0.4f)
, m_fColorNoise(0.3f)
, m_fBrightnessNoise(0.3f)
{
m_vRange.set(0.1f, 0.7f);
m_vPositionFactor.set(1, 1);
m_vPositionOffset.set(0, 0);
SetSize(0.04f);
SetBrightness(0.3f);
SetCount(20);
}
public:
static const int MAX_COUNT;
void GenGhosts(SAuxParams& aux);
EFlareType GetType() { return eFT_MultiGhosts; }
bool IsGroup() const { return false; }
int GetElementCount() const { return 0; }
void Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux);
void Load(IXmlNode* pNode);
CTexture* GetTexture() const { return m_pTex; }
void SetTexture(CTexture* tex)
{
m_pTex = tex;
m_bContentDirty = true;
}
float GetXOffsetNoise() const { return m_fXOffsetNoise; }
void SetXOffsetNoise(float x)
{
m_fXOffsetNoise = x;
m_bContentDirty = true;
}
float GetYOffsetNoise() const { return m_fYOffsetNoise; }
void SetYOffsetNoise(float y)
{
m_fYOffsetNoise = y;
m_bContentDirty = true;
}
Vec2 GetPositionFactor() const { return m_vPositionFactor; }
void SetPositionFactor(Vec2 positionFactor)
{
m_vPositionFactor = positionFactor;
m_bContentDirty = true;
}
Vec2 GetPositionOffset() const { return m_vPositionOffset; }
void SetPositionOffset(Vec2 offsets)
{
m_vPositionOffset = offsets;
m_bContentDirty = true;
}
Vec2 GetRange() const { return m_vRange; }
void SetRange(Vec2 range)
{
m_vRange = range;
m_bContentDirty = true;
}
int GetCount() const { return m_nCount; }
void SetCount(int count);
int GetRandSeed() const { return m_nRandSeed; }
void SetRandSeed(int n)
{
m_nRandSeed = n;
m_bContentDirty = true;
}
float GetSizeNoise() const { return m_fSizeNoise; }
void SetSizeNoise(float n)
{
m_fSizeNoise = n;
m_bContentDirty = true;
}
float GetBrightnessNoise() const { return m_fBrightnessNoise; }
void SetBrightnessNoise(float n)
{
m_fBrightnessNoise = n;
m_bContentDirty = true;
}
float GetColorNoise() const { return m_fColorNoise; }
void SetColorNoise(float n)
{
m_fColorNoise = n;
m_bContentDirty = true;
}
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_GHOST_H
@@ -0,0 +1,120 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "Glow.h"
#include "../Textures/Texture.h"
#include "../CryNameR.h"
#include "../../RenderDll/XRenderD3D9/DriverD3D.h"
#if defined(FLARES_SUPPORT_EDITING)
#define MFPtr(FUNC_NAME) (Optics_MFPtr)(&Glow::FUNC_NAME)
void Glow::InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups)
{
COpticsElement::InitEditorParamGroups(groups);
FuncVariableGroup glowGroup;
glowGroup.SetName("Glow");
glowGroup.AddVariable(new OpticsMFPVariable(e_INT, "Polygon factor", "Polygons factor", this, MFPtr(SetPolygonFactor), MFPtr(GetPolygonFactor), 0, 128.0f));
glowGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Focus factor", "Focus factor", this, MFPtr(SetFocusFactor), MFPtr(GetFocusFactor)));
glowGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Gamma", "Gamma", this, MFPtr(SetGamma), MFPtr(GetGamma)));
groups.push_back(glowGroup);
}
#undef MFPtr
#endif
void Glow::Load(IXmlNode* pNode)
{
COpticsElement::Load(pNode);
XmlNodeRef pGlowNode = pNode->findChild("Glow");
if (pGlowNode)
{
int nPolygonFactor(0);
if (pGlowNode->getAttr("Polygonfactor", nPolygonFactor))
{
SetPolygonFactor(nPolygonFactor);
}
float fFocusFactor(m_fFocusFactor);
if (pGlowNode->getAttr("Focusfactor", fFocusFactor))
{
SetFocusFactor(fFocusFactor);
}
float fGamma(m_fGamma);
if (pGlowNode->getAttr("Gamma", fGamma))
{
SetGamma(fGamma);
}
}
}
void Glow::GenMesh()
{
float ringPos = 1;
MeshUtil::GenDisk(m_fSize, (int)m_fPolyonFactor, 1, true, m_globalColor, &ringPos, m_vertBuf, m_idxBuf);
}
void Glow::ApplyDistributionParamsPS(CShader* shader)
{
static CCryNameR lumaParamsName("lumaParams");
Vec4 lumaParams(m_fFocusFactor, m_fGamma, 0, 0);
shader->FXSetPSFloat(lumaParamsName, &lumaParams, 1);
}
void Glow::DrawMesh()
{
gcpRendD3D->FX_Commit();
DrawMeshTriList();
}
void Glow::Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, [[maybe_unused]] SAuxParams& aux)
{
if (!IsVisible())
{
return;
}
PROFILE_LABEL_SCOPE("Glow");
gRenDev->m_RP.m_FlagsShader_RT = 0;
static CCryNameTSCRC pGlowTechName("Glow");
shader->FXSetTechnique(pGlowTechName);
uint nPass;
shader->FXBegin(&nPass, FEF_DONTSETTEXTURES);
ApplyGeneralFlags(shader);
shader->FXBeginPass(0);
ApplyCommonVSParams(shader, vSrcWorldPos, vSrcProjPos);
ApplyExternTintAndBrightnessVS(shader, m_globalColor, m_globalFlareBrightness);
static CCryNameR meshCenterName("meshCenterAndBrt");
float x = computeMovementLocationX(vSrcProjPos);
float y = computeMovementLocationY(vSrcProjPos);
const Vec4 meshCenterParam(x, y, vSrcProjPos.z, 1);
shader->FXSetVSFloat(meshCenterName, &meshCenterParam, 1);
ApplyDistributionParamsPS(shader);
ValidateMesh();
ApplyMesh();
DrawMesh();
shader->FXEndPass();
shader->FXEnd();
}
@@ -0,0 +1,101 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_GLOW_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_GLOW_H
#pragma once
#include "OpticsElement.h"
#include "AbstractMeshElement.h"
#include "MeshUtil.h"
class Glow
: public COpticsElement
, public AbstractMeshElement
{
private:
static float compositionBufRatio;
protected:
float m_fFocusFactor;
float m_fPolyonFactor;
float m_fGamma;
protected:
void ApplyDistributionParamsPS(CShader* shader);
virtual void GenMesh();
void DrawMesh();
void Invalidate()
{
m_meshDirty = true;
}
public:
Glow(const char* name)
: COpticsElement(name)
, m_fFocusFactor(0.3f)
, m_fPolyonFactor(32.f)
, m_fGamma(1)
{
m_Color.a = 1.f; //Max alpha so that the ghost can be seen when it's created
}
#if defined(FLARES_SUPPORT_EDITING)
void InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups);
#endif
EFlareType GetType() { return eFT_Glow; }
void Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux);
void Load(IXmlNode* pNode);
void SetColor(ColorF t)
{
COpticsElement::SetColor(t);
m_meshDirty = true;
}
float GetFocusFactor() const {return m_fFocusFactor; }
void SetFocusFactor(float f)
{
m_fFocusFactor = f;
}
int GetPolygonFactor() const { return (int)m_fPolyonFactor; }
void SetPolygonFactor(int f)
{
if (f < 0)
{
f = 0;
}
else if (f > 128)
{
f = 128;
}
if (m_fPolyonFactor != f)
{
m_fPolyonFactor = (float)f;
m_meshDirty = true;
}
}
float GetGamma() const { return m_fGamma; }
void SetGamma(float gamma)
{
m_fGamma = (float)gamma;
}
void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this) + GetMeshDataSize());
}
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_GLOW_H
@@ -0,0 +1,204 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "ImageSpaceShafts.h"
#include "FlareSoftOcclusionQuery.h"
#include "../CryNameR.h"
#include "Common/Textures/TextureManager.h"
#include "../../RenderDll/XRenderD3D9/DriverD3D.h"
CTexture* ImageSpaceShafts::m_pOccBuffer = NULL;
CTexture* ImageSpaceShafts::m_pDraftBuffer = NULL;
#if defined(FLARES_SUPPORT_EDITING)
#define MFPtr(FUNC_NAME) (Optics_MFPtr)(&ImageSpaceShafts::FUNC_NAME)
void ImageSpaceShafts::InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups)
{
COpticsElement::InitEditorParamGroups(groups);
FuncVariableGroup isShaftsGroup;
isShaftsGroup.SetName("ImageSpaceShafts", "Image Space Shafts");
isShaftsGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "High Quality", "Enable High quality mode", this, MFPtr(SetHighQualityMode), MFPtr(IsHighQualityMode)));
isShaftsGroup.AddVariable(new OpticsMFPVariable(e_TEXTURE2D, "Gobo Tex", "Gobo texture", this, MFPtr(SetGoboTex), MFPtr(GetGoboTex)));
groups.push_back(isShaftsGroup);
}
#undef MFPtr
#endif
void ImageSpaceShafts::Load(IXmlNode* pNode)
{
COpticsElement::Load(pNode);
XmlNodeRef pImageSpaceNode = pNode->findChild("ImageSpaceShafts");
if (pImageSpaceNode)
{
bool bHighQualityMode(m_bHighQualityMode);
if (pImageSpaceNode->getAttr("HighQuality", bHighQualityMode))
{
SetHighQualityMode(bHighQualityMode);
}
else
{
assert(0);
}
const char* pGoboTexName = NULL;
if (pImageSpaceNode->getAttr("GoboTex", &pGoboTexName))
{
if (pGoboTexName && pGoboTexName[0])
{
ITexture* pTexture = gEnv->pRenderer->EF_LoadTexture(pGoboTexName);
SetGoboTex((CTexture*)pTexture);
//Release this reference because we're no longer going to reference the texture from this pointer
if (pTexture)
{
pTexture->Release();
}
}
}
else
{
assert(0);
}
}
else
{
assert(0);
}
}
CTexture* ImageSpaceShafts::GetGoboTex()
{
if (!m_pGoboTex)
{
m_pGoboTex = CTexture::ForName("EngineAssets/Textures/flares/iris_shaft.tif", FT_DONT_STREAM, eTF_Unknown);
}
return m_pGoboTex;
}
void ImageSpaceShafts::InitTextures()
{
float occBufRatio, occDraftRatio, occFinalRatio;
if (m_bHighQualityMode && CRenderer::CV_r_flareHqShafts)
{
occBufRatio = 0.5f;
occDraftRatio = 0.5f;
occFinalRatio = 0.5f;
}
else
{
occBufRatio = 0.25f;
occDraftRatio = 0.4f;
occFinalRatio = 0.45f;
}
int w = gcpRendD3D->GetWidth();
int h = gcpRendD3D->GetHeight();
int flag = FT_DONT_RELEASE | FT_DONT_STREAM;
m_pOccBuffer = CTexture::CreateRenderTarget("$ImageSpaceShaftsOccBuffer", (int)(w * occBufRatio), (int)(h * occBufRatio), Clr_Empty, eTT_2D, flag, eTF_R8G8B8A8);
ETEX_Format draftTexFormat(eTF_R16G16B16A16);
m_pDraftBuffer = CTexture::CreateRenderTarget("$ImageSpaceShaftsDraftBuffer", (int)(w * occDraftRatio), (int)(h * occDraftRatio), Clr_Empty, eTT_2D, flag, draftTexFormat);
m_bTexDirty = false;
}
static STexState s_isPointTS(FILTER_POINT, true);
static STexState s_isBilinearTS(FILTER_BILINEAR, true);
void ImageSpaceShafts::Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux)
{
if (!IsVisible())
{
return;
}
CD3D9Renderer* rd = gcpRendD3D;
if (!m_pOccBuffer || m_bTexDirty)
{
InitTextures();
}
PROFILE_LABEL_SCOPE("ImagesSpaceShafts");
vSrcProjPos = computeOrbitPos(vSrcProjPos, m_globalOrbitAngle);
static CCryNameTSCRC pImageSpaceShaftsTechName("ImageSpaceShafts");
shader->FXSetTechnique(pImageSpaceShaftsTechName);
uint nPass;
shader->FXBegin(&nPass, FEF_DONTSETTEXTURES);
static CCryNameR texSizeName("baseTexSize");
Vec4 texSizeParam(1, 1, 0, 0);
{
PROFILE_LABEL_SCOPE("ImagesSpaceShafts-Occ");
gRenDev->m_RP.m_FlagsShader_RT = 0;
rd->FX_ClearTarget(m_pOccBuffer, Clr_Empty);
rd->FX_PushRenderTarget(0, m_pOccBuffer, NULL, -1, false);
ApplyGeneralFlags(shader);
shader->FXBeginPass(0);
CTexture* pGoboTex = ((CTexture*)m_pGoboTex) ? ((CTexture*)m_pGoboTex) : CTextureManager::Instance()->GetBlackTexture();
pGoboTex->Apply(0, CTexture::GetTexState(s_isBilinearTS));
CTexture::s_ptexZTargetScaled->Apply(1, CTexture::GetTexState(s_isBilinearTS));
ApplyCommonVSParams(shader, vSrcWorldPos, vSrcProjPos);
shader->FXSetVSFloat(texSizeName, &texSizeParam, 1);
rd->DrawQuad(vSrcProjPos.x, vSrcProjPos.y, vSrcProjPos.x, vSrcProjPos.y, m_globalColor, aux.linearDepth);
shader->FXEndPass();
rd->FX_PopRenderTarget(0);
}
{
PROFILE_LABEL_SCOPE("ImagesSpaceShafts-Gen");
gRenDev->m_RP.m_FlagsShader_RT = 0;
rd->FX_ClearTarget(m_pDraftBuffer, Clr_Empty);
rd->FX_PushRenderTarget(0, m_pDraftBuffer, NULL, -1, false);
ApplyGeneralFlags(shader);
shader->FXBeginPass(1);
ApplyCommonVSParams(shader, vSrcWorldPos, vSrcProjPos);
shader->FXSetVSFloat(texSizeName, &texSizeParam, 1);
m_pOccBuffer->Apply(1, CTexture::GetTexState(s_isBilinearTS));
rd->DrawQuad(vSrcProjPos.x, vSrcProjPos.y, vSrcProjPos.x, vSrcProjPos.y, m_globalColor, m_globalShaftBrightness);
shader->FXEndPass();
rd->FX_PopRenderTarget(0);
}
{
PROFILE_LABEL_SCOPE("ImagesSpaceShafts-BLEND");
gRenDev->m_RP.m_FlagsShader_RT = 0;
m_pDraftBuffer->Apply(1, CTexture::GetTexState(s_isBilinearTS));
shader->FXBeginPass(2);
rd->DrawQuad(0, 0, 0, 0, m_globalColor, m_globalShaftBrightness);
shader->FXEndPass();
}
shader->FXEnd();
}
@@ -0,0 +1,61 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_IMAGESPACESHAFTS_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_IMAGESPACESHAFTS_H
#pragma once
#include "OpticsElement.h"
class CTexture;
class CD3D9Renderer;
class ImageSpaceShafts
: public COpticsElement
{
protected:
static CTexture* m_pOccBuffer;
static CTexture* m_pDraftBuffer;
protected:
bool m_bHighQualityMode;
bool m_bTexDirty;
_smart_ptr<CTexture> m_pGoboTex;
virtual void InitTextures();
public:
ImageSpaceShafts(const char* name)
: COpticsElement(name)
, m_bTexDirty(true)
, m_bHighQualityMode(false)
{
m_Color.a = 1.f;
SetSize(0.7f);
}
EFlareType GetType() { return eFT_ImageSpaceShafts; }
void InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups);
void Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux);
void Load(IXmlNode* pNode);
bool IsHighQualityMode() const { return m_bHighQualityMode; }
void SetHighQualityMode(bool b) { m_bHighQualityMode = b; m_bTexDirty = true; }
CTexture* GetGoboTex();
void SetGoboTex(CTexture* tex) { m_pGoboTex = tex; }
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_IMAGESPACESHAFTS_H
@@ -0,0 +1,70 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Interpolator deals with animations' interpolation.
// These are bare bones interpolators: they take 3 key values as inputs.
// The first two specify the two end points(start and end), and the last one specify the interpolation tweenness (x-value).
// The output is the y-value.
// For additional time-based playback type animation, see Timeline.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_INTERPOLATOR_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_INTERPOLATOR_H
#pragma once
template<class T>
class Interpolator
{
protected:
virtual T mix(T v0, T v1, float mixRatio)
{
return (T)(v0 * (1 - mixRatio) + v1 * mixRatio);
}
public:
virtual ~Interpolator(){}
virtual T compute(T start, T end, float xValue) = 0;
};
template<class T>
class LinearInterp
: public Interpolator<T>
{
public:
virtual T compute(T start, T end, float xValue)
{
return Interpolator<T>::mix(start, end, xValue);
}
};
template<class T>
class CubicInterp
: public Interpolator<T>
{
public:
virtual T compute(T start, T end, float xValue)
{
float x = xValue * xValue * (3 - 2 * xValue);
return Interpolator<T>::mix(start, end, x);
}
};
namespace InterpPredef
{
static LinearInterp<float> Linear_FLOAT;
static LinearInterp<int> Linear_INT;
static CubicInterp<float> CUBIC_FLOAT;
static CubicInterp<int> CUBIC_INT;
}
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_INTERPOLATOR_H
@@ -0,0 +1,320 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "IrisShafts.h"
#include "RootOpticsElement.h"
#include "FlareSoftOcclusionQuery.h"
#include "../CryNameR.h"
#include "../../RenderDll/XRenderD3D9/DriverD3D.h"
#include "../Common/Textures/TextureManager.h"
#if defined(FLARES_SUPPORT_EDITING)
#define MFPtr(FUNC_NAME) (Optics_MFPtr)(&IrisShafts::FUNC_NAME)
void IrisShafts::InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups)
{
COpticsElement::InitEditorParamGroups(groups);
FuncVariableGroup irisGroup;
irisGroup.SetName("IrisShafts", "Iris Shafts");
irisGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Enable gradient tex", "Enable gradient texture", this, MFPtr(SetEnableSpectrumTex), MFPtr(GetEnableSpectrumTex)));
irisGroup.AddVariable(new OpticsMFPVariable(e_TEXTURE2D, "Base Tex", "Basic Texture", this, MFPtr(SetBaseTex), MFPtr(GetBaseTex)));
irisGroup.AddVariable(new OpticsMFPVariable(e_TEXTURE2D, "Gradient Tex", "Gradient Texture", this, MFPtr(SetSpectrumTex), MFPtr(GetSpectrumTex)));
irisGroup.AddVariable(new OpticsMFPVariable(e_INT, "Noise seed", "Noise seed", this, MFPtr(SetNoiseSeed), MFPtr(GetNoiseSeed), -255.0f, 255.0f));
irisGroup.AddVariable(new OpticsMFPVariable(e_INT, "Complexity", "Complexity of shafts", this, MFPtr(SetComplexity), MFPtr(GetComplexity), 0, 1000.0f));
irisGroup.AddVariable(new OpticsMFPVariable(e_INT, "Smoothness", "The level of smoothness", this, MFPtr(SetSmoothLevel), MFPtr(GetSmoothLevel), 0, 255.0f));
irisGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Thickness", "Thickness of the shafts", this, MFPtr(SetThickness), MFPtr(GetThickness), 0, 255.0f));
irisGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Thickness noise", "Noise strength of thickness variation", this, MFPtr(SetThicknessNoise), MFPtr(GetThicknessNoise)));
irisGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Spread", "Spread of the shafts", this, MFPtr(SetSpread), MFPtr(GetSpread)));
irisGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Spread noise", "Noise strength of spread variation", this, MFPtr(SetSpreadNoise), MFPtr(GetSpreadNoise)));
irisGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Size noise", "Noise strength of shafts' sizes", this, MFPtr(SetSizeNoise), MFPtr(GetSizeNoise)));
irisGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Spacing noise", "Noise strength of shafts' spacing", this, MFPtr(SetSpacingNoise), MFPtr(GetSpacingNoise)));
groups.push_back(irisGroup);
}
#undef MFPtr
#endif
void IrisShafts::Load(IXmlNode* pNode)
{
COpticsElement::Load(pNode);
XmlNodeRef pIrisShaftsNode = pNode->findChild("IrisShafts");
if (pIrisShaftsNode)
{
bool bUseSpectrumTex(m_bUseSpectrumTex);
if (pIrisShaftsNode->getAttr("Enablegradienttex", bUseSpectrumTex))
{
SetEnableSpectrumTex(bUseSpectrumTex);
}
const char* baseTextureName = NULL;
if (pIrisShaftsNode->getAttr("BaseTex", &baseTextureName))
{
if (baseTextureName && baseTextureName[0])
{
ITexture* pTexture = gEnv->pRenderer->EF_LoadTexture(baseTextureName);
SetBaseTex((CTexture*)pTexture);
//Release this reference because we're no longer going to reference the texture from this pointer
if (pTexture)
{
pTexture->Release();
}
}
}
const char* gradientTexName = NULL;
if (pIrisShaftsNode->getAttr("GradientTex", &gradientTexName))
{
if (gradientTexName && gradientTexName[0])
{
ITexture* pTexture = gEnv->pRenderer->EF_LoadTexture(gradientTexName);
SetSpectrumTex((CTexture*)pTexture);
//Release this reference because we're no longer going to reference the texture from this pointer
if (pTexture)
{
pTexture->Release();
}
}
}
int nNoiseSeed(m_nNoiseSeed);
if (pIrisShaftsNode->getAttr("Noiseseed", nNoiseSeed))
{
SetNoiseSeed(nNoiseSeed);
}
int nComplexity(m_nComplexity);
if (pIrisShaftsNode->getAttr("Complexity", nComplexity))
{
SetComplexity(nComplexity);
}
int nSmoothLevel(m_nSmoothLevel);
if (pIrisShaftsNode->getAttr("Smoothness", nSmoothLevel))
{
SetSmoothLevel(nSmoothLevel);
}
float fThickness(m_fThickness);
if (pIrisShaftsNode->getAttr("Thickness", fThickness))
{
SetThickness(fThickness);
}
float fThicknessNoise(m_fThicknessNoiseStrength);
if (pIrisShaftsNode->getAttr("Thicknessnoise", fThicknessNoise))
{
SetThicknessNoise(fThicknessNoise);
}
float fSpread(m_fSpread);
if (pIrisShaftsNode->getAttr("Spread", fSpread))
{
SetSpread(fSpread);
}
float fThicknessNoiseStrength(m_fThicknessNoiseStrength);
if (pIrisShaftsNode->getAttr("Spreadnoise", fThicknessNoiseStrength))
{
SetSpreadNoise(fThicknessNoiseStrength);
}
float fSizeNoiseStrength(m_fSizeNoiseStrength);
if (pIrisShaftsNode->getAttr("Sizenoise", fSizeNoiseStrength))
{
SetSizeNoise(fSizeNoiseStrength);
}
float fSpacingNoiseStrength(m_fSpacingNoiseStrength);
if (pIrisShaftsNode->getAttr("Spacingnoise", fSpacingNoiseStrength))
{
SetSpacingNoise(fSpacingNoiseStrength);
}
}
}
float IrisShafts::ComputeSpreadParameters(const float spread)
{
return spread * 75;
}
int IrisShafts::ComputeDynamicSmoothLevel(int maxLevel, float spanAngle, float threshold)
{
return min(maxLevel, (int)(spanAngle / threshold));
}
void IrisShafts::GenMesh()
{
stable_rand::setSeed((int)(m_nNoiseSeed * m_fConcentrationBoost));
float dirDelta = 1.0f / (float)m_nComplexity;
float halfAngleRange = m_fAngleRange / 2;
ColorF color(1, 1, 1, 1);
m_vertBuf.clear();
m_idxBuf.clear();
std::vector<int> randomTable;
randomTable.resize(m_nComplexity);
for (int i = 0; i < m_nComplexity; ++i)
{
randomTable[i] = i;
}
for (int i = 0; i < m_nComplexity; ++i)
{
std::swap(randomTable[(int)(stable_rand::randPositive() * m_nComplexity)], randomTable[(int)(stable_rand::randPositive() * m_nComplexity)]);
}
for (int i = 0; i < m_nComplexity; i++)
{
float spacingNoise = 1 + stable_rand::randUnit() * m_fSpacingNoiseStrength;
float dirDiff;
if (m_fConcentrationBoost > 1.f && randomTable[i] == m_nComplexity / 2)
{
dirDiff = dirDelta * spacingNoise * 0.05f;
}
else
{
dirDiff = m_fAngleRange * fmod((randomTable[i] * dirDelta + spacingNoise), 1.0f) - halfAngleRange;
}
float dirUnit = m_fPrimaryDir + dirDiff;
float dir = 360 * dirUnit;
float dirDiffRatio = fabs(dirDiff) / m_fAngleRange;
float sizeBoost = 1 + (m_fConcentrationBoost - 1) * (-1.75f * dirDiffRatio + 2.f); // From center to edge: 2->0.25
float brightnessBoost = 1 + (m_fConcentrationBoost - 1) * (1 / (15 * (dirDiffRatio + 0.02f)) - 1); // from center to edge: 2.333->-0.994
color.a = brightnessBoost;
float size = sizeBoost * (1 + stable_rand::randUnit() * m_fSizeNoiseStrength);
float thickness = m_fThickness * (1 + stable_rand::randUnit() * m_fThicknessNoiseStrength);
float spread = m_fSpread * (1 + stable_rand::randUnit() * m_fSpreadNoiseStrength);
float halfAngle = ComputeSpreadParameters(spread);
int dynSmoothLevel = ComputeDynamicSmoothLevel(m_nSmoothLevel, halfAngle * 2, 1);
if (dynSmoothLevel <= 1)
{
continue;
}
std::vector<SVF_P3F_C4B_T2F> vertices;
std::vector<uint16> indices;
MeshUtil::GenShaft(size, thickness, dynSmoothLevel, dir - halfAngle, dir + halfAngle, color, vertices, indices);
int generatedPolyonNum = (int)(indices.size() + m_idxBuf.size()) / 3;
if (CRenderer::CV_r_FlaresIrisShaftMaxPolyNum != 0 && generatedPolyonNum > CRenderer::CV_r_FlaresIrisShaftMaxPolyNum)
{
break;
}
int indexOffset = m_vertBuf.size();
m_vertBuf.insert(m_vertBuf.end(), vertices.begin(), vertices.end());
for (int k = 0, iIndexSize(indices.size()); k < iIndexSize; ++k)
{
m_idxBuf.push_back(indices[k] + indexOffset);
}
}
}
void IrisShafts::Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, [[maybe_unused]] SAuxParams& aux)
{
if (!IsVisible())
{
return;
}
PROFILE_LABEL_SCOPE("IrisShafts");
gRenDev->m_RP.m_FlagsShader_RT = 0;
vSrcProjPos = computeOrbitPos(vSrcProjPos, m_globalOrbitAngle);
static CCryNameTSCRC pIrisShaftsTechName("IrisShafts");
shader->FXSetTechnique(pIrisShaftsTechName);
uint nPass;
shader->FXBegin(&nPass, FEF_DONTSETTEXTURES);
ApplyGeneralFlags(shader);
ApplySpectrumTexFlag(shader, m_bUseSpectrumTex);
shader->FXBeginPass(0);
if (m_globalOcclusionBokeh)
{
RootOpticsElement* root = GetRoot();
CFlareSoftOcclusionQuery* occQuery = root->GetOcclusionQuery();
float occ = occQuery->GetOccResult();
float interpOcc = root->GetShaftVisibilityFactor();
if (occ >= 0.05f && fabs(m_fPrevOcc - occ) > 0.01f)
{
m_fAngleRange = 0.65f * occ * occ + 0.35f;
m_fPrimaryDir = occQuery->GetDirResult() / (2 * PI);
m_fConcentrationBoost = 2.0f - occ;
m_fBrightnessBoost = aznumeric_cast<float>(1 + 2 * pow(occ - 1, 6));
m_meshDirty = true;
m_fPrevOcc = occ;
}
else if (occ < 0.05f)
{
m_fAngleRange = 0.33f;
m_fBrightnessBoost = aznumeric_cast<float>(1 + 2 * pow(interpOcc - 1, 6));
m_fPrevOcc = 0;
m_meshDirty = true;
}
}
else
{
if (m_fAngleRange < 0.999f)
{
m_meshDirty = true;
}
m_fPrimaryDir = 0;
m_fAngleRange = 1;
m_fConcentrationBoost = 1;
m_fBrightnessBoost = 1;
}
ApplyCommonVSParams(shader, vSrcWorldPos, vSrcProjPos);
ApplyExternTintAndBrightnessVS(shader, m_globalColor, m_globalFlareBrightness);
static CCryNameR meshCenterName("meshCenterAndBrt");
const float x = computeMovementLocationX(vSrcProjPos);
const float y = computeMovementLocationY(vSrcProjPos);
const Vec4 meshCenterParam(x, y, vSrcProjPos.z, 1);
shader->FXSetVSFloat(meshCenterName, &meshCenterParam, 1);
static STexState bilinearTS(FILTER_LINEAR, true);
bilinearTS.SetBorderColor(0);
bilinearTS.SetClampMode(TADDR_BORDER, TADDR_BORDER, TADDR_BORDER);
CTexture* pBaseTex = ((CTexture*)m_pBaseTex) ? ((CTexture*)m_pBaseTex) : CTextureManager::Instance()->GetBlackTexture();
pBaseTex->Apply(1, CTexture::GetTexState(bilinearTS));
CTexture* pSpectrumTex = (m_bUseSpectrumTex && ((CTexture*)m_pSpectrumTex)) ? ((CTexture*)m_pSpectrumTex) : CTextureManager::Instance()->GetBlackTexture();
pSpectrumTex->Apply(0, CTexture::GetTexState(bilinearTS));
if (m_MaxNumberOfPolygon != CRenderer::CV_r_FlaresIrisShaftMaxPolyNum)
{
m_meshDirty = true;
m_MaxNumberOfPolygon = CRenderer::CV_r_FlaresIrisShaftMaxPolyNum;
}
ValidateMesh();
ApplyMesh();
DrawMeshTriList();
shader->FXEndPass();
shader->FXEnd();
}
@@ -0,0 +1,189 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_IRISSHAFTS_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_IRISSHAFTS_H
#pragma once
#include "OpticsElement.h"
#include "AbstractMeshElement.h"
#include "MeshUtil.h"
class CTexture;
class IrisShafts
: public COpticsElement
, public AbstractMeshElement
{
private:
_smart_ptr<CTexture> m_pBaseTex;
_smart_ptr<CTexture> m_pSpectrumTex;
bool m_bUseSpectrumTex : 1;
int m_nComplexity;
int m_nSmoothLevel;
int m_nColorComplexity;
float m_fPrevOcc;
float m_fPrimaryDir;
float m_fAngleRange;
float m_fConcentrationBoost;
float m_fBrightnessBoost;
float m_fSizeNoiseStrength;
float m_fThicknessNoiseStrength;
float m_fSpreadNoiseStrength;
float m_fSpacingNoiseStrength;
float m_fSpread;
float m_fThickness;
int m_nNoiseSeed;
int m_MaxNumberOfPolygon;
protected:
virtual void GenMesh();
float ComputeSpreadParameters(const float thickness);
int ComputeDynamicSmoothLevel(int maxLevel, float spanAngle, float threshold);
void Invalidate()
{
m_meshDirty = true;
}
public:
IrisShafts (const char* name)
: COpticsElement(name, 0.5f)
, m_fThickness(0.3f)
, m_fSpread(0.2f)
, m_nSmoothLevel(2)
, m_nNoiseSeed(81)
, m_pBaseTex(0)
, m_fSizeNoiseStrength(0.8f)
, m_fThicknessNoiseStrength(0.6f)
, m_fSpacingNoiseStrength(0.2f)
, m_fSpreadNoiseStrength(0.0f)
, m_bUseSpectrumTex(false)
, m_fPrimaryDir(0)
, m_fAngleRange(1)
, m_fConcentrationBoost(0)
, m_fPrevOcc(-1.f)
, m_fBrightnessBoost(0)
, m_MaxNumberOfPolygon(0)
{
m_vMovement.x = 1.f;
m_vMovement.y = 1.f;
m_Color.a = 1.f;
m_pBaseTex = CTexture::ForName("EngineAssets/Textures/flares/iris_shaft.dds", FT_DONT_RELEASE | FT_DONT_STREAM, eTF_Unknown);
SetAutoRotation(false);
SetAspectRatioCorrection(true);
SetColorComplexity(2);
SetComplexity(32);
m_meshDirty = true;
}
#if defined(FLARES_SUPPORT_EDITING)
void InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups);
#endif
EFlareType GetType() { return eFT_IrisShafts; }
void Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux);
void Load(IXmlNode* pNode);
bool GetEnableSpectrumTex() const { return m_bUseSpectrumTex; }
void SetEnableSpectrumTex(bool b) { m_bUseSpectrumTex = b; }
CTexture* GetSpectrumTex() const { return m_pSpectrumTex; }
void SetSpectrumTex(CTexture* tex) { m_pSpectrumTex = tex; }
CTexture* GetBaseTex() const { return m_pBaseTex; }
void SetBaseTex(CTexture* tex) { m_pBaseTex = tex; }
int GetNoiseSeed() const { return m_nNoiseSeed; }
void SetNoiseSeed(int seed)
{
m_nNoiseSeed = seed;
m_meshDirty = true;
}
int GetComplexity() const { return m_nComplexity; }
void SetComplexity(int n)
{
m_nComplexity = n;
m_meshDirty = true;
}
int GetColorComplexity() const { return m_nColorComplexity; }
void SetColorComplexity(int n)
{
m_nColorComplexity = n;
m_meshDirty = true;
}
int GetSmoothLevel() const { return m_nSmoothLevel; }
void SetSmoothLevel(int n)
{
m_nSmoothLevel = n;
m_meshDirty = true;
}
float GetThickness() const { return m_fThickness; }
void SetThickness(float f)
{
m_fThickness = f;
m_meshDirty = true;
}
float GetSpread() const { return m_fSpread; }
void SetSpread(float s)
{
m_fSpread = s;
m_meshDirty = true;
}
float GetThicknessNoise() const { return m_fThicknessNoiseStrength; }
void SetThicknessNoise(float noise)
{
m_fThicknessNoiseStrength = noise;
m_meshDirty = true;
}
float GetSpreadNoise() const { return m_fSpreadNoiseStrength; }
void SetSpreadNoise(float noise)
{
m_fThicknessNoiseStrength = noise;
m_meshDirty = true;
}
float GetSizeNoise() const { return m_fSizeNoiseStrength; }
void SetSizeNoise(float noise)
{
m_fSizeNoiseStrength = noise;
m_meshDirty = true;
}
float GetSpacingNoise() const { return m_fSpacingNoiseStrength; }
void SetSpacingNoise(float noise)
{
m_fSpacingNoiseStrength = noise;
m_meshDirty = true;
}
void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this) + GetMeshDataSize());
}
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_IRISSHAFTS_H
@@ -0,0 +1,578 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "MeshUtil.h"
#include "../../../CryCommon/VertexFormats.h"
#include "../../../CryCommon/MTPseudoRandom.h"
using namespace stable_rand;
CMTRand_int32 randGen;
void stable_rand::setSeed(uint32 seed) {randGen.seed(seed); }
float stable_rand::randUnit() { return randGen.GenerateFloat() * 2.f - 1.f; }
float stable_rand::randPositive() { return randGen.GenerateFloat(); }
float stable_rand::randBias(float noise) { return 1.f + randUnit() * noise; }
float computeFade(float current, float start, float end, float fadingLength)
{
if (current < start - fadingLength)
{
return 0;
}
else if (current < start)
{
return 1 - (start - current) / fadingLength;
}
else if (current > end + fadingLength)
{
return 0;
}
else if (current > end)
{
return 1 - (current - end) / fadingLength;
}
else
{
return 1;
}
}
Vec2 rotate(float x, float y, float rad)
{
Vec2 ret;
float cosRad = cos(rad);
float sinRad = sin(rad);
ret.x = x * cosRad - y * sinRad;
ret.y = y * cosRad + x * sinRad;
return ret;
}
void MeshUtil::GenDisk([[maybe_unused]] float radius, int polySides, int ringCount, bool capInnerHole, const ColorF& clr, float* ringPosArray, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut)
{
bool gCollectPosArray = false;
if (ringPosArray == NULL)
{
// create a uniformly spaced setting
ringPosArray = new float[ringCount];
float ringCountf = (float)ringCount;
for (int i = 0; i < ringCount; i++)
{
ringPosArray[i] = (i + 1) / ringCountf;
}
gCollectPosArray = true;
}
// Current strategy: whether or not capping, center pivot is always generated only not indexed in later case.
// UV mapping follows polar representation: u for thou, v for theta
DWORD dclr = clr.pack_argb8888();
vertOut.resize(polySides * ringCount + 1); // rings and the center
SVF_P3F_C4B_T2F& centerV = vertOut[0];
centerV.xyz = Vec3(0, 0, 0);
centerV.st = Vec2(0, 0);
centerV.color.dcolor = dclr;
// Generate all vertices starting from inner rings:
for (int i = 0; i < polySides; i++)
{
float theta = i / (float)polySides;
float angle = 2 * PI * theta;
float x = cos(angle);
float y = sin(angle);
//float noise = randUnit() * noiseStrength;
for (int r = 0; r < ringCount; r++)
{
float curRingRadius = ringPosArray[r];
float thou = (r + 1) / (float)(ringCount);
//curRingRadius += noise; // apply translation noise
SVF_P3F_C4B_T2F& vert = vertOut[i * ringCount + r + 1];
vert.xyz.Set(x * curRingRadius, y * curRingRadius, 0);
vert.st.set(thou, theta);
vert.color.dcolor = dclr;
}
}
// Rings' Indices;
int holeCapperIdxCount = 0;
if (capInnerHole)
{
holeCapperIdxCount = polySides * 3;
}
idxOut.resize(polySides * (ringCount - 1) * 6 + holeCapperIdxCount);
for (int i = 0; i < polySides; i++)
{
int baseVertIdx0 = i * ringCount;
for (int r = 0; r < ringCount - 1; r++)
{
// counter clock wise:
int a = baseVertIdx0 + r;
int b = a + 1;
int c = (a + ringCount + 1) % vertOut.size();
int d = (c - 1) % vertOut.size();
int baseIdx = (i * (ringCount - 1) + r) * 6 + holeCapperIdxCount;
idxOut[baseIdx] = b;
idxOut[baseIdx + 1] = c;
idxOut[baseIdx + 2] = a;
idxOut[baseIdx + 3] = a;
idxOut[baseIdx + 4] = c;
idxOut[baseIdx + 5] = d;
}
}
// indices for the capper:
if (capInnerHole)
{
// inner circle:
// vert: [nPolySide][nRing]
// index: [nPolySide][3]
for (int i = 0; i < polySides; i++)
{
int baseIdx = i * 3;
idxOut[baseIdx] = 0;
idxOut[baseIdx + 1] = 1 + i * ringCount;
idxOut[baseIdx + 2] = (i != (polySides - 1)) ? (2 + i * ringCount) : 1;
}
}
if (gCollectPosArray)
{
delete [] ringPosArray;
}
}
//Generate a hoop which consists of specified number of inscribe circles
void MeshUtil::GenHoop(float radius, int polySides, float thickness, int ringCount, const ColorF& clr, float noiseStrength, int noiseSeed, float startAngle, float endAngle, float fadeAngle, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut)
{
// use inscribe circles. Tangent point is at the origin:
setSeed(noiseSeed);
polySides *= 2;
if (ringCount < 2)
{
// Log("Warning: Illegal ring count");
ringCount = 2;
}
if (endAngle < startAngle)
{
float tmp = endAngle;
endAngle = startAngle;
startAngle = tmp;
}
float startAngleRad = startAngle / 180 * PI;
float endAngleRad = endAngle / 180 * PI;
float fadeAngleRad = fadeAngle / 180 * PI;
// Verts:
vertOut.resize(polySides * ringCount);
float innerRadius = radius - thickness;
float deltaRadius = thickness / (float)(ringCount - 1);
float deltaTheta = 1 / (float)polySides;
for (int i = 0; i < polySides; i++)
{
float spikeThetaWidth = 0.18f * deltaTheta;
float thetaLinear = i / (float)polySides + randUnit() * 0.5f * deltaTheta - spikeThetaWidth; // old linear mapping
float k = 2.6f * thetaLinear - 1.3f;
float theta = 0.5f + 0.5f * tanf(k) / tanf(1.3f);
float angle = 2 * PI * theta;
float x = cos(angle);
float y = sin(angle);
float fade = computeFade(angle, startAngleRad, endAngleRad, fadeAngleRad);
float noise = randUnit() * noiseStrength;
for (int r = 0; r < ringCount; r++)
{
float curRingRadius = innerRadius + r * deltaRadius;
float thou = r / (float)(ringCount - 1);
curRingRadius += noise; // apply translation noise
SVF_P3F_C4B_T2F& vert = vertOut[i * ringCount + r];
vert.xyz.Set((x - 1) * curRingRadius, y * curRingRadius, 0);
vert.st.set(thou, theta);
ColorF c(clr.r, clr.g, clr.b, clr.a * fade);
vert.color.dcolor = c.pack_argb8888();
}
// generate spikes
i++;
theta += 2 * spikeThetaWidth;
angle = 2 * PI * theta;
x = cos(angle);
y = sin(angle);
for (int r = 0; r < ringCount; r++)
{
float curRingRadius = innerRadius + r * deltaRadius;
float thou = r / (float)(ringCount - 1);
curRingRadius += noise; // apply translation noise
SVF_P3F_C4B_T2F& vert = vertOut[i * ringCount + r];
vert.xyz.Set((x - 1) * curRingRadius, y * curRingRadius, 0);
vert.st.set(thou, theta);
ColorF c(clr.r, clr.g, clr.b, clr.a * fade);
vert.color.dcolor = c.pack_argb8888();
}
}
// Indices;
idxOut.resize(polySides * (ringCount - 1) * 6);
for (int i = 0; i < polySides; i++)
{
int baseVertIdx0 = i * ringCount;
for (int r = 0; r < ringCount - 1; r++)
{
// counter clock wise:
int a = baseVertIdx0 + r;
int b = a + 1;
int c = (a + ringCount + 1) % vertOut.size();
int d = (c - 1) % vertOut.size();
int baseIdx = (i * (ringCount - 1) + r) * 6;
idxOut[baseIdx] = b;
idxOut[baseIdx + 1] = c;
idxOut[baseIdx + 2] = a;
idxOut[baseIdx + 3] = a;
idxOut[baseIdx + 4] = c;
idxOut[baseIdx + 5] = d;
}
}
}
void MeshUtil::GenTrapezoidFan(int numSideVert, float radius, float startAngleDegree, float endAngleDegree, float centerThickness, const ColorF& clr, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut)
{
if (endAngleDegree < startAngleDegree)
{
float tmp = endAngleDegree;
endAngleDegree = startAngleDegree;
startAngleDegree = tmp;
}
float startAngle = startAngleDegree / 180 * PI;
float endAngle = endAngleDegree / 180 * PI;
float midAngle = 0.5f * (startAngle + endAngle);
float halfAngleRange = 0.5f * (endAngle - startAngle);
float angleDelta = (endAngle - startAngle) / (numSideVert - 1);
vertOut.resize(numSideVert * 2);
float dirX = cos(midAngle);
float dirY = sin(midAngle);
DWORD dclr = clr.pack_argb8888();
for (int i = 0; i < numSideVert; i++)
{
float relativeAngle = i * angleDelta;
float theta = startAngle + relativeAngle;
float x = cos(theta);
float y = sin(theta);
float angleRatio = (theta - midAngle) / halfAngleRange;
float u = i / (float)(numSideVert - 1);
SVF_P3F_C4B_T2F& vert = vertOut[i * 2];
float yRela = angleRatio;
vert.xyz.Set((-yRela * dirY) * centerThickness, (yRela * dirX) * centerThickness, 0); // swap x,y and negate and translate
vert.st.set(u, 0);
vert.color.dcolor = dclr;
// top:
SVF_P3F_C4B_T2F& vert2 = vertOut[i * 2 + 1];
vert2.xyz.Set(x * radius, y * radius, 0);
vert2.st.set(u, 1);
vert2.color.dcolor = dclr;
}
idxOut.resize((numSideVert - 1) * 6);
for (int i = 0; i < numSideVert - 1; i++)
{
int baseVertIdx = i;
int a = baseVertIdx * 2;
int b = a + 2;
int c = b + 1;
int d = a + 1;
int baseIdx = i * 6;
idxOut[baseIdx] = b;
idxOut[baseIdx + 1] = c;
idxOut[baseIdx + 2] = a;
idxOut[baseIdx + 3] = a;
idxOut[baseIdx + 4] = c;
idxOut[baseIdx + 5] = d;
}
}
void MeshUtil::GenFan(int numSideVert, float radius, float startAngleDegree, float endAngleDegree, const ColorF& clr, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut)
{
if (endAngleDegree < startAngleDegree)
{
float tmp = endAngleDegree;
endAngleDegree = startAngleDegree;
startAngleDegree = tmp;
}
float startAngle = startAngleDegree / 180 * PI;
float endAngle = endAngleDegree / 180 * PI;
float angleDelta = (endAngle - startAngle) / (numSideVert - 1);
vertOut.resize(numSideVert + 1);
DWORD dclr = clr.pack_argb8888();
// center
SVF_P3F_C4B_T2F& centerVert = vertOut[0];
centerVert.xyz.Set(0, 0, 0);
centerVert.st.set(0, 0);
centerVert.color.dcolor = dclr;
for (int i = 0; i < numSideVert; i++)
{
float relativeAngle = i * angleDelta;
float theta = startAngle + relativeAngle;
float x = cos(theta);
float y = sin(theta);
float xLocal = cos(relativeAngle);
float yLocal = sin(relativeAngle);
// top:
SVF_P3F_C4B_T2F& vert2 = vertOut[i + 1];
vert2.xyz.Set(x * radius, y * radius, 0);
vert2.st.set(xLocal, yLocal);
vert2.color.dcolor = dclr;
}
idxOut.resize((numSideVert - 1) * 3);
for (int i = 0; i < numSideVert - 1; i++)
{
int baseVertIdx = i + 1;
int a = 0;
int b = baseVertIdx;
int c = baseVertIdx + 1;
int baseIdx = i * 3;
idxOut[baseIdx] = a;
idxOut[baseIdx + 1] = c;
idxOut[baseIdx + 2] = b;
}
}
// A shaft/falloff-fan is a simple coarse fan-shaped mesh with odd number of side-vertices.
// It's UV mapping spans a strict rectangular shape (x:[0,1,0] y:[0,1]).
// On top of the fan shape, there's a concentric beam which simulates the spike effect.
void MeshUtil::GenShaft(float radius, float centerThickness, int complexity, float startAngleDegree, float endAngleDegree, const ColorF& clr, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut)
{
if (complexity <= 1)
{
return;
}
int numSideVert = complexity;
GenTrapezoidFan(numSideVert, radius, startAngleDegree, endAngleDegree, centerThickness, clr, vertOut, idxOut);
float midAngleDegree = 0.5f * (startAngleDegree + endAngleDegree);
float halfAngleRangeDegree = 0.5f * (endAngleDegree - startAngleDegree);
const float beamWidthFactor = 0.1f;
float beamHalfAngle = halfAngleRangeDegree * beamWidthFactor;
std::vector<SVF_P3F_C4B_T2F> beamVertOut;
std::vector<uint16> beamIdxOut;
ColorF clr2 = clr * 1.1f;
GenTrapezoidFan(2, radius, midAngleDegree - beamHalfAngle, midAngleDegree + beamHalfAngle, centerThickness, clr2, beamVertOut, beamIdxOut);
}
void MeshUtil::GenStreak(float dir, float radius, float thickness, const ColorF& clr, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut)
{
static const int polySides = 24;
Matrix33 rotMx;
rotMx.SetRotationAA(dir * PI, Vec3(0, 0, 1));
DWORD dclr = clr.pack_argb8888();
vertOut.resize(polySides + 1);
SVF_P3F_C4B_T2F& centerV = vertOut[0];
centerV.xyz = Vec3(0, 0, 0);
centerV.st = Vec2(0, 0);
centerV.color.dcolor = dclr;
// Generate all vertices
for (int i = 0; i < polySides; i++)
{
float theta = i / (float)polySides;
float angle = 2 * PI * theta;
float x = cos(angle);
float y = sin(angle) * thickness;
Vec2 scale(x, y);
scale = scale * rotMx;
x = scale.x;
y = scale.y;
SVF_P3F_C4B_T2F& vert = vertOut[i + 1];
vert.xyz.Set(x * radius, y * radius, 0);
vert.st.set(1.0f, theta);
vert.color.dcolor = dclr;
}
// indices;
int centerIdxCount = polySides * 3;
idxOut.resize(centerIdxCount);
for (int i = 0; i < polySides; i++)
{
int baseIdx = i * 3;
idxOut[baseIdx] = 0;
idxOut[baseIdx + 1] = 1 + i;
idxOut[baseIdx + 2] = (i != (polySides - 1)) ? (2 + i) : 1;
}
}
void MeshUtil::GenSprites(std::vector<SpritePoint>& spriteList, float aspectRatio, bool packPivotPos, std::vector<SVF_P3F_C4B_T2F>& vertOut, [[maybe_unused]] std::vector<uint16>& idxOut)
{
vertOut.resize(spriteList.size() * 4);
for (unsigned int i = 0; i < spriteList.size(); i++)
{
SpritePoint& sprite = spriteList[i];
Vec2& pivot = sprite.pos;
float size = sprite.size;
float rot = sprite.rotation;
ColorF clr = sprite.color;
float radius = size;
DWORD dclr = clr.pack_argb8888();
int vertIdx = i * 4;
SVF_P3F_C4B_T2F& vert0 = vertOut[vertIdx];
Vec2 p = rotate(-radius, -radius, rot);
float zComp;
if (packPivotPos)
{
zComp = (float)(((int)floor((pivot.x * 0.5f + 0.5f) * 4095) << 12) | ((int)floor((pivot.y * 0.5f + 0.5f) * 4095))) / (4096 * 4096);
}
else
{
zComp = rot;
}
vert0.xyz.Set(p.x / aspectRatio + pivot.x, p.y + pivot.y, zComp);
vert0.color.dcolor = dclr;
vert0.st.set(0, 0);
SVF_P3F_C4B_T2F& vert1 = vertOut[vertIdx + 1];
p = rotate(radius, -radius, rot);
vert1.xyz.Set(p.x / aspectRatio + pivot.x, p.y + pivot.y, zComp);
vert1.color.dcolor = dclr;
vert1.st.set(1, 0);
SVF_P3F_C4B_T2F& vert2 = vertOut[vertIdx + 2];
p = rotate(radius, radius, rot);
vert2.xyz.Set(p.x / aspectRatio + pivot.x, p.y + pivot.y, zComp);
vert2.color.dcolor = dclr;
vert2.st.set(1, 1);
SVF_P3F_C4B_T2F& vert3 = vertOut[vertIdx + 3];
p = rotate(-radius, radius, rot);
vert3.xyz.Set(p.x / aspectRatio + pivot.x, p.y + pivot.y, zComp);
vert3.color.dcolor = dclr;
vert3.st.set(0, 1);
}
}
void MeshUtil::TrianglizeQuadIndices(int quadCount, std::vector<uint16>& idxOut)
{
idxOut.resize(quadCount * 6);
for (int i = 0; i < quadCount; i++)
{
int baseVertIdx = i * 4;
int a = baseVertIdx;
int b = a + 1;
int c = b + 1;
int d = c + 1;
int baseIdx = i * 6;
idxOut[baseIdx] = b;
idxOut[baseIdx + 1] = c;
idxOut[baseIdx + 2] = a;
idxOut[baseIdx + 3] = c;
idxOut[baseIdx + 4] = a;
idxOut[baseIdx + 5] = d;
}
}
void MeshUtil::GenScreenTile(float x0, float y0, float x1, float y1, ColorF clr, int rowCount, int columnCount, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut)
{
int yCount = rowCount + 1;
int xCount = columnCount + 1;
vertOut.resize(xCount * yCount);
DWORD dclr = clr.pack_argb8888();
float xSpan = x1 - x0;
float ySpan = y1 - y0;
float xDelta = xSpan / columnCount;
float yDelta = ySpan / rowCount;
float uDelta = 1.f / columnCount;
float vDelta = 1.f / rowCount;
for (int j = 0; j < yCount; j++)
{
for (int i = 0; i < xCount; i++)
{
SVF_P3F_C4B_T2F& vert = vertOut[ i + j * xCount ];
vert.xyz.Set(x0 + xDelta * i, y0 + yDelta * j, 0);
vert.st.set(uDelta * i, vDelta * j);
vert.color.dcolor = dclr;
}
}
idxOut.resize(rowCount * columnCount * 6);
for (int j = 0; j < rowCount; j++)
{
for (int i = 0; i < columnCount; i++)
{
int a = i + j * xCount;
int b = a + 1;
int c = (i + 1) + (j + 1) * xCount;
int d = c - 1;
int baseIdx = (i + j * columnCount) * 6;
idxOut[ baseIdx + 0 ] = b;
idxOut[ baseIdx + 1 ] = c;
idxOut[ baseIdx + 2 ] = a;
idxOut[ baseIdx + 3 ] = a;
idxOut[ baseIdx + 4 ] = c;
idxOut[ baseIdx + 5 ] = d;
}
}
}
@@ -0,0 +1,73 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_MESHUTIL_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_MESHUTIL_H
#pragma once
#include "../../../CryCommon/VertexFormats.h"
namespace stable_rand
{
void setSeed(uint32 seed);
float randUnit();
float randPositive();
float randBias(float noise);
}
struct SpritePoint
{
Vec2 pos;
float size;
float brightness;
float rotation;
ColorF color;
SpritePoint(const Vec2& _pos, float _brightness)
: pos(_pos)
, brightness(_brightness)
, size(0.1f)
, rotation(0)
{
color.set(1, 1, 1, 1);
}
SpritePoint()
: brightness(1)
, size(0.1f)
, rotation(0)
{
pos.set(0, 0);
color.set(1, 1, 1, 1);
}
};
class MeshUtil
{
public:
static void GenDisk(float radius, int polySides, int ringCount, bool capInnerHole, const ColorF& clr, float* ringPosArray, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut);
static void GenHoop(float radius, int polySides, float thickness, int ringCount, const ColorF& clr, float noiseStrength, int noiseSeed, float startAngle, float endAngle, float fadeAngle, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut);
static void GenTrapezoidFan(int numSideVert, float radius, float startAngleDegree, float endAngleDegree, float centerThickness, const ColorF& clr, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut);
static void GenFan(int numSideVert, float radius, float startAngleDegree, float endAngleDegree, const ColorF& clr, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut);
//A falloff fan is a simple coarse fan-shaped mesh with odd number of side-vertices.
//It's UV mapping spans a strict rectanglular shape (x:[0,1,0] y:[0,1]).
//On top of the fan shape, there's a concentric beam which simulates the spike effect.
static void GenShaft(float radius, float centerThickness, int complexity, float startAngleDegree, float endAngleDegree, const ColorF& clr, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut);
static void GenStreak(float dir, float radius, float thickness, const ColorF& clr, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut);
static void GenSprites(std::vector<SpritePoint>& spriteList, float aspectRatio, bool packPivotPos, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut);
static void TrianglizeQuadIndices(int quadCount, std::vector<uint16>& idxOut);
static void GenScreenTile(float x0, float y0, float x1, float y1, ColorF clr, int rowCount, int columnCount, std::vector<SVF_P3F_C4B_T2F>& vertOut, std::vector<uint16>& idxOut);
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_MESHUTIL_H
@@ -0,0 +1,426 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "OpticsElement.h"
#include "../CryNameR.h"
#include "../../XRenderD3D9/DriverD3D.h"
#include "RootOpticsElement.h"
#include "../Textures/Texture.h"
#include "../Common/Textures/TextureManager.h"
#include "FlareSoftOcclusionQuery.h"
#if defined(FLARES_SUPPORT_EDITING)
AZStd::vector<FuncVariableGroup> COpticsElement::GetEditorParamGroups()
{
if (m_paramGroups.empty())
{
InitEditorParamGroups(m_paramGroups);
}
return m_paramGroups;
}
#define MFPtr(FUNC_NAME) (Optics_MFPtr)(&COpticsElement::FUNC_NAME)
void COpticsElement::InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups)
{
FuncVariableGroup baseGroup;
baseGroup.SetName("Common");
baseGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Size", "Size", this, MFPtr(SetSize), MFPtr(GetSize)));
baseGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Perspective factor", "Perspective factor", this, MFPtr(SetPerspectiveFactor), MFPtr(GetPerspectiveFactor)));
baseGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Distance Fading factor", "Distance fading factor", this, MFPtr(SetDistanceFadingFactor), MFPtr(GetDistanceFadingFactor)));
baseGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Brightness", "Brightness", this, MFPtr(SetBrightness), MFPtr(GetBrightness)));
baseGroup.AddVariable(new OpticsMFPVariable(e_VEC2, "Position", "The relative position to light", this, MFPtr(SetMovement), MFPtr(GetMovement)));
baseGroup.AddVariable(new OpticsMFPVariable(e_COLOR, "Tint", "Basic tint", this, MFPtr(SetColor), MFPtr(GetColor)));
baseGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Orbit angle", "The rotation angle of the virtual light source", this, MFPtr(SetOrbitAngle), MFPtr(GetOrbitAngle)));
baseGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Occlusion Interaction", "Enable various flare interaction with the occlusion", this, MFPtr(SetOccBokehEnabled), MFPtr(IsOccBokehEnabled)));
baseGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Auto Rotation", "Enable Auto Rotation around the pivot", this, MFPtr(SetAutoRotation), MFPtr(HasAutoRotation)));
baseGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Correct Aspect Ratio", "Correct aspect ratio", this, MFPtr(SetAspectRatioCorrection), MFPtr(HasAspectRatioCorrection)));
groups.push_back(baseGroup);
FuncVariableGroup sensorGroup;
sensorGroup.SetName("Sensor");
sensorGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Sensor image size variation factor", "sensor image size variation factor", this, MFPtr(SetSensorSizeFactor), MFPtr(GetSensorSizeFactor)));
sensorGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Sensor image brightness variation factor", "sensor image brightness variation factor", this, MFPtr(SetSensorBrightnessFactor), MFPtr(GetSensorBrightnessFactor)));
groups.push_back(sensorGroup);
FuncVariableGroup xformGroup;
xformGroup.SetName("Transformation");
xformGroup.AddVariable(new OpticsMFPVariable(e_VEC2, "Scale", "Scale", this, MFPtr(SetScale), MFPtr(GetScale)));
xformGroup.AddVariable(new OpticsMFPVariable(e_VEC2, "Translation", "Translation", this, MFPtr(SetTranslation), MFPtr(GetTranslation)));
xformGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Rotation", "Rotation", this, MFPtr(SetRotation), MFPtr(GetRotation)));
groups.push_back(xformGroup);
FuncVariableGroup dynamicsGroup;
dynamicsGroup.SetName("Dynamics");
dynamicsGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Enable", "Enable.", this, MFPtr(SetDynamicsEnabled), MFPtr(GetDynamicsEnabled)));
dynamicsGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Trigger Invert", "Invert the trigger area.", this, MFPtr(SetDynamicsInvert), MFPtr(GetDynamicsInvert)));
dynamicsGroup.AddVariable(new OpticsMFPVariable(e_VEC2, "Trigger Offset", "Offset from the center of the screen.", this, MFPtr(SetDynamicsOffset), MFPtr(GetDynamicsOffset)));
dynamicsGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Trigger Range", "How much influence the trigger has.", this, MFPtr(SetDynamicsRange), MFPtr(GetDynamicsRange)));
dynamicsGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Trigger Falloff", "Falloff strength of the trigger area.", this, MFPtr(SetDynamicsFalloff), MFPtr(GetDynamicsFalloff)));
groups.push_back(dynamicsGroup);
}
#undef MFPtr
#endif
void COpticsElement::Load(IXmlNode* pNode)
{
XmlNodeRef pCommonNode = pNode->findChild("Common");
if (pCommonNode)
{
float fSize(m_fSize);
if (pCommonNode->getAttr("Size", fSize))
{
SetSize(fSize);
}
float fPerspectiveFactor(m_fPerpectiveFactor);
if (pCommonNode->getAttr("Perspectivefactor", fPerspectiveFactor))
{
SetPerspectiveFactor(fPerspectiveFactor);
}
float fDistanceFadingFactor = m_fDistanceFadingFactor;
if (pCommonNode->getAttr("DistanceFadingfactor", fDistanceFadingFactor))
{
SetDistanceFadingFactor(fDistanceFadingFactor);
}
float fBrightness = m_fBrightness;
if (pCommonNode->getAttr("Brightness", fBrightness))
{
SetBrightness(fBrightness);
}
Vec2 vPos(m_vMovement);
if (pCommonNode->getAttr("Position", vPos))
{
SetMovement(vPos);
}
Vec3 color(m_Color.r, m_Color.g, m_Color.b);
int nAlpha((int)(m_Color.a * 255.0f));
if (pCommonNode->getAttr("Tint", color) && pCommonNode->getAttr("Tint.alpha", nAlpha))
{
SetColor(ColorF(color.x, color.y, color.z, (float)nAlpha / 255.0f));
}
float fOrbitAngle(m_fOrbitAngle);
if (pCommonNode->getAttr("Orbitangle", fOrbitAngle))
{
SetOrbitAngle(fOrbitAngle);
}
bool bOcclusionBokeh(m_bOcclusionBokeh);
if (pCommonNode->getAttr("OcclusionInteraction", bOcclusionBokeh))
{
SetOccBokehEnabled(bOcclusionBokeh);
}
bool bAutoRotation(m_bAutoRotation);
if (pCommonNode->getAttr("AutoRotation", bAutoRotation))
{
SetAutoRotation(bAutoRotation);
}
bool bCorrectAspectRatio(m_bCorrectAspectRatio);
if (pCommonNode->getAttr("CorrectAspectRatio", bCorrectAspectRatio))
{
SetAspectRatioCorrection(bCorrectAspectRatio);
}
}
XmlNodeRef pSensorNode = pNode->findChild("Sensor");
if (pSensorNode)
{
float fSensorSizeFactor(m_fSensorSizeFactor);
if (pSensorNode->getAttr("Sensorimagesizevariationfactor", fSensorSizeFactor))
{
SetSensorSizeFactor(fSensorSizeFactor);
}
float fSensorBrightnessFactor = m_fSensorBrightnessFactor;
if (pSensorNode->getAttr("Sensorimagebrightnessvariationfactor", fSensorBrightnessFactor))
{
SetSensorBrightnessFactor(fSensorBrightnessFactor);
}
}
XmlNodeRef pTransformationNode = pNode->findChild("Transformation");
if (pTransformationNode)
{
Vec2 vScale(xform_scale);
if (pTransformationNode->getAttr("Scale", vScale))
{
SetScale(vScale);
}
Vec2 vTranslation(xform_translate);
if (pTransformationNode->getAttr("Translation", vTranslation))
{
SetTranslation(vTranslation);
}
float fRotation(xform_rotation);
if (pTransformationNode->getAttr("Rotation", fRotation))
{
SetRotation(fRotation);
}
}
XmlNodeRef pDynamicsNode = pNode->findChild("Dynamics");
if (pDynamicsNode)
{
bool bEnable(m_bEnabled);
if (pDynamicsNode->getAttr("Enable", bEnable))
{
SetDynamicsEnabled(bEnable);
}
bool bDynamicInvert(m_bDynamicsInvert);
if (pDynamicsNode->getAttr("TriggerInvert", bDynamicInvert))
{
SetDynamicsInvert(bDynamicInvert);
}
Vec2 vDynamicsOffset(m_vDynamicsOffset);
if (pDynamicsNode->getAttr("TriggerOffset", vDynamicsOffset))
{
SetDynamicsOffset(vDynamicsOffset);
}
float fDynamicsRange(m_fDynamicsRange);
if (pDynamicsNode->getAttr("TriggerRange", fDynamicsRange))
{
SetDynamicsRange(fDynamicsRange);
}
float fDynamicsFalloff(m_fDynamicsFalloff);
if (pDynamicsNode->getAttr("TriggerFalloff", fDynamicsFalloff))
{
SetDynamicsFalloff(fDynamicsFalloff);
}
}
}
RootOpticsElement* COpticsElement::GetRoot()
{
IOpticsElementBase* parent = this;
do
{
parent = parent->GetParent();
if (parent == NULL)
{
return NULL;
}
} while (parent->GetType() != eFT_Root);
return (RootOpticsElement*)parent;
}
void COpticsElement::validateGlobalVars(SAuxParams& aux)
{
if (m_pParent)
{
m_globalPerpectiveFactor = m_fPerpectiveFactor * m_pParent->m_globalPerpectiveFactor;
m_globalDistanceFadingFactor = m_fDistanceFadingFactor * m_pParent->m_globalDistanceFadingFactor;
m_globalSensorSizeFactor = m_fSensorSizeFactor * m_pParent->m_globalSensorSizeFactor;
float sensorSizeFactor = 1 + m_globalSensorSizeFactor * aux.sensorVariationValue;
m_globalSensorBrightnessFactor = m_fSensorBrightnessFactor * m_pParent->m_globalSensorBrightnessFactor;
float sensorBrightnessFactor = fabs(1 + m_globalSensorBrightnessFactor * aux.sensorVariationValue);
float perspectiveShortening = 1 + m_globalPerpectiveFactor * (aux.perspectiveShortening - 1);
m_globalSize = m_fSize * m_pParent->m_globalSize * perspectiveShortening * sensorSizeFactor; // remember to multiply the additional perspective factor
if (aux.bMultiplyColor)
{
m_globalColor = m_Color * m_pParent->m_globalColor;
}
else
{
m_globalColor = ColorF(m_Color.r + m_pParent->m_globalColor.r,
m_Color.g + m_pParent->m_globalColor.g,
m_Color.b + m_pParent->m_globalColor.b,
m_Color.a * m_pParent->m_globalColor.a);
}
float fading = clamp_tpl(1 - 1000.f * m_globalDistanceFadingFactor * aux.linearDepth, 0.0f, 1.f);
float brightness = m_fBrightness * sensorBrightnessFactor * fading;
m_globalFlareBrightness = brightness * m_pParent->m_globalFlareBrightness;
m_globalShaftBrightness = brightness * m_pParent->m_globalShaftBrightness;
m_globalMovement.x = m_vMovement.x * m_pParent->m_globalMovement.x;
m_globalMovement.y = m_vMovement.y * m_pParent->m_globalMovement.y;
if (!m_pParent->m_globalTransform.IsIdentity())
{
m_globalTransform = m_mxTransform * m_pParent->m_globalTransform;
}
else
{
m_globalTransform = m_mxTransform;
}
m_globalOrbitAngle = m_fOrbitAngle + m_pParent->m_globalOrbitAngle;
m_globalOcclusionBokeh = m_bOcclusionBokeh & m_pParent->m_globalOcclusionBokeh;
m_globalAutoRotation = m_bAutoRotation & m_pParent->m_bAutoRotation;
m_globalCorrectAspectRatio = m_bCorrectAspectRatio & m_pParent->m_bCorrectAspectRatio;
}
}
void COpticsElement::updateXformMatrix()
{
Matrix33 scaleMx;
scaleMx.SetScale(Vec3(xform_scale.x, xform_scale.y, 1));
Matrix33 rotMx;
rotMx.SetRotationAA(xform_rotation * 2.0f * PI, Vec3(0, 0, 1));
Matrix33 combine = rotMx * scaleMx;
combine.SetColumn(2, Vec3(xform_translate.x, xform_translate.y, 1));
SetTransform(combine);
}
const Vec3 COpticsElement::computeOrbitPos(const Vec3& vSrcProjPos, float orbitAngle)
{
if (orbitAngle < 0.01f && orbitAngle > -0.01f)
{
return vSrcProjPos;
}
const Vec2 oriVec (vSrcProjPos.x - 0.5f, vSrcProjPos.y - 0.5f);
float orbitSin = 0.0f, orbitCos = 0.0f;
sincos_tpl(orbitAngle, &orbitSin, &orbitCos);
const Vec2 resultVec = Vec2(oriVec.x * orbitCos - oriVec.y * orbitSin, oriVec.y * orbitCos + oriVec.x * orbitSin);
return Vec3(resultVec.x + 0.5f, resultVec.y + 0.5f, vSrcProjPos.z);
}
void COpticsElement::ApplyVSParam_WPosAndSize(CShader* shader, const Vec3& wpos)
{
static CCryNameR wPosAndSizeName("wposAndSize");
Vec4 wPosAndSizeParam(wpos, m_globalSize);
shader->FXSetVSFloat(wPosAndSizeName, &wPosAndSizeParam, 1);
}
void COpticsElement::ApplyOcclusionPattern(CShader* shader)
{
if (GetRoot() == NULL)
{
return;
}
static STexState bilinearTS(FILTER_LINEAR, true);
CFlareSoftOcclusionQuery* pSoftOcclusionQuery = GetRoot()->GetOcclusionQuery();
if (pSoftOcclusionQuery && pSoftOcclusionQuery->GetGatherTexture())
{
CTexture* pGatherTex = pSoftOcclusionQuery->GetGatherTexture();
pGatherTex->Apply(5, CTexture::GetTexState(bilinearTS));
float x0 = 0, y0 = 0, x1 = 0, y1 = 0;
pSoftOcclusionQuery->GetDomainInTexture(x0, y0, x1, y1);
float width, height;
pSoftOcclusionQuery->GetSectorSize(width, height);
static CCryNameR occPatternInfoName("occPatternInfo");
const Vec4 occPatternInfo((x0 + x1) * 0.5f, (y0 + y1) * 0.5f, width, height);
shader->FXSetPSFloat(occPatternInfoName, &occPatternInfo, 1);
}
else
{
CTextureManager::Instance()->GetBlackTexture()->Apply(5, CTexture::GetTexState(bilinearTS));
}
}
void COpticsElement::ApplyOcclusionBokehFlag([[maybe_unused]] CShader* shader)
{
if (m_globalOcclusionBokeh)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE3];
}
}
void COpticsElement::ApplySpectrumTexFlag([[maybe_unused]] CShader* shader, bool enabled)
{
if (enabled)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE2];
}
}
void COpticsElement::ApplyExternTintAndBrightnessVS(CShader* shader, ColorF& cExTint, float fExBrt)
{
static CCryNameR exTintName("externTint");
Vec4 exTintParam(cExTint.r * fExBrt, cExTint.g * fExBrt, cExTint.b * fExBrt, cExTint.a);
shader->FXSetVSFloat(exTintName, &exTintParam, 1);
}
void COpticsElement::ApplyVSParam_Xform(CShader* shader, Matrix33& mx33)
{
static CCryNameR xformName("xform");
Matrix44 mx44(mx33);
mx44.Transpose();
shader->FXSetVSFloat(xformName, reinterpret_cast<Vec4*>(mx44.GetData()), 3);
}
void COpticsElement::ApplyVSParam_Dynamics(CShader* shader, const Vec3& lightProjPos)
{
static CCryNameR dynamicsName("dynamics");
float fTriggerArea = 1.0f;
if (m_bDynamics)
{
float fRange = 1.0f / max(0.01f, m_fDynamicsRange);
float fFalloff = m_fDynamicsFalloff;
Vec2 vProjPos;
vProjPos.x = (lightProjPos.x * 2.f - 1.f) + m_vDynamicsOffset.x;
vProjPos.y = (lightProjPos.y * 2.f - 1.f) + m_vDynamicsOffset.y;
fTriggerArea = vProjPos.GetLength();
fTriggerArea = m_bDynamicsInvert ? 1.0f - fTriggerArea : fTriggerArea;
fTriggerArea = powf(clamp_tpl(1.f - fTriggerArea * fRange, 0.f, 1.f), fFalloff);
}
Vec4 dynamicsParam(fTriggerArea, 1, 1, 1);
shader->FXSetVSFloat(dynamicsName, &dynamicsParam, 1);
}
void COpticsElement::ApplyGeneralFlags([[maybe_unused]] CShader* shader)
{
if (m_globalAutoRotation)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
}
if (m_globalCorrectAspectRatio)
{
gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE5];
}
}
void COpticsElement::ApplyVSParam_LightProjPos(CShader* shader, const Vec3& lightProjPos)
{
static CCryNameR ccrName("lightProjPos");
Vec4 lpposParam(lightProjPos.x, lightProjPos.y, lightProjPos.z, 0);
shader->FXSetVSFloat(ccrName, &lpposParam, 1);
}
void COpticsElement::ApplyPSParam_LightProjPos(CShader* shader, const Vec3& lightProjPos)
{
static CCryNameR ccrName("lightProjPos");
Vec4 lpposParam(lightProjPos.x, lightProjPos.y, lightProjPos.z, 0);
shader->FXSetPSFloat(ccrName, &lpposParam, 1);
}
void COpticsElement::GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
}
@@ -0,0 +1,343 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSELEMENT_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSELEMENT_H
#pragma once
#include "CryString.h"
#include "Cry_Vector2.h"
#include "Cry_Vector3.h"
#include "Cry_Matrix33.h"
#include "Cry_Color.h"
#include "IFlares.h"
class CD3D9Renderer;
class CTexture;
class RootOpticsElement;
namespace LensOpConst
{
static Vec4 _LO_DEF_VEC4(1.f, 1.f, 1.f, 0.f);
static Vec2 _LO_DEF_VEC2(0.f, 0.f);
static Vec2 _LO_DEF_VEC2_I(1.f, 1.f);
static Vec2 _LO_DEF_ANGLE(-90.f, 90.f);
static Matrix33 _LO_DEF_MX33(IDENTITY);
static ColorF _LO_DEF_CLR(1.f, 1.f, 1.f, 0.2f);
static ColorF _LO_DEF_CLR_BLK(0.f, 0.f, 0.f, 0.0f);
static float _LO_MIN(1e-6f);
}
typedef MFPVariable<IOpticsElementBase> OpticsMFPVariable;
typedef void (IOpticsElementBase::* Optics_MFPtr)(void);
class COpticsElement
: public IOpticsElementBase
{
public:
struct SAuxParams
{
float perspectiveShortening;
float linearDepth;
float distance;
float sensorVariationValue;
float viewAngleFalloff;
bool attachToSun;
bool bMultiplyColor;
bool bForceRender;
};
private:
Vec2 xform_scale;
Vec2 xform_translate;
float xform_rotation;
protected:
COpticsElement* m_pParent;
Vec2 m_globalMovement;
Matrix33 m_globalTransform;
ColorF m_globalColor;
float m_globalFlareBrightness;
float m_globalShaftBrightness;
float m_globalSize;
float m_globalPerpectiveFactor;
float m_globalDistanceFadingFactor;
float m_globalOrbitAngle;
float m_globalSensorSizeFactor;
float m_globalSensorBrightnessFactor;
bool m_globalAutoRotation : 1;
bool m_globalCorrectAspectRatio : 1;
bool m_globalOcclusionBokeh : 1;
string m_name;
bool m_bEnabled : 1;
protected:
Matrix33 m_mxTransform;
float m_fSize;
float m_fPerpectiveFactor;
float m_fDistanceFadingFactor;
ColorF m_Color;
float m_fBrightness;
Vec2 m_vMovement;
float m_fOrbitAngle;
float m_fSensorSizeFactor;
float m_fSensorBrightnessFactor;
Vec2 m_vDynamicsOffset;
float m_fDynamicsRange;
float m_fDynamicsFalloff;
bool m_bAutoRotation : 1;
bool m_bCorrectAspectRatio : 1;
bool m_bOcclusionBokeh : 1;
bool m_bDynamics : 1;
bool m_bDynamicsInvert : 1;
#if defined(FLARES_SUPPORT_EDITING)
AZStd::vector<FuncVariableGroup> m_paramGroups;
#endif
public:
COpticsElement (const char* name, float size = 0.3f, const float brightness = 1.0f, const ColorF& color = LensOpConst::_LO_DEF_CLR)
: m_pParent(0)
, m_bEnabled(true)
, m_fPerpectiveFactor(0)
, m_globalPerpectiveFactor(1)
, m_fOrbitAngle(0)
, m_bOcclusionBokeh(false)
, m_fSensorSizeFactor(0)
, m_fSensorBrightnessFactor(0)
, m_fDistanceFadingFactor(1)
{
m_name = name;
m_vMovement = Vec2(1.f, 1.f);
m_fSize = size;
m_Color = color;
m_mxTransform = LensOpConst::_LO_DEF_MX33;
m_globalMovement = LensOpConst::_LO_DEF_VEC2_I;
m_globalTransform = Matrix33::CreateIdentity();
m_globalColor.Set(1.f, 1.f, 1.f, 1.f);
m_globalFlareBrightness = 1.f;
m_globalShaftBrightness = 1.f;
m_globalSize = 1;
m_fBrightness = brightness;
m_bAutoRotation = false;
m_bCorrectAspectRatio = true;
xform_scale.set(1.f, 1.f);
xform_rotation = 0.f;
xform_translate.set(0.f, 0.f);
m_bDynamics = false;
m_vDynamicsOffset.set(0.f, 0.f);
m_fDynamicsRange = 1.f;
m_bDynamicsInvert = false;
m_fDynamicsFalloff = 1.f;
}
virtual ~COpticsElement()
{
}
virtual void Load(IXmlNode* pNode);
COpticsElement(const COpticsElement& copyFrom)
{
*this = copyFrom;
#if defined(FLARES_SUPPORT_EDITING)
m_paramGroups.clear();
#endif
}
IOpticsElementBase* GetParent() const
{
return m_pParent;
}
RootOpticsElement* GetRoot();
string GetName() const { return m_name; }
void SetName(const char* newName)
{
m_name = newName;
}
bool IsEnabled() const { return m_bEnabled; }
float GetSize() const { return m_fSize; }
float GetPerspectiveFactor() const { return m_fPerpectiveFactor; }
float GetDistanceFadingFactor() const { return m_fDistanceFadingFactor; }
float GetBrightness() const { return m_fBrightness; }
ColorF GetColor() const { return m_Color; }
Vec2 GetMovement() const { return m_vMovement; }
float GetOrbitAngle() const {return m_fOrbitAngle; }
float GetSensorSizeFactor() const { return m_fSensorSizeFactor; }
float GetSensorBrightnessFactor() const { return m_fSensorBrightnessFactor; }
bool IsOccBokehEnabled() const { return m_bOcclusionBokeh; }
bool HasAutoRotation() const { return m_bAutoRotation; }
bool HasAspectRatioCorrection() const { return m_bCorrectAspectRatio; }
void SetEnabled(bool b) override { m_bEnabled = b; }
void SetSize(float s) override { m_fSize = s; }
void SetPerspectiveFactor(float p) override { m_fPerpectiveFactor = p; }
void SetDistanceFadingFactor(float p) override { m_fDistanceFadingFactor = p; }
void SetBrightness(float b) override { m_fBrightness = b; }
void SetColor(ColorF color) { m_Color = color; Invalidate(); }
void SetMovement(Vec2 movement)
{
m_vMovement = movement;
if (fabs(m_vMovement.x) < 0.0001f)
{
m_vMovement.x = 0.001f;
}
if (fabs(m_vMovement.y) < 0.0001f)
{
m_vMovement.y = 0.001f;
}
}
void SetTransform(const Matrix33& xform) override { m_mxTransform = xform; }
void SetOccBokehEnabled(bool b) override { m_bOcclusionBokeh = b; }
void SetOrbitAngle(float orbitAngle) override { m_fOrbitAngle = orbitAngle; }
void SetSensorSizeFactor(float sizeFactor) override { m_fSensorSizeFactor = sizeFactor; }
void SetSensorBrightnessFactor(float brtFactor) override { m_fSensorBrightnessFactor = brtFactor; }
void SetAutoRotation(bool b) override { m_bAutoRotation = b; }
void SetAspectRatioCorrection(bool b) override { m_bCorrectAspectRatio = b; }
void SetParent(COpticsElement* pParent)
{
m_pParent = pParent;
}
virtual void GetMemoryUsage(ICrySizer* pSizer) const;
bool IsVisible() const
{
return m_globalColor.a > LensOpConst::_LO_MIN && m_globalFlareBrightness > LensOpConst::_LO_MIN;
}
virtual void Render([[maybe_unused]] SLensFlareRenderParam* pParam, [[maybe_unused]] const Vec3& vPos){assert(0); }
protected:
void updateXformMatrix();
virtual void Invalidate() {}
public:
void SetScale(Vec2 scale)
{
xform_scale = scale;
updateXformMatrix();
}
void SetRotation(float rot)
{
xform_rotation = rot;
updateXformMatrix();
}
void SetTranslation(Vec2 xlation)
{
xform_translate = xlation;
updateXformMatrix();
}
Vec2 GetScale() { return xform_scale; }
Vec2 GetTranslation() { return xform_translate; }
float GetRotation() { return xform_rotation; }
void SetDynamicsEnabled(bool enable) { m_bDynamics = enable; }
void SetDynamicsOffset(Vec2 offset) { m_vDynamicsOffset = offset; }
void SetDynamicsRange(float range) { m_fDynamicsRange = range; }
void SetDynamicsInvert(bool invert) { m_bDynamicsInvert = invert; }
void SetDynamicsFalloff(float falloff) { m_fDynamicsFalloff = falloff; }
bool GetDynamicsEnabled() const { return m_bDynamics; }
Vec2 GetDynamicsOffset() const { return m_vDynamicsOffset; }
float GetDynamicsRange() const { return m_fDynamicsRange; }
bool GetDynamicsInvert() const { return m_bDynamicsInvert; }
float GetDynamicsFalloff() const { return m_fDynamicsFalloff; }
virtual void AddElement([[maybe_unused]] IOpticsElementBase* pElement) {}
virtual void InsertElement([[maybe_unused]] int nPos, [[maybe_unused]] IOpticsElementBase* pElement) {}
virtual void Remove([[maybe_unused]] int i) {}
virtual void RemoveAll() {}
virtual int GetElementCount() const {return 0; }
virtual IOpticsElementBase* GetElementAt([[maybe_unused]] int i) const
{
#ifndef RELEASE
iLog->Log("ERROR");
__debugbreak();
#endif
return 0;
}
#if defined(FLARES_SUPPORT_EDITING)
virtual AZStd::vector<FuncVariableGroup> GetEditorParamGroups();
#endif
protected:
#if defined(FLARES_SUPPORT_EDITING)
virtual void InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups);
#endif
public:
virtual void validateGlobalVars(SAuxParams& aux);
float computeMovementLocationX(const Vec3& vSrcProjPos)
{
return (vSrcProjPos.x - 0.5f) * m_globalMovement.x + 0.5f;
}
float computeMovementLocationY(const Vec3& vSrcProjPos)
{
return (vSrcProjPos.y - 0.5f) * m_globalMovement.y + 0.5f;
}
static const Vec3 computeOrbitPos(const Vec3& vSrcProjPos, float orbitAngle);
void ApplyVSParam_WPosAndSize(CShader* shader, const Vec3& wpos);
void ApplyOcclusionPattern(CShader* shader);
void ApplyGeneralFlags(CShader* shader);
void ApplyOcclusionBokehFlag(CShader* shader);
void ApplySpectrumTexFlag(CShader* shader, bool enabled);
void ApplyExternTintAndBrightnessVS(CShader* shader, ColorF& cExTint, float fExBrt);
void ApplyVSParam_Xform(CShader* shader, Matrix33& mx33);
void ApplyVSParam_Dynamics(CShader* shader, const Vec3& projPos);
void ApplyPSParam_LightProjPos(CShader* shader, const Vec3& lightProjPos);
void ApplyVSParam_LightProjPos(CShader* shader, const Vec3& lightProjPos);
void ApplyCommonVSParams(CShader* shader, const Vec3& wpos, const Vec3& lightProjPos)
{
//If aspect ratio correction is on (default) we want to adjust the global
//transform to re-scale the flare geometry to keep a constant size regardless of
//the window's aspect ratio.
//This used to be handled in the shader with params passed from a method ApplyVSParams_ScreenWidthHeight.
//But that only applied to ghost flares and why bother doing that per-vertex when we can do it once
//per constant buffer.
if (HasAspectRatioCorrection())
{
const float inverseAspectRatio = static_cast<float>(gEnv->pRenderer->GetHeight()) / static_cast<float>(gEnv->pRenderer->GetWidth());
//Adjust the entire base to avoid warping when rotation is applied
const Vec3 adjustedXBasis = m_globalTransform.GetRow(0) * inverseAspectRatio;
m_globalTransform.SetRow(0, adjustedXBasis);
}
ApplyVSParam_WPosAndSize(shader, wpos);
ApplyVSParam_Xform(shader, m_globalTransform);
ApplyVSParam_Dynamics(shader, lightProjPos);
}
virtual EFlareType GetType() { return eFT__Base__; }
virtual bool IsGroup() const { return false; }
virtual void Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux) = 0;
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSELEMENT_H
@@ -0,0 +1,61 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "OpticsFactory.h"
#include "RootOpticsElement.h"
#include "OpticsElement.h"
#include "Ghost.h"
#include "Glow.h"
#include "ChromaticRing.h"
#include "CameraOrbs.h"
#include "IrisShafts.h"
#include "Streaks.h"
#include "ImageSpaceShafts.h"
#include "OpticsReference.h"
#include "OpticsProxy.h"
#include "OpticsPredef.hpp"
IOpticsElementBase* COpticsFactory::Create(EFlareType type) const
{
switch (type)
{
case eFT_Root:
return new RootOpticsElement;
case eFT_Group:
return new COpticsGroup("[Group]");
case eFT_Ghost:
return new CLensGhost("Ghost");
case eFT_MultiGhosts:
return new CMultipleGhost("Multi Ghost");
case eFT_Glow:
return new Glow("Glow");
case eFT_IrisShafts:
return new IrisShafts("Iris Shafts");
case eFT_ChromaticRing:
return new ChromaticRing("Chromatic Ring");
case eFT_CameraOrbs:
return new CameraOrbs("Orbs");
case eFT_ImageSpaceShafts:
return new ImageSpaceShafts("Vol Shafts");
case eFT_Streaks:
return new Streaks("Streaks");
case eFT_Reference:
return new COpticsReference("Reference");
case eFT_Proxy:
return new COpticsProxy("Proxy");
default:
return NULL;
}
}
@@ -0,0 +1,35 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSFACTORY_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSFACTORY_H
#pragma once
#include "IFlares.h"
class COpticsFactory
{
private:
COpticsFactory(){}
public:
static COpticsFactory* GetInstance()
{
static COpticsFactory instance;
return &instance;
}
IOpticsElementBase* Create(EFlareType type) const;
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSFACTORY_H
@@ -0,0 +1,130 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "../CryNameR.h"
#include "../../XRenderD3D9/DriverD3D.h"
#include "../Textures/Texture.h"
#include "OpticsGroup.h"
#if defined(FLARES_SUPPORT_EDITING)
#define MFPtr(FUNC_NAME) (Optics_MFPtr)(&COpticsGroup::FUNC_NAME)
void COpticsGroup::InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups)
{
COpticsElement::InitEditorParamGroups(groups);
}
#undef MFPtr
#endif
void COpticsGroup::_init()
{
SetSize(1.f);
SetAutoRotation(true);
}
COpticsGroup::COpticsGroup(const char* name, COpticsElement* ghost, ...)
: COpticsElement(name)
{
_init();
va_list arg;
va_start(arg, ghost);
COpticsElement* curArg;
while ((curArg = va_arg(arg, COpticsElement*)) != NULL)
{
Add(curArg);
}
va_end(arg);
}
COpticsGroup& COpticsGroup::Add(IOpticsElementBase* pElement)
{
children.push_back(pElement);
((COpticsElement*)&*pElement)->SetParent(this);
return *this;
}
void COpticsGroup::InsertElement(int nPos, IOpticsElementBase* pElement)
{
children.insert(children.begin() + nPos, pElement);
((COpticsElement*)&*pElement)->SetParent(this);
}
void COpticsGroup::Remove(int i)
{
children.erase(children.begin() + i);
}
void COpticsGroup::RemoveAll()
{
children.clear();
}
int COpticsGroup::GetElementCount() const { return children.size(); }
IOpticsElementBase* COpticsGroup::GetElementAt(int i) const { return children.at(i); }
void COpticsGroup::SetElementAt(int i, IOpticsElementBase* elem)
{
if (i < 0 || i > GetElementCount())
{
return;
}
children[i] = elem;
((COpticsElement*)&*children[i])->SetParent(this);
}
void COpticsGroup::validateGlobalVars(SAuxParams& aux)
{
COpticsElement::validateGlobalVars(aux);
validateChildrenGlobalVars(aux);
}
void COpticsGroup::validateChildrenGlobalVars(SAuxParams& aux)
{
for (uint i = 0; i < children.size(); i++)
{
((COpticsElement*)GetElementAt(i))->validateGlobalVars(aux);
}
}
void COpticsGroup::Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux)
{
PROFILE_LABEL_SCOPE("LensEfxGroup");
for (uint i = 0; i < children.size(); i++)
{
if (GetElementAt(i)->IsEnabled())
{
((COpticsElement*)GetElementAt(i))->Render(shader, vSrcWorldPos, vSrcProjPos, aux);
}
}
}
void COpticsGroup::GetMemoryUsage(ICrySizer* pSizer) const
{
for (int i = 0, iChildSize(children.size()); i < iChildSize; ++i)
{
children[i]->GetMemoryUsage(pSizer);
}
pSizer->AddObject(this, sizeof(*this));
}
void COpticsGroup::Invalidate()
{
for (int i = 0, iChildSize(children.size()); i < iChildSize; ++i)
{
children[i]->Invalidate();
}
}
@@ -0,0 +1,64 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSGROUP_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSGROUP_H
#pragma once
#include "OpticsElement.h"
class COpticsGroup
: public COpticsElement
{
protected:
std::vector<IOpticsElementBasePtr> children;
void _init();
public:
COpticsGroup(const char* name = "[Unnamed_Group]")
: COpticsElement(name) { _init(); };
COpticsGroup(const char* name, COpticsElement* elem, ...);
virtual ~COpticsGroup(){}
COpticsGroup& Add(IOpticsElementBase* pElement);
void Remove(int i);
void RemoveAll();
virtual int GetElementCount() const;
IOpticsElementBase* GetElementAt(int i) const;
void AddElement(IOpticsElementBase* pElement) { Add(pElement); }
void InsertElement(int nPos, IOpticsElementBase* pElement);
void SetElementAt(int i, IOpticsElementBase* elem);
void Invalidate();
bool IsGroup() const { return true; }
void validateChildrenGlobalVars(SAuxParams& aux);
virtual void GetMemoryUsage(ICrySizer* pSizer) const;
virtual EFlareType GetType() { return eFT_Group; }
virtual void validateGlobalVars(SAuxParams& aux);
void Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux);
#if defined(FLARES_SUPPORT_EDITING)
virtual void InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups);
#endif
public:
static COpticsGroup predef_simpleCamGhost;
static COpticsGroup predef_cheapCamGhost;
static COpticsGroup predef_multiGlassGhost;
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSGROUP_H
@@ -0,0 +1,77 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include "OpticsElement.h"
#include "RootOpticsElement.h"
#include "Ghost.h"
#include "Glow.h"
#include "ChromaticRing.h"
#include "IrisShafts.h"
#include "Streaks.h"
#include "CameraOrbs.h"
class OpticsPredef
{
public:
COpticsGroup PREDEF_MULTIGLASS_GHOST;
private:
void InitPredef()
{
static CTexture* s_pCenterFlare = CTexture::ForName("EngineAssets/Textures/flares/lens_flare1-wide.tif", FT_DONT_RELEASE | FT_DONT_STREAM, eTF_Unknown);
PREDEF_MULTIGLASS_GHOST.SetName("[Multi-glass Reflection]");
Glow* rotStreak = new Glow("RotatingStreak");
rotStreak->SetSize(0.28f);
rotStreak->SetAutoRotation(true);
rotStreak->SetFocusFactor(-0.18f);
rotStreak->SetBrightness(6.f);
rotStreak->SetScale(Vec2(0.034f, 25.f));
PREDEF_MULTIGLASS_GHOST.Add(rotStreak);
CameraOrbs* orbs = new CameraOrbs("Orbs");
orbs->SetIllumRange(1.2f);
orbs->SetUseLensTex(true);
PREDEF_MULTIGLASS_GHOST.Add(orbs);
ChromaticRing* ring = new ChromaticRing("Forward Ring");
PREDEF_MULTIGLASS_GHOST.Add(ring);
ChromaticRing* backRing = new ChromaticRing("Backward Ring");
backRing->SetCompletionFading(10.f);
backRing->SetCompletionSpanAngle(25.f);
PREDEF_MULTIGLASS_GHOST.Add(backRing);
CLensGhost* centerCorona = new CLensGhost("Center Corona");
centerCorona->SetTexture(s_pCenterFlare);
centerCorona->SetSize(0.6f);
PREDEF_MULTIGLASS_GHOST.Add(centerCorona);
}
OpticsPredef()
{
InitPredef();
}
OpticsPredef(OpticsPredef const& copy);
void operator=(OpticsPredef const& copy);
public:
static OpticsPredef* GetInstance()
{
static OpticsPredef instance;
return &instance;
}
};
@@ -0,0 +1,69 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "OpticsProxy.h"
#if defined(FLARES_SUPPORT_EDITING)
AZStd::vector<FuncVariableGroup> COpticsProxy::GetEditorParamGroups()
{
return AZStd::vector<FuncVariableGroup>();
}
#endif
COpticsProxy::COpticsProxy(const char* name)
: m_bEnable(false)
, m_name(name)
, m_pOpticsReference(NULL)
{
}
void COpticsProxy::Load(IXmlNode* pNode)
{
XmlNodeRef pProxy = pNode->findChild("Proxy");
if (pProxy)
{
const char* referenceName(NULL);
if (pProxy->getAttr("Reference", &referenceName))
{
if (referenceName && referenceName[0])
{
int nReferenceIndex(-1);
if (gEnv->pOpticsManager->Load(referenceName, nReferenceIndex))
{
IOpticsElementBase* pOptics = gEnv->pOpticsManager->GetOptics(nReferenceIndex);
if (pOptics->GetType() == eFT_Reference)
{
m_pOpticsReference = (COpticsReference*)gEnv->pOpticsManager->GetOptics(nReferenceIndex);
}
}
}
}
}
}
void COpticsProxy::GetMemoryUsage([[maybe_unused]] ICrySizer* pSizer) const
{
}
void COpticsProxy::Invalidate()
{
}
void COpticsProxy::Render(SLensFlareRenderParam* pParam, const Vec3& vPos)
{
if (m_pOpticsReference)
{
m_pOpticsReference->Render(pParam, vPos);
}
}
@@ -0,0 +1,74 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSPROXY_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSPROXY_H
#pragma once
#include "OpticsReference.h"
class COpticsProxy
: public IOpticsElementBase
{
public:
COpticsProxy(const char* name);
~COpticsProxy(){}
EFlareType GetType() { return eFT_Proxy; }
bool IsGroup() const { return false; }
string GetName() const { return m_name; }
void SetName(const char* ch_name) { m_name = ch_name; }
void Load(IXmlNode* pNode);
IOpticsElementBase* GetParent() const { return NULL; }
bool IsEnabled() const { return m_bEnable; }
void SetEnabled(bool b) { m_bEnable = b; }
void AddElement([[maybe_unused]] IOpticsElementBase* pElement) {}
void InsertElement([[maybe_unused]] int nPos, [[maybe_unused]] IOpticsElementBase* pElement) {}
void Remove([[maybe_unused]] int i) {}
void RemoveAll() {}
int GetElementCount() const { return 0; }
IOpticsElementBase* GetElementAt([[maybe_unused]] int i) const { return NULL; }
void GetMemoryUsage(ICrySizer* pSizer) const;
void Invalidate();
void Render(SLensFlareRenderParam* pParam, const Vec3& vPos);
void SetOpticsReference(IOpticsElementBase* pReference)
{
if (pReference->GetType() == eFT_Reference)
{
m_pOpticsReference = (COpticsReference*)pReference;
}
}
IOpticsElementBase* GetOpticsReference() const
{
return m_pOpticsReference;
}
#if defined(FLARES_SUPPORT_EDITING)
AZStd::vector<FuncVariableGroup> GetEditorParamGroups();
#endif
public:
bool m_bEnable;
string m_name;
_smart_ptr<COpticsReference> m_pOpticsReference;
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSPROXY_H
@@ -0,0 +1,97 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "OpticsReference.h"
#if defined(FLARES_SUPPORT_EDITING)
AZStd::vector<FuncVariableGroup> COpticsReference::GetEditorParamGroups()
{
return AZStd::vector<FuncVariableGroup>();
}
#endif
COpticsReference::COpticsReference(const char* name)
: m_name(name)
{
}
void COpticsReference::Load([[maybe_unused]] IXmlNode* pNode)
{
}
void COpticsReference::AddElement(IOpticsElementBase* pElement)
{
m_OpticsList.push_back(pElement);
}
void COpticsReference::InsertElement(int nPos, IOpticsElementBase* pElement)
{
if (nPos < 0 || nPos >= (int)m_OpticsList.size())
{
return;
}
m_OpticsList.insert(m_OpticsList.begin() + nPos, pElement);
}
void COpticsReference::Remove(int i)
{
if (i < 0 || i >= (int)m_OpticsList.size())
{
return;
}
m_OpticsList.erase(m_OpticsList.begin() + i);
}
void COpticsReference::RemoveAll()
{
m_OpticsList.clear();
}
int COpticsReference::GetElementCount() const
{
return m_OpticsList.size();
}
IOpticsElementBase* COpticsReference::GetElementAt(int i) const
{
if (i < 0 || i >= (int)m_OpticsList.size())
{
return NULL;
}
return m_OpticsList[i];
}
void COpticsReference::GetMemoryUsage(ICrySizer* pSizer) const
{
for (int i = 0, iSize(m_OpticsList.size()); i < iSize; ++i)
{
m_OpticsList[i]->GetMemoryUsage(pSizer);
}
}
void COpticsReference::Invalidate()
{
for (int i = 0, iSize(m_OpticsList.size()); i < iSize; ++i)
{
m_OpticsList[i]->Invalidate();
}
}
void COpticsReference::Render(SLensFlareRenderParam* pParam, const Vec3& vPos)
{
for (int i = 0, iSize(m_OpticsList.size()); i < iSize; ++i)
{
m_OpticsList[i]->Render(pParam, vPos);
}
}
@@ -0,0 +1,60 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSREFERENCE_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSREFERENCE_H
#pragma once
#include "IFlares.h"
class COpticsReference
: public IOpticsElementBase
{
public:
#if defined(FLARES_SUPPORT_EDITING)
AZStd::vector<FuncVariableGroup> GetEditorParamGroups();
#endif
COpticsReference(const char* name);
~COpticsReference(){}
EFlareType GetType() { return eFT_Reference; }
bool IsGroup() const { return false; }
string GetName() const { return m_name; }
void SetName(const char* ch_name) { m_name = ch_name; }
void Load(IXmlNode* pNode);
IOpticsElementBase* GetParent() const { return NULL; }
bool IsEnabled() const { return true; }
void SetEnabled([[maybe_unused]] bool b) {}
void AddElement(IOpticsElementBase* pElement);
void InsertElement(int nPos, IOpticsElementBase* pElement);
void Remove(int i);
void RemoveAll();
int GetElementCount() const;
IOpticsElementBase* GetElementAt(int i) const;
void GetMemoryUsage(ICrySizer* pSizer) const;
void Invalidate();
void Render(SLensFlareRenderParam* pParam, const Vec3& vPos);
public:
string m_name;
std::vector<IOpticsElementBasePtr> m_OpticsList;
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_OPTICSREFERENCE_H
@@ -0,0 +1,265 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : common RE functions.
#include "RenderDll_precompiled.h"
//TArray<CRendElementBase *> CRendElementBase::m_AllREs;
CRendElement CRendElement::m_RootGlobal;
CRendElement CRendElement::m_RootRelease[4];
//===============================================================
CryCriticalSection m_sREResLock;
//============================================================================
void CRendElement::ShutDown()
{
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_releaseallresourcesonexit)
{
return;
}
AUTO_LOCK(m_sREResLock); // Not thread safe without this
CRendElement* pRE;
CRendElement* pRENext;
for (pRE = CRendElement::m_RootGlobal.m_NextGlobal; pRE != &CRendElement::m_RootGlobal; pRE = pRENext)
{
pRENext = pRE->m_NextGlobal;
if IsCVarConstAccess(constexpr) (CRenderer::CV_r_printmemoryleaks)
{
iLog->Log("Warning: CRendElementBase::ShutDown: RenderElement %s was not deleted", pRE->mfTypeString());
}
pRE->Release();
}
}
void CRendElement::Tick()
{
#ifndef STRIP_RENDER_THREAD
assert(gRenDev->m_pRT->IsMainThread(true));
#endif
int nFrameID = gRenDev->m_RP.m_TI[gRenDev->m_RP.m_nFillThreadID].m_nFrameUpdateID;
int nFrame = nFrameID - 3;
CRendElement& Root = CRendElement::m_RootRelease[nFrame & 3];
CRendElement* pRENext = NULL;
for (CRendElement* pRE = Root.m_NextGlobal; pRE != &Root; pRE = pRENext)
{
pRENext = pRE->m_NextGlobal;
SAFE_DELETE(pRE);
}
}
void CRendElement::Cleanup()
{
gRenDev->m_pRT->FlushAndWait();
AUTO_LOCK(m_sREResLock); // Not thread safe without this
for (int i = 0; i < 4; ++i)
{
CRendElement& Root = CRendElement::m_RootRelease[i];
CRendElement* pRENext = NULL;
for (CRendElement* pRE = Root.m_NextGlobal; pRE != &Root; pRE = pRENext)
{
pRENext = pRE->m_NextGlobal;
SAFE_DELETE(pRE);
}
}
}
CRendElement::CRendElement()
{
m_Type = eDATA_Unknown;
if (!m_RootGlobal.m_NextGlobal)
{
m_RootGlobal.m_NextGlobal = &m_RootGlobal;
m_RootGlobal.m_PrevGlobal = &m_RootGlobal;
for (int i = 0; i < 4; i++)
{
m_RootRelease[i].m_NextGlobal = &m_RootRelease[i];
m_RootRelease[i].m_PrevGlobal = &m_RootRelease[i];
}
}
}
CRendElement::~CRendElement()
{
assert(m_Type == eDATA_Unknown || m_Type == eDATA_Particle || m_Type == eDATA_GPUParticle || m_Type == eDATA_Gem || m_Type == eDATA_VolumeObject);
//@TODO: Fix later, prevent crash on exit in single executable
if (this == &m_RootRelease[0] || this == &m_RootRelease[1] || this == &m_RootRelease[2] || this == &m_RootRelease[3] || this == &m_RootGlobal)
{
return;
}
AUTO_LOCK(m_sREResLock);
UnlinkGlobal();
}
void CRendElement::Release(bool bForce)
{
CRendElementBase* pThis = (CRendElementBase*)this;
pThis->m_Flags |= FCEF_DELETED;
m_Type = eDATA_Unknown;
if (bForce)
{
delete this;
return;
}
int nFrame = gRenDev->GetFrameID(false);
AUTO_LOCK(m_sREResLock);
CRendElement& Root = CRendElement::m_RootRelease[nFrame & 3];
UnlinkGlobal();
LinkGlobal(&Root);
}
CRendElementBase::CRendElementBase()
{
m_Flags = 0;
m_nFrameUpdated = 0xffff;
m_CustomData = NULL;
m_NextGlobal = NULL;
m_PrevGlobal = NULL;
int i;
for (i = 0; i < MAX_CUSTOM_TEX_BINDS_NUM; i++)
{
m_CustomTexBind[i] = -1;
}
AUTO_LOCK(m_sREResLock);
LinkGlobal(&m_RootGlobal);
}
CRendElementBase::~CRendElementBase()
{
if ((m_Flags & FCEF_ALLOC_CUST_FLOAT_DATA) && m_CustomData)
{
delete [] ((float*)m_CustomData);
m_CustomData = 0;
}
}
const char* CRendElement::mfTypeString()
{
switch (m_Type)
{
case eDATA_Sky:
return "Sky";
case eDATA_Beam:
return "Beam";
case eDATA_ClientPoly:
return "ClientPoly";
case eDATA_Flare:
return "Flare";
case eDATA_Terrain:
return "Terrain";
case eDATA_SkyZone:
return "SkyZone";
case eDATA_Mesh:
return "Mesh";
case eDATA_Imposter:
return "Imposter";
case eDATA_LensOptics:
return "LensOptics";
case eDATA_OcclusionQuery:
return "OcclusionQuery";
case eDATA_Particle:
return "Particle";
case eDATA_GPUParticle:
return "GPUParticle";
case eDATA_PostProcess:
return "PostProcess";
case eDATA_HDRProcess:
return "HDRProcess";
case eDATA_Cloud:
return "Cloud";
case eDATA_HDRSky:
return "HDRSky";
case eDATA_FogVolume:
return "FogVolume";
case eDATA_WaterVolume:
return "WaterVolume";
case eDATA_WaterOcean:
return "WaterOcean";
case eDATA_VolumeObject:
return "VolumeObject";
case eDATA_PrismObject:
return "PrismObject";
case eDATA_DeferredShading:
return "DeferredShading";
case eDATA_GameEffect:
return "GameEffect";
case eDATA_BreakableGlass:
return "BreakableGlass";
case eDATA_GeomCache:
return "GeomCache";
case eDATA_Gem:
return "Gem";
default:
{
CRY_ASSERT(false);
return "Unknown";
}
}
}
CRendElementBase* CRendElementBase::mfCopyConstruct(void)
{
CRendElementBase* re = new CRendElementBase;
*re = *this;
return re;
}
void CRendElementBase::mfCenter(Vec3& centr, [[maybe_unused]] CRenderObject* pObj)
{
centr(0, 0, 0);
}
void CRendElementBase::mfGetPlane(Plane& pl)
{
pl.n = Vec3(0, 0, 1);
pl.d = 0;
}
//=============================================================================
void* SRendItem::mfGetPointerCommon(ESrcPointer ePT, int* Stride, [[maybe_unused]] EParamType Type, [[maybe_unused]] ESrcPointer Dst, [[maybe_unused]] int Flags)
{
int j;
switch (ePT)
{
case eSrcPointer_Vert:
*Stride = gRenDev->m_RP.m_StreamStride;
return gRenDev->m_RP.m_StreamPtr.PtrB;
case eSrcPointer_Color:
*Stride = gRenDev->m_RP.m_StreamStride;
return gRenDev->m_RP.m_StreamPtr.PtrB + gRenDev->m_RP.m_StreamOffsetColor;
case eSrcPointer_Tex:
case eSrcPointer_TexLM:
*Stride = gRenDev->m_RP.m_StreamStride;
j = ePT - eSrcPointer_Tex;
return gRenDev->m_RP.m_StreamPtr.PtrB + gRenDev->m_RP.m_StreamOffsetTC + j * 16;
}
return NULL;
}
@@ -0,0 +1,351 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "RootOpticsElement.h"
#include "FlareSoftOcclusionQuery.h"
#include "../Textures/Texture.h"
#include "DriverD3D.h"
#include "D3DPostProcess.h"
#include "stdarg.h"
enum EVisFader
{
VISFADER_FLARE = 0,
VISFADER_SHAFT,
VISFADER_NUM
};
#if defined(FLARES_SUPPORT_EDITING)
#define MFPtr(FUNC_NAME) (Optics_MFPtr)(&RootOpticsElement::FUNC_NAME)
void RootOpticsElement::InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups)
{
COpticsGroup::InitEditorParamGroups(groups);
FuncVariableGroup rootGroup;
rootGroup.SetName("GlobalSettings", "Global Settings");
rootGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Enable Occlusion", "Enable Occlusion", this, MFPtr(SetOcclusionEnabled), MFPtr(IsOcclusionEnabled)));
rootGroup.AddVariable(new OpticsMFPVariable(e_VEC2, "Occlusion Size", "The size for occlusion plane", this, MFPtr(SetOccSize), MFPtr(GetOccSize)));
rootGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Flare fade time", "The duration of flare afterimage fading in seconds", this, MFPtr(SetFlareFadingDuration), MFPtr(GetFlareFadingDuration)));
rootGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Shaft fade time", "The duration of shaft afterimage fading in seconds", this, MFPtr(SetShaftFadingDuration), MFPtr(GetShaftFadingDuration)));
rootGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Affected by light color", "light color can affect flare color", this, MFPtr(SetAffectedByLightColor), MFPtr(IsAffectedByLightColor)));
rootGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Affected by light radius", "light radius can affect flare fading", this, MFPtr(SetAffectedByLightRadius), MFPtr(IsAffectedByLightRadius)));
rootGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Affected by light FOV", "light projection FOV can affect flare fading", this, MFPtr(SetAffectedByLightFOV), MFPtr(IsAffectedByLightFOV)));
rootGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Multiply Color", "Select one of between Multiply and Addition about color calculation. If true, Multiply will be chosen.", this, MFPtr(SetMultiplyColor), MFPtr(IsMultiplyColor)));
groups.push_back(rootGroup);
FuncVariableGroup sensorGroup;
sensorGroup.SetName("Sensor");
sensorGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Custom Sensor Variation Map", "Enable Custom Sensor Variation Map", this, MFPtr(SetCustomSensorVariationMapEnabled), MFPtr(IsCustomSensorVariationMapEnabled)));
sensorGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Effective Sensor Size", "The size of image-able part of the sensor", this, MFPtr(SetEffectiveSensorSize), MFPtr(GetEffectiveSensorSize)));
groups.push_back(sensorGroup);
}
#undef MFPtr
#endif
void RootOpticsElement::Load(IXmlNode* pNode)
{
COpticsElement::Load(pNode);
XmlNodeRef pGloabalSettingsNode = pNode->findChild("GlobalSettings");
if (pGloabalSettingsNode)
{
bool bOcclusionEnabled(m_bOcclusionEnabled);
if (pGloabalSettingsNode->getAttr("EnableOcclusion", bOcclusionEnabled))
{
SetOcclusionEnabled(bOcclusionEnabled);
}
Vec2 occlusionSize(m_OcclusionSize);
if (pGloabalSettingsNode->getAttr("OcclusionSize", occlusionSize))
{
SetOccSize(occlusionSize);
}
float fFlareTimelineDuration(m_fFlareTimelineDuration);
if (pGloabalSettingsNode->getAttr("Flarefadetime", fFlareTimelineDuration))
{
SetFlareFadingDuration(fFlareTimelineDuration);
}
float fShaftTimelineDuration(m_fShaftTimelineDuration);
if (pGloabalSettingsNode->getAttr("Flarefadetime", fShaftTimelineDuration))
{
SetShaftFadingDuration(fShaftTimelineDuration);
}
bool bAffectedByLightColor(m_bAffectedByLightColor);
if (pGloabalSettingsNode->getAttr("Affectedbylightcolor", bAffectedByLightColor))
{
SetAffectedByLightColor(bAffectedByLightColor);
}
bool bAffectedByLightRadius(m_bAffectedByLightRadius);
if (pGloabalSettingsNode->getAttr("Affectedbylightradius", bAffectedByLightRadius))
{
SetAffectedByLightRadius(bAffectedByLightRadius);
}
bool bAffectedByLightFOV(m_bAffectedByLightFOV);
if (pGloabalSettingsNode->getAttr("AffectedbylightFOV", bAffectedByLightFOV))
{
SetAffectedByLightFOV(bAffectedByLightFOV);
}
bool bMultiplyColor(m_bMultiplyColor);
if (pGloabalSettingsNode->getAttr("MultiplyColor", bMultiplyColor))
{
SetMultiplyColor(bMultiplyColor);
}
}
XmlNodeRef pSensorNode = pNode->findChild("Sensor");
if (pSensorNode)
{
bool bCustomSensorVariationMap(m_bCustomSensorVariationMap);
if (pSensorNode->getAttr("CustomSensorVariationMap", bCustomSensorVariationMap))
{
SetCustomSensorVariationMapEnabled(bCustomSensorVariationMap);
}
float fEffectiveSensorSize(m_fEffectiveSensorSize);
if (pSensorNode->getAttr("EffectiveSensorSize", fEffectiveSensorSize))
{
SetEffectiveSensorSize(fEffectiveSensorSize);
}
}
}
void RootOpticsElement::SetOcclusionQuery(CFlareSoftOcclusionQuery* query)
{
m_pOccQuery = query;
}
float RootOpticsElement::GetFlareVisibilityFactor() const
{
CSoftOcclusionVisiblityFader* pFader = m_pOccQuery ? m_pOccQuery->GetVisibilityFader(VISFADER_FLARE) : NULL;
return pFader ? pFader->m_fVisibilityFactor : 0.0f;
}
float RootOpticsElement::GetShaftVisibilityFactor() const
{
CSoftOcclusionVisiblityFader* pFader = m_pOccQuery ? m_pOccQuery->GetVisibilityFader(VISFADER_SHAFT) : NULL;
return pFader ? pFader->m_fVisibilityFactor : 0.0f;
}
void RootOpticsElement::SetVisibilityFactor(float f)
{
f = clamp_tpl(f, 0.f, 1.f);
if (m_pOccQuery)
{
for (uint i = 0; i < VISFADER_NUM; ++i)
{
if (CSoftOcclusionVisiblityFader* pFader = m_pOccQuery->GetVisibilityFader(i))
{
pFader->m_fVisibilityFactor = f;
}
}
}
}
CTexture* RootOpticsElement::GetOcclusionPattern()
{
return m_pOccQuery->GetGatherTexture();
}
void RootOpticsElement::validateGlobalVars(SAuxParams& aux)
{
m_globalPerpectiveFactor = m_fPerpectiveFactor;
m_globalDistanceFadingFactor = m_flareLight.m_bAttachToSun ? 0.0f : m_fDistanceFadingFactor;
m_globalSensorBrightnessFactor = m_fSensorBrightnessFactor;
m_globalSensorSizeFactor = m_fSensorSizeFactor;
m_globalSize = m_fSize;
m_globalFlareBrightness = GetBrightness();
m_globalMovement = m_vMovement;
if (m_bAffectedByLightColor)
{
if (aux.bMultiplyColor)
{
m_globalColor = ColorF(m_Color.r * m_flareLight.m_cLdrClr.r, m_Color.g * m_flareLight.m_cLdrClr.g, m_Color.b * m_flareLight.m_cLdrClr.b, m_Color.a);
}
else
{
m_globalColor = ColorF(m_Color.r + m_flareLight.m_cLdrClr.r, m_Color.g + m_flareLight.m_cLdrClr.g, m_Color.b + m_flareLight.m_cLdrClr.b, m_Color.a);
}
m_globalFlareBrightness *= m_flareLight.m_fClrMultiplier;
}
else
{
m_globalColor = m_Color;
}
if (m_bAffectedByLightRadius)
{
m_globalFlareBrightness *= clamp_tpl(1 - aux.distance / m_flareLight.m_fRadius, 0.0f, 1.0f);
}
if (m_bAffectedByLightFOV)
{
m_globalFlareBrightness *= aux.viewAngleFalloff;
}
float fShaftVisibilityFactor = aux.bForceRender ? 1.0f : GetShaftVisibilityFactor();
float fFlareVisibilityFactor = aux.bForceRender ? 1.0f : GetFlareVisibilityFactor();
m_globalShaftBrightness = m_globalFlareBrightness * fShaftVisibilityFactor;
m_globalFlareBrightness *= fFlareVisibilityFactor;
m_globalOcclusionBokeh = m_bOcclusionBokeh & IsOcclusionEnabled();
m_globalCorrectAspectRatio = m_globalCorrectAspectRatio;
m_globalAutoRotation = m_globalAutoRotation;
m_globalOrbitAngle = m_fOrbitAngle;
m_globalTransform = m_mxTransform;
COpticsGroup::validateChildrenGlobalVars(aux);
}
void RootOpticsElement::Render(SLensFlareRenderParam* pParam, const Vec3& vPos)
{
if (pParam == NULL)
{
return;
}
if (!pParam->IsValid())
{
return;
}
SFlareLight light;
light.m_vPos = vPos;
light.m_fRadius = 10000.0f;
light.m_bAttachToSun = false;
light.m_cLdrClr = ColorF(1, 1, 1, 1);
light.m_fClrMultiplier = 1;
light.m_fViewAngleFalloff = 1;
ProcessAll((CShader*)pParam->pShader, light, true, pParam->pCamera);
}
bool RootOpticsElement::ProcessAll(CShader* shader, SFlareLight& light, bool bForceRender, CCamera* pCamera)
{
CD3D9Renderer* pRD = gcpRendD3D;
Vec3 vSrcWorldPos = light.m_vPos;
Vec3 vSrcProjPos;
m_flareLight = light;
float linearDepth = 0;
float distance = 0;
if (pCamera)
{
Matrix44A mProj, mView;
mathMatrixPerspectiveFov(&mProj, pCamera->GetFov(), pCamera->GetProjRatio(), pCamera->GetNearPlane(), pCamera->GetFarPlane());
mathMatrixLookAt(&mView, pCamera->GetPosition(), pCamera->GetPosition() + pCamera->GetViewdir(), Vec3(0, 0, 1));
if (!CFlareSoftOcclusionQuery::ComputeProjPos(vSrcWorldPos, mView, mProj, vSrcProjPos))
{
return false;
}
linearDepth = clamp_tpl(CFlareSoftOcclusionQuery::ComputeLinearDepth(vSrcWorldPos, mView, pCamera->GetNearPlane(), pCamera->GetFarPlane()), -1.0f, 0.99f);
distance = mView.GetTranslation().GetDistance(vSrcWorldPos);
}
else
{
if (!CFlareSoftOcclusionQuery::ComputeProjPos(vSrcWorldPos, pRD->m_ViewMatrix, pRD->m_ProjMatrix, vSrcProjPos))
{
return false;
}
if (pRD->m_RP.m_TI[pRD->m_RP.m_nProcessThreadID].m_PersFlags & RBPF_REVERSE_DEPTH)
{
vSrcProjPos.z = 1.0f - vSrcProjPos.z;
}
const CameraViewParameters& rc = gRenDev->GetViewParameters();
linearDepth = clamp_tpl(CFlareSoftOcclusionQuery::ComputeLinearDepth(vSrcWorldPos, pRD->m_CameraMatrix, rc.fNear, rc.fFar), -1.0f, 0.99f);
distance = pRD->GetViewParameters().vOrigin.GetDistance(vSrcWorldPos);
}
if (GetElementCount() <= 0 || !IsEnabled())
{
return false;
}
if (!bForceRender && (linearDepth <= 0 || !IsVisibleBasedOnLight(light, distance)))
{
return false;
}
bool bVisible(!IsOcclusionEnabled());
if (!bVisible && !bForceRender)
{
float curTargetVisibility = 0.0f;
m_fFlareVisibilityFactor = m_fShaftVisibilityFactor = 0.0f;
if (m_pOccQuery)
{
curTargetVisibility = m_pOccQuery->GetVisibility();
if (CSoftOcclusionVisiblityFader* pFader = m_pOccQuery->GetVisibilityFader(VISFADER_FLARE))
{
m_fFlareVisibilityFactor = pFader->UpdateVisibility(curTargetVisibility, m_fFlareTimelineDuration);
}
if (CSoftOcclusionVisiblityFader* pFader = m_pOccQuery->GetVisibilityFader(VISFADER_SHAFT))
{
m_fShaftVisibilityFactor = pFader->UpdateVisibility(curTargetVisibility, m_fShaftTimelineDuration);
}
}
bVisible = IsVisible();
}
if (bVisible || bForceRender)
{
SAuxParams aux;
aux.linearDepth = linearDepth;
aux.distance = distance;
float x = vSrcProjPos.x * 2 - 1;
float y = vSrcProjPos.y * 2 - 1;
float unitLenSq = (x * x + y * y);
aux.sensorVariationValue = clamp_tpl((1 - powf(unitLenSq, 0.25f)) * 2 - 1, -1.0f, 1.0f);
aux.perspectiveShortening = clamp_tpl(10.f * (1.f - vSrcProjPos.z), 0.0f, 2.0f);
aux.viewAngleFalloff = light.m_fViewAngleFalloff;
aux.attachToSun = light.m_bAttachToSun;
aux.bMultiplyColor = IsMultiplyColor();
aux.bForceRender = bForceRender;
// The legacy entity system does not allow for overriding the color, brightness and size of lens flares.
// The new component systems does allow for overriding these values so we apply them only when valid
if (light.m_opticsParams.m_isValid)
{
SetColor(light.m_opticsParams.m_color);
SetBrightness(light.m_opticsParams.m_brightness);
SetSize(light.m_opticsParams.m_size);
}
validateGlobalVars(aux);
if (bForceRender || m_globalFlareBrightness > 0.001f || m_globalShaftBrightness > 0.001f)
{
gcpRendD3D->m_RP.m_PersFlags2 |= RBPF2_LENS_OPTICS_COMPOSITE;
COpticsGroup::Render(shader, vSrcWorldPos, vSrcProjPos, aux);
}
}
return true;
}
@@ -0,0 +1,171 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_ROOTOPTICSELEMENT_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_ROOTOPTICSELEMENT_H
#pragma once
#include "OpticsGroup.h"
#include "Timeline.h"
class CRenderObject;
class CFlareSoftOcclusionQuery;
class RootOpticsElement
: public COpticsGroup
{
public:
struct SFlareLight
{
Vec3 m_vPos;
ColorF m_cLdrClr;
float m_fClrMultiplier;
float m_fRadius;
float m_fViewAngleFalloff;
bool m_bAttachToSun;
SOpticsInstanceParameters m_opticsParams;
};
private:
bool m_bChromaticAbrEnabled : 1;
bool m_bLateralChromaticAbr : 1;
float m_fChromaticAbrOffset;
float m_fChromaticAbrDir;
float m_fEffectiveSensorSize;
bool m_bCustomSensorVariationMap : 1;
bool m_bPostBlur : 1;
float m_fPostBlurAmount;
bool m_bOcclusionEnabled : 1;
float m_fFlareVisibilityFactor;
float m_fShaftVisibilityFactor;
float m_fFlareTimelineDuration;
float m_fShaftTimelineDuration;
CFlareSoftOcclusionQuery* m_pOccQuery;
bool m_bAffectedByLightColor : 1;
bool m_bAffectedByLightRadius : 1;
bool m_bAffectedByLightFOV : 1;
SFlareLight m_flareLight;
Vec2 m_OcclusionSize;
bool m_bMultiplyColor : 1;
public:
RootOpticsElement()
: COpticsGroup("@root")
, m_bChromaticAbrEnabled(false)
, m_bLateralChromaticAbr(false)
, m_fChromaticAbrOffset(0.002f)
, m_fChromaticAbrDir(0.785f)
, m_bOcclusionEnabled(true)
, m_fFlareVisibilityFactor(1)
, m_fShaftVisibilityFactor(1)
, m_pOccQuery(NULL)
, m_fEffectiveSensorSize(0.8f)
, m_bCustomSensorVariationMap(false)
, m_bAffectedByLightColor(false)
, m_bAffectedByLightRadius(false)
, m_bAffectedByLightFOV(true)
, m_bPostBlur(false)
, m_fPostBlurAmount(0)
, m_bMultiplyColor(true)
{
SetFlareFadingDuration(0.2f);
SetShaftFadingDuration(1.0f);
m_OcclusionSize = Vec2(0.02f, 0.02f);
m_fPerpectiveFactor = 1;
}
~RootOpticsElement()
{
}
EFlareType GetType() { return eFT_Root; }
void validateGlobalVars(SAuxParams& aux);
#if defined(FLARES_SUPPORT_EDITING)
void InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups);
#endif
void Load(IXmlNode* pNode);
using COpticsGroup::Render;
void Render(SLensFlareRenderParam* pParam, const Vec3& vPos);
bool ProcessAll(CShader* shader, SFlareLight& light, bool bForceRender = false, CCamera* pCamera = NULL);
IOpticsElementBase* GetParent() const { return NULL; }
float GetEffectiveSensorSize() const { return m_fEffectiveSensorSize; }
void SetEffectiveSensorSize(float s) { m_fEffectiveSensorSize = s; }
bool IsCustomSensorVariationMapEnabled() const { return m_bCustomSensorVariationMap; }
void SetCustomSensorVariationMapEnabled(bool b) { m_bCustomSensorVariationMap = b; }
bool IsVisible() const { return (m_fFlareVisibilityFactor > 0.0f) || (m_fShaftVisibilityFactor > 0.0f); }
bool IsVisibleBasedOnLight(const SFlareLight& light, float distance) const
{
return (!m_bAffectedByLightRadius || distance < light.m_fRadius) &&
(!m_bAffectedByLightColor || ((light.m_cLdrClr.r > LensOpConst::_LO_MIN || light.m_cLdrClr.g > LensOpConst::_LO_MIN || light.m_cLdrClr.b > LensOpConst::_LO_MIN) && light.m_fClrMultiplier > LensOpConst::_LO_MIN)) &&
(!m_bAffectedByLightFOV || light.m_fViewAngleFalloff > LensOpConst::_LO_MIN);
}
bool IsOcclusionEnabled() const { return m_bOcclusionEnabled; }
void SetOcclusionEnabled(bool b)
{
m_bOcclusionEnabled = b;
if (!b)
{
SetVisibilityFactor(1.0f);
}
}
void SetOcclusionQuery(CFlareSoftOcclusionQuery* query);
CFlareSoftOcclusionQuery* GetOcclusionQuery() { return m_pOccQuery; }
float GetFlareVisibilityFactor() const;
float GetShaftVisibilityFactor() const;
void SetVisibilityFactor(float f);
Vec2 GetOccSize() const
{
return m_OcclusionSize;
}
void SetOccSize(Vec2 vSize)
{
m_OcclusionSize = vSize;
}
CTexture* GetOcclusionPattern();
float GetFlareFadingDuration() const { return m_fFlareTimelineDuration / 1e3f; }
void SetFlareFadingDuration(float d) { m_fFlareTimelineDuration = d * 1e3f; }
float GetShaftFadingDuration() const { return m_fShaftTimelineDuration / 1e3f; }
void SetShaftFadingDuration(float d) { m_fShaftTimelineDuration = d * 1e3f; }
bool IsAffectedByLightColor() const { return m_bAffectedByLightColor; }
void SetAffectedByLightColor(bool b) { m_bAffectedByLightColor = b; }
bool IsAffectedByLightRadius() const { return m_bAffectedByLightRadius; }
void SetAffectedByLightRadius(bool b) { m_bAffectedByLightRadius = b; }
bool IsAffectedByLightFOV() const { return m_bAffectedByLightFOV; }
void SetAffectedByLightFOV(bool b) { m_bAffectedByLightFOV = b; }
bool IsMultiplyColor() const { return m_bMultiplyColor; }
void SetMultiplyColor(bool b) { m_bMultiplyColor = b; }
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_ROOTOPTICSELEMENT_H
@@ -0,0 +1,34 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_STARS_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_STARS_H
#pragma once
class CStars
{
public:
CStars();
~CStars();
void Render(bool bUseMoon);
private:
bool LoadData();
private:
uint32 m_numStars;
_smart_ptr<IRenderMesh> m_pStarMesh;
CShader* m_pShader;
};
#endif // #ifndef _STARS_H_
@@ -0,0 +1,208 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "Streaks.h"
#include "RootOpticsElement.h"
#include "../CryNameR.h"
#include "../../RenderDll/XRenderD3D9/DriverD3D.h"
#if defined(FLARES_SUPPORT_EDITING)
#define MFPtr(FUNC_NAME) (Optics_MFPtr)(&Streaks::FUNC_NAME)
void Streaks::InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups)
{
COpticsElement::InitEditorParamGroups(groups);
FuncVariableGroup streakGroup;
streakGroup.SetName("Streaks", "Streaks");
streakGroup.AddVariable(new OpticsMFPVariable(e_BOOL, "Enable gradient tex", "Enable gradient texture", this, MFPtr(SetEnableSpectrumTex), MFPtr(GetEnableSpectrumTex)));
streakGroup.AddVariable(new OpticsMFPVariable(e_TEXTURE2D, "Gradient Tex", "Gradient Texture", this, MFPtr(SetSpectrumTex), MFPtr(GetSpectrumTex)));
streakGroup.AddVariable(new OpticsMFPVariable(e_INT, "Noise seed", "Noise seed", this, MFPtr(SetNoiseSeed), MFPtr(GetNoiseSeed), -255.0f, 255.0f));
streakGroup.AddVariable(new OpticsMFPVariable(e_INT, "Streak count", "Number of streaks to generate", this, MFPtr(SetStreakCount), MFPtr(GetStreakCount), 0, 1000.0f));
streakGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Thickness", "Thickness of the shafts", this, MFPtr(SetThickness), MFPtr(GetThickness)));
streakGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Thickness noise", "Noise strength of thickness variation", this, MFPtr(SetThicknessNoise), MFPtr(GetThicknessNoise)));
streakGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Size noise", "Noise strength of shafts' sizes", this, MFPtr(SetSizeNoise), MFPtr(GetSizeNoise)));
streakGroup.AddVariable(new OpticsMFPVariable(e_FLOAT, "Spacing noise", "Noise strength of shafts' spacing", this, MFPtr(SetSpacingNoise), MFPtr(GetSpacingNoise)));
groups.push_back(streakGroup);
}
#undef MFPtr
#endif
void Streaks::Load(IXmlNode* pNode)
{
COpticsElement::Load(pNode);
XmlNodeRef pStreakNode = pNode->findChild("Streaks");
if (pStreakNode)
{
bool bUseSpectrumTex(m_bUseSpectrumTex);
if (pStreakNode->getAttr("Enablegradienttex", bUseSpectrumTex))
{
SetEnableSpectrumTex(bUseSpectrumTex);
}
const char* gradientTexName = NULL;
if (pStreakNode->getAttr("GradientTex", &gradientTexName))
{
if (gradientTexName && gradientTexName[0])
{
ITexture* pTexture = gEnv->pRenderer->EF_LoadTexture(gradientTexName);
SetSpectrumTex((CTexture*)pTexture);
if (pTexture)
{
pTexture->Release();
}
}
}
int nNoiseSeed(m_nNoiseSeed);
if (pStreakNode->getAttr("Noiseseed", nNoiseSeed))
{
SetNoiseSeed(nNoiseSeed);
}
int nStreakCount(m_nStreakCount);
if (pStreakNode->getAttr("Streakcount", nStreakCount))
{
SetStreakCount(nStreakCount);
}
float fThickness(m_fThickness);
if (pStreakNode->getAttr("Thickness", fThickness))
{
SetThickness(fThickness);
}
float fThicknessNoiseStrength(m_fThicknessNoiseStrength);
if (pStreakNode->getAttr("Thicknessnoise", fThicknessNoiseStrength))
{
SetThicknessNoise(fThicknessNoiseStrength);
}
float fSizeNoiseStrength(m_fSizeNoiseStrength);
if (pStreakNode->getAttr("Sizenoise", fSizeNoiseStrength))
{
SetSizeNoise(fSizeNoiseStrength);
}
float fSpacingNoiseStrength(m_fSpacingNoiseStrength);
if (pStreakNode->getAttr("Spacingnoise", fSpacingNoiseStrength))
{
SetSpacingNoise(fSpacingNoiseStrength);
}
}
}
void Streaks::DrawMesh()
{
gcpRendD3D->FX_Commit();
DrawMeshTriList();
}
void Streaks::GenMesh()
{
stable_rand::setSeed((int)m_nNoiseSeed);
float dirDelta = 1.0f / (float)(m_separatedMeshList.size());
ColorF tint(1, 1, 1, 1);
for (uint32 i = 0; i < m_separatedMeshList.size(); i++)
{
float spacingNoise = 1 + stable_rand::randUnit() * m_fSpacingNoiseStrength;
float dirUnit = (i * dirDelta + spacingNoise);
float dir = dirUnit;
float randRadius = (1 + stable_rand::randUnit() * m_fSizeNoiseStrength);
float thickness = m_fThickness * (1 + stable_rand::randUnit() * m_fThicknessNoiseStrength);
std::vector<SVF_P3F_C4B_T2F>& vBuf = (m_separatedMeshList[i]);
MeshUtil::GenStreak(dir, randRadius, thickness, tint, vBuf, m_separatedMeshIndices);
}
}
void Streaks::ApplySingleMesh(int n)
{
m_vertBuf = m_separatedMeshList[n];
m_idxBuf = m_separatedMeshIndices;
ApplyMesh();
}
void Streaks::Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, [[maybe_unused]] SAuxParams& aux)
{
if (!IsVisible())
{
return;
}
PROFILE_LABEL_SCOPE("DRAW_Streaks");
gRenDev->m_RP.m_FlagsShader_RT = 0;
vSrcProjPos = computeOrbitPos(vSrcProjPos, m_globalOrbitAngle);
shader->FXSetTechnique("Streaks");
uint nPass;
shader->FXBegin(&nPass, FEF_DONTSETTEXTURES);
ApplyGeneralFlags(shader);
ApplySpectrumTexFlag(shader, m_bUseSpectrumTex);
shader->FXBeginPass(0);
// common params
ApplyCommonVSParams(shader, vSrcWorldPos, vSrcProjPos);
ApplyExternTintAndBrightnessVS(shader, m_globalColor, m_globalFlareBrightness);
// meshCenter and brightness params
static CCryNameR meshCenterName("meshCenterAndBrt");
float x = computeMovementLocationX(vSrcProjPos);
float y = computeMovementLocationY(vSrcProjPos);
Vec4 meshCenterParam(x, y, vSrcProjPos.z, 1);
shader->FXSetVSFloat(meshCenterName, &meshCenterParam, 1);
// spectrum texture:
static STexState bilinearTS(FILTER_LINEAR, true);
bilinearTS.SetBorderColor(0);
bilinearTS.SetClampMode(TADDR_BORDER, TADDR_BORDER, TADDR_BORDER);
if (m_bUseSpectrumTex)
{
if (m_pSpectrumTex == NULL)
{
m_pSpectrumTex = CTexture::ForName("EngineAssets/Textures/flares/spectrum_full.tif", FT_DONT_STREAM, eTF_Unknown);
if (m_pSpectrumTex)
{
m_pSpectrumTex->Release();
}
}
m_pSpectrumTex->Apply(0, CTexture::GetTexState(bilinearTS));
}
ValidateMesh();
for (uint32 i = 0; i < m_separatedMeshList.size(); i++)
{
ApplySingleMesh(i);
DrawMesh();
}
shader->FXEndPass();
shader->FXEnd();
}
void Streaks::GetMemoryUsage(ICrySizer* pSizer) const
{
int nVertexSize(0);
for (int i = 0, iSize(m_separatedMeshList.size()); i < iSize; ++i)
{
nVertexSize += m_separatedMeshList[i].size() * sizeof(SVF_P3F_C4B_T2F);
}
pSizer->AddObject(this, sizeof(*this) + GetMeshDataSize() + nVertexSize + m_separatedMeshIndices.size() * sizeof(uint16));
}
@@ -0,0 +1,145 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_STREAKS_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_STREAKS_H
#pragma once
#include "OpticsElement.h"
#include "AbstractMeshElement.h"
#include "MeshUtil.h"
class CTexture;
class Streaks
: public COpticsElement
, public AbstractMeshElement
{
private:
_smart_ptr<CTexture> m_pSpectrumTex;
bool m_bUseSpectrumTex;
int m_nStreakCount;
int m_nColorComplexity;
// noise strengths
float m_fSizeNoiseStrength;
float m_fThicknessNoiseStrength;
float m_fSpacingNoiseStrength;
float m_fThickness;
int m_nNoiseSeed;
protected:
std::vector< std::vector<SVF_P3F_C4B_T2F> > m_separatedMeshList;
std::vector< uint16 > m_separatedMeshIndices;
// !Override
virtual void GenMesh();
virtual void ApplySingleMesh(int n);
virtual void DrawMesh();
void Invalidate()
{
m_meshDirty = true;
}
public:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ctor
Streaks (const char* name)
: COpticsElement(name, 0.5f)
, m_fThickness(0.3f)
, m_nNoiseSeed(81)
, m_fSizeNoiseStrength(0.8f)
, m_fThicknessNoiseStrength(0.6f)
, m_fSpacingNoiseStrength(0.2f)
, m_bUseSpectrumTex(false)
{
m_vMovement.x = 1.f;
m_vMovement.y = 1.f;
m_Color.a = 1.f;
SetAutoRotation(false);
SetAspectRatioCorrection(true);
SetColorComplexity(2);
SetStreakCount(1);
m_meshDirty = true;
}
#if defined(FLARES_SUPPORT_EDITING)
void InitEditorParamGroups(AZStd::vector<FuncVariableGroup>& groups);
#endif
EFlareType GetType() { return eFT_Streaks; }
void Render(CShader* shader, Vec3 vSrcWorldPos, Vec3 vSrcProjPos, SAuxParams& aux);
void Load(IXmlNode* pNode);
bool GetEnableSpectrumTex() const { return m_bUseSpectrumTex; }
void SetEnableSpectrumTex(bool b) { m_bUseSpectrumTex = b; }
CTexture* GetSpectrumTex() const { return m_pSpectrumTex; }
void SetSpectrumTex(CTexture* tex) { m_pSpectrumTex = tex; }
int GetNoiseSeed() const { return m_nNoiseSeed; }
void SetNoiseSeed(int seed)
{
m_nNoiseSeed = seed;
m_meshDirty = true;
}
int GetStreakCount() const { return m_nStreakCount; }
void SetStreakCount(int n)
{
m_nStreakCount = n;
m_separatedMeshList.resize(n);
m_meshDirty = true;
}
int GetColorComplexity() const { return m_nColorComplexity; }
void SetColorComplexity(int n)
{
m_nColorComplexity = n;
m_meshDirty = true;
}
float GetThickness() const { return m_fThickness; }
void SetThickness(float f)
{
m_fThickness = f;
m_meshDirty = true;
}
float GetThicknessNoise() const { return m_fThicknessNoiseStrength; }
void SetThicknessNoise(float noise)
{
m_fThicknessNoiseStrength = noise;
m_meshDirty = true;
}
float GetSizeNoise() const { return m_fSizeNoiseStrength; }
void SetSizeNoise(float noise)
{
m_fSizeNoiseStrength = noise;
m_meshDirty = true;
}
float GetSpacingNoise() const { return m_fSpacingNoiseStrength; }
void SetSpacingNoise(float noise)
{
m_fSpacingNoiseStrength = noise;
m_meshDirty = true;
}
void GetMemoryUsage(ICrySizer* pSizer) const;
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_STREAKS_H
@@ -0,0 +1,159 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_TIMELINE_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_TIMELINE_H
#pragma once
#include "Interpolator.h"
template <class T>
class Timeline
{
public:
enum LoopMode
{
NORMAL, REVERSE, LOOP
};
protected:
T prevYValue;
float prevXValue;
public:
Interpolator<T>* pInterp;
T startValue;
T endValue;
LoopMode loopMode;
float duration; // in milliseconds
float currentTime; // in milliseconds
void init(T start, T end, float _duration, Interpolator<T>* interp)
{
SetInterpolationRange(start, end);
prevYValue = start;
prevXValue = 0;
this->duration = _duration;
loopMode = NORMAL;
pInterp = interp;
}
protected:
float computeTimeStepping(float curTime, float elapsedMs)
{
switch (loopMode)
{
case NORMAL:
curTime += elapsedMs;
if (curTime > duration)
{
return duration;
}
case REVERSE:
curTime -= elapsedMs;
if (curTime < 0)
{
return 0;
}
case LOOP:
curTime += elapsedMs;
if (curTime > duration)
{
return fmod(curTime, duration);
}
}
return curTime;
}
void positCursorByRatio(float ratio)
{
switch (loopMode)
{
case NORMAL:
currentTime = ratio * duration;
break;
case REVERSE:
currentTime = (1 - ratio) * duration;
break;
case LOOP:
break;
}
}
public:
virtual ~Timeline() {}
Timeline(T start, T end, float _duration, Interpolator<T>* interp)
{
currentTime = 0;
init(start, end, _duration, interp);
}
Timeline(Interpolator<T>* interp)
{
currentTime = 0;
init(0, 1, 1000, interp);
}
// Accumulate time and produce the interpolated value accordingly
virtual T step(float elapsedMs)
{
currentTime = computeTimeStepping(currentTime, elapsedMs);
prevXValue = currentTime / duration;
prevYValue = pInterp->compute(startValue, endValue, prevXValue);
return prevYValue;
}
// Rewind the current time to initial position
virtual void rewind()
{
positCursorByRatio(0);
}
void SetInterpolationRange(T start, T end)
{
startValue = start;
endValue = end;
}
float GetPrevXValue() { return prevXValue; }
T GetPrevYValue() { return prevYValue; }
};
namespace {
float tempFloat0 = 0;
float tempFloat1 = 1;
int tempInt0 = 0;
int tempInt1 = 1;
}
class TimelineFloat
: public Timeline<float>
{
public:
TimelineFloat()
: Timeline<float>(0, 1, 1000, &InterpPredef::CUBIC_FLOAT) {}
};
class TimelineInt
: public Timeline<int>
{
public:
TimelineInt()
: Timeline<int>(0, 1, 1000, &InterpPredef::CUBIC_INT) {}
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_TIMELINE_H
@@ -0,0 +1,853 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Polygon math helper functions optimized for breakable glass sim
#include "RenderDll_precompiled.h"
#include "PolygonMath2D.h"
#ifndef RELEASE
#define ASSERT_NUM_POLY_SIDES(numPts) {if (numPts < 0 || numPts > POLY_ARRAY_SIZE) { \
CRY_ASSERT_MESSAGE(0, "[BreakGlassSystem Error]: Polygon too large, need to increase array sizes."); \
CryLogAlways("[BreakGlassSystem Error]: Polygon too large, need to increase array sizes."); } \
}
#else
#define ASSERT_NUM_POLY_SIDES(numPts)
#endif
//--------------------------------------------------------------------------------------------------
// Name: PointInTriangle2D
// Desc: Determines if a point is in the specified triangle
//--------------------------------------------------------------------------------------------------
bool PointInTriangle2D(const Vec2& pt, const Vec2& a, const Vec2& b, const Vec2& c)
{
float ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
float cCROSSap, bCROSScp, aCROSSbp;
ax = c.x - b.x;
ay = c.y - b.y;
bx = a.x - c.x;
by = a.y - c.y;
cx = b.x - a.x;
cy = b.y - a.y;
apx = pt.x - a.x;
apy = pt.y - a.y;
bpx = pt.x - b.x;
bpy = pt.y - b.y;
cpx = pt.x - c.x;
cpy = pt.y - c.y;
aCROSSbp = ax * bpy - ay * bpx;
cCROSSap = cx * apy - cy * apx;
bCROSScp = bx * cpy - by * cpx;
float ra = (float)fsel(aCROSSbp, 1.0f, 0.0f);
float rb = (float)fsel(cCROSSap, 1.0f, 0.0f);
float rc = (float)fsel(bCROSScp, 1.0f, 0.0f);
return (ra + rb + rc) > 2.5f;
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: TriangleIsConvex2D
// Desc: Determines if a triangle is convex (angle at B less than 180 degrees)
//--------------------------------------------------------------------------------------------------
bool TriangleIsConvex2D(const Vec2& a, const Vec2& b, const Vec2& c)
{
const Vec2 ba = a - b;
const Vec2 bc = c - b;
const float cross = ba.x * bc.y - bc.x * ba.y;
return (cross < 0.0f);
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: LineCircleIntersect2D
// Desc: Finds the intersection points (if any) between a line and circle
// Note: Returns the number of intersection points (0, 1 or 2)
//--------------------------------------------------------------------------------------------------
int LineCircleIntersect2D(const Vec2& pt0, const Vec2& pt1, const Vec2& center, const float radiusSq, float& intersectA, float& intersectB)
{
int numIntersects = 0;
const Vec2 lineSegment = pt1 - pt0;
const Vec2 circleToLine = pt0 - center;
// Check if there is an intersection
const float a = lineSegment.Dot(lineSegment);
const float b = 2.0f * circleToLine.Dot(lineSegment);
const float c = circleToLine.Dot(circleToLine) - radiusSq;
float discriminant = b * b - 4 * a * c;
float isIntersection = min(discriminant, a);
if (isIntersection >= 0.0f)
{
// Find exact intersection points (assuming infinite length line)
discriminant = sqrtf(discriminant);
float inv2A = 1.0f / (a + a);
intersectA = (-b + discriminant) * inv2A;
intersectB = (-b - discriminant) * inv2A;
// Found if either value valid
if (intersectA >= 0.0f && intersectA <= 1.0f)
{
++numIntersects;
}
if (intersectB >= 0.0f && intersectB <= 1.0f)
{
++numIntersects;
}
}
return numIntersects;
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: PointInPolygon2D
// Desc: Determines if a point is in the specified polygon
// Note: Taken from "Cry_GeoOverlap.h" and cut down for our specific tests
//--------------------------------------------------------------------------------------------------
bool PointInPolygon2D(const Vec2& pt, const Vec2* pPolygon, const int numPts)
{
bool count = false;
if (pPolygon)
{
for (int i = 0, j = 1; i < numPts; ++i, ++j)
{
j = (j == numPts) ? 0 : j;
const Vec2& l0 = pPolygon[i];
const Vec2& l1 = pPolygon[j];
if ((((l1.y < pt.y) && (pt.y < l0.y)) || ((l0.y < pt.y) && (pt.y < l1.y)))
&& (pt.x < (l0.x - l1.x) * (pt.y - l1.y) / (l0.y - l1.y) + l1.x))
{
count = !count;
}
}
}
return count;
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: CalculatePolygonArea2D
// Desc: Calculates the area covered by a 2D polygon
//--------------------------------------------------------------------------------------------------
float CalculatePolygonArea2D(const Vec2* pPolygon, const int numPts)
{
float area = 0.0f;
if (pPolygon && numPts > 0)
{
for (int i = numPts - 1, j = 0; j < numPts; i = j++)
{
area += pPolygon[i].x * pPolygon[j].y;
area -= pPolygon[j].x * pPolygon[i].y;
}
}
return area * 0.5f;
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: CalculatePolygonBounds2D
// Desc: Calculates the AA size of a 2D polygon
//--------------------------------------------------------------------------------------------------
Vec2 CalculatePolygonBounds2D(const Vec2* pPolygon, const int numPts)
{
Vec2 bounds(Vec2_Zero);
if (pPolygon && numPts > 0)
{
Vec2 minPt = pPolygon[0], maxPt = pPolygon[0];
for (int i = 1; i < numPts; ++i)
{
minPt.x = min(minPt.x, pPolygon[i].x);
minPt.y = min(minPt.y, pPolygon[i].y);
maxPt.x = max(maxPt.x, pPolygon[i].x);
maxPt.y = max(maxPt.y, pPolygon[i].y);
}
bounds = maxPt - minPt;
}
return bounds;
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: CalculatePolygonCenter2D
// Desc: Calculates the center of a 2D polygon
//--------------------------------------------------------------------------------------------------
Vec2 CalculatePolygonCenter2D(const Vec2* pPolygon, const int numPts)
{
Vec2 center(0.0f, 0.0f);
if (pPolygon && numPts > 0)
{
const float size = (float)numPts;
for (int i = 0; i < numPts; ++i)
{
center += pPolygon[i];
}
center /= size;
}
return center;
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: CalculatePolygonSharedPerimeter2D
// Desc: Calculates the connected percentage of fragments
// Note: Returns fraction of perimeter connected in two float params
//--------------------------------------------------------------------------------------------------
bool CalculatePolygonSharedPerimeter2D(const Vec2* pPolygonA, const int numPtsA, const Vec2* pPolygonB, const int numPtsB, float& connectionA, float& connectionB)
{
// Default values
const int minPolySize = 3;
connectionA = connectionB = 0.0f;
ASSERT_NUM_POLY_SIDES(numPtsA);
ASSERT_NUM_POLY_SIDES(numPtsB);
if (pPolygonA && numPtsA >= minPolySize && numPtsA <= POLY_ARRAY_SIZE
&& pPolygonB && numPtsB >= minPolySize && numPtsB <= POLY_ARRAY_SIZE)
{
// Check for shared polygon points
TPolyIndexArray polyAShared, polyBShared;
for (int i = 0; i < numPtsA; ++i)
{
for (int j = 0; j < numPtsB; ++j)
{
// Store matching points
if (pPolygonA[i] == pPolygonB[j])
{
polyAShared.push_back(i);
polyBShared.push_back(j);
}
}
}
// Valid connection found when two or more points shared
const bool connFound = (polyAShared.size() >= 2);
// Calculate fraction of A that is shared
if (connFound)
{
// Calculate squared length of A's perimeter shared
const uint polyASize = polyAShared.size() - 1;
for (uint i = 0; i < polyASize; ++i)
{
const Vec2& pt = pPolygonA[polyAShared[i]];
const Vec2& nextPt = pPolygonA[polyAShared[i + 1]];
connectionA += (nextPt - pt).GetLength2();
}
// Calculate remaining squared perimeter length
float polyAPerimSq = connectionA;
int polyIndex = polyAShared.back();
while (polyIndex != polyAShared[0])
{
polyIndex = (polyIndex + 1 == numPtsA) ? 0 : polyIndex + 1;
int nextPolyIndex = (polyIndex + 1 == numPtsA) ? 0 : polyIndex + 1;
const Vec2& pt = pPolygonA[polyIndex];
const Vec2& nextPt = pPolygonA[nextPolyIndex];
polyAPerimSq += (nextPt - pt).GetLength2();
}
// Convert to fraction
connectionA = sqrtf(connectionA / polyAPerimSq);
}
// Calculate fraction of B that is shared
if (connFound)
{
// Calculate squared length of B's perimeter shared
const uint polyBSize = polyBShared.size() - 1;
for (uint i = 0; i < polyBSize; ++i)
{
const Vec2& pt = pPolygonB[polyBShared[i]];
const Vec2& nextPt = pPolygonB[polyBShared[i + 1]];
connectionB += (nextPt - pt).GetLength2();
}
// Calculate remaining squared perimeter length
float polyBPerimSq = connectionB;
int polyIndex = polyBShared.back();
while (polyIndex != polyBShared[0])
{
polyIndex = (polyIndex + 1 == numPtsB) ? 0 : polyIndex + 1;
int nextPolyIndex = (polyIndex + 1 == numPtsB) ? 0 : polyIndex + 1;
const Vec2& pt = pPolygonB[polyIndex];
const Vec2& nextPt = pPolygonB[nextPolyIndex];
polyBPerimSq += (nextPt - pt).GetLength2();
}
// Convert to fraction
connectionB = sqrtf(connectionB / polyBPerimSq);
}
// Successful
return true;
}
return false;
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: TriangulatePolygon2D
// Desc: Generates triangles from a polygon's in-order point list
//--------------------------------------------------------------------------------------------------
void TriangulatePolygon2D(const Vec2* pPolygon, const int numPolyPts, PodArray<Vec2>* pVertices, PodArray<uint8>* pIndices)
{
ASSERT_NUM_POLY_SIDES(numPolyPts);
if (pPolygon && numPolyPts >= 3 && numPolyPts <= POLY_ARRAY_SIZE && (pVertices || pIndices))
{
int numPts = numPolyPts;
int numTris = numPts - 2;
// Offset for output vertex data
int vertOffset = 0;
if (pVertices)
{
vertOffset = pVertices->Count();
pVertices->resize(vertOffset + numTris * 3);
}
// Offset for output index data
int indOffset = 0;
if (pIndices)
{
indOffset = pIndices->Count();
pIndices->resize(indOffset + numTris * 3);
}
// Simple case, push single triangle
if (numTris == 1)
{
if (pVertices)
{
(*pVertices)[vertOffset] = pPolygon[0];
(*pVertices)[vertOffset + 1] = pPolygon[1];
(*pVertices)[vertOffset + 2] = pPolygon[2];
}
if (pIndices)
{
(*pIndices)[indOffset] = 0;
(*pIndices)[indOffset + 1] = 1;
(*pIndices)[indOffset + 2] = 2;
}
}
// Complex case, need to triangulate full point list
else if (numTris > 1)
{
// Initialise outline list as pIndices
TPolyIndexArray outline;
outline.resize(numPts);
for (int i = 0; i < numPts; ++i)
{
outline[i] = i;
}
// Already know the expected number of triangles
for (int i = 0; i < numTris; ++i)
{
int* pIterBegin = outline.begin();
int* pIterEnd = outline.end();
int* pIterA = pIterBegin;
int* pIterB = pIterBegin;
int* pIterC = pIterBegin;
++pIterB;
++pIterC;
++pIterC;
// Loop around entire list and check for ears
for (int j = 0; j < numPts; ++j)
{
const Vec2& a = pPolygon[*pIterA];
const Vec2& b = pPolygon[*pIterB];
const Vec2& c = pPolygon[*pIterC];
// Valid ear triangles will be convex (internal angle < 180)
if (TriangleIsConvex2D(a, b, c))
{
// Check valid triangles against all other outline points
int* pIterPt = pIterBegin;
bool isEar = true;
do
{
if (pIterPt != pIterA && pIterPt != pIterB && pIterPt != pIterC)
{
const Vec2& pt = pPolygon[*pIterPt];
// When we have a point in the triangle, it means this is *not* an ear
if (PointInTriangle2D(pt, a, b, c))
{
isEar = false;
break;
}
}
++pIterPt;
} while (pIterPt != pIterEnd);
// Create triangle and clip ear when found
if (isEar)
{
if (pVertices)
{
(*pVertices)[vertOffset] = pPolygon[*pIterA];
(*pVertices)[vertOffset + 1] = pPolygon[*pIterB];
(*pVertices)[vertOffset + 2] = pPolygon[*pIterC];
}
if (pIndices)
{
(*pIndices)[indOffset] = *pIterA;
(*pIndices)[indOffset + 1] = *pIterB;
(*pIndices)[indOffset + 2] = *pIterC;
}
// If ear is last point, erase immediately
if (*pIterB == *pIterEnd)
{
outline.pop_back();
}
// May need to shuffle points along (rather than erase)
else
{
while (pIterC != pIterEnd)
{
*pIterB = *pIterC;
++pIterB;
++pIterC;
// Need to handle looping case
if (pIterB == pIterEnd)
{
pIterB = pIterBegin;
}
}
outline.pop_back();
}
// Done with this ear
break;
}
}
// Try next triangle
++pIterA;
++pIterB;
++pIterC;
// Treat outline as a ring buffer
pIterBegin = outline.begin();
pIterEnd = outline.end();
if (pIterC == pIterEnd)
{
pIterC = pIterBegin;
}
else if (pIterB == pIterEnd)
{
pIterB = pIterBegin;
}
}
// Clipped one ear point
--numPts;
vertOffset += 3;
indOffset += 3;
}
}
}
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: FindPolygonCircleSplitPoints
// Desc: Common code to finds the split points for SplitPolygonAroundPoint() varations
//--------------------------------------------------------------------------------------------------
struct SPolyCircleSplit
{
int A, B, ANext, BNext, numPtsToMove;
Vec2 ptA, ptB, ptMid;
bool allPtsInsideCircle, validSegment, cyclicSegment;
};
bool FindPolygonCircleSplitPoints(const Vec2* pPolygon, const int numPts, const Vec2& splitPt, const float splitRadius, SPolyCircleSplit& split)
{
// Default data
const int invalidPt = -1;
split.A = split.B = invalidPt;
split.allPtsInsideCircle = true;
if (pPolygon && numPts >= 3)
{
const float splitRadiusSq = splitRadius * splitRadius;
float intersectA, intersectB;
// Loop round polygon
for (int i = 0; i < numPts; ++i)
{
// Check segment for intersection
int j = (i + 1 == numPts) ? 0 : i + 1;
float tA, tB;
int numIntersects = LineCircleIntersect2D(pPolygon[i], pPolygon[j], splitPt, splitRadiusSq, tA, tB);
// Store line intersection points if found
if (numIntersects == 1)
{
tA = (tA < 0.0f || tA > 1.0f) ? tB : tA;
if (split.A == invalidPt)
{
split.A = i;
intersectA = tA;
}
else
{
split.B = i;
intersectB = tA;
break;
}
}
// Can be a case where the circle intersects fully on one line. This
// means we can't really split the polygon though, so early out
else if (numIntersects == 2)
{
split.A = split.B = invalidPt;
intersectA = intersectB = 0.0f;
break;
}
// Check if we still have all points inside the circle
if (split.allPtsInsideCircle)
{
const float distSq = (pPolygon[i] - splitPt).GetLength2();
if (distSq > splitRadiusSq)
{
split.allPtsInsideCircle = false;
}
}
}
// Valid polygon segment?
if (split.validSegment = (split.A >= 0 && split.B >= 0 && split.A != split.B))
{
// May need to swap points to ensure generating inner polygon
const float splitADistSq = (pPolygon[split.A] - splitPt).GetLength2();
if (splitADistSq < splitRadiusSq)
{
int temp = split.A;
split.A = split.B;
split.B = temp;
}
// Calculate how many points in cut segment
split.cyclicSegment = split.A > split.B;
split.numPtsToMove = split.cyclicSegment ? (split.B + numPts) - split.A : split.B - split.A;
if (split.numPtsToMove > 0)
{
// Calculate intersect points
split.ANext = (split.A + 1 == numPts) ? 0 : split.A + 1;
split.BNext = (split.B + 1 == numPts) ? 0 : split.B + 1;
split.ptA = pPolygon[split.A] * intersectA + pPolygon[split.ANext] * (1.0f - intersectA);
split.ptB = pPolygon[split.B] * intersectB + pPolygon[split.BNext] * (1.0f - intersectB);
// Extra mid-point lying on circle, for use with the outer polygon only
split.ptMid = (split.ptA + split.ptB) * 0.5f;
split.ptMid = splitPt + (split.ptMid - splitPt).Normalize() * splitRadius;
}
else
{
split.validSegment = false;
}
}
}
return (split.validSegment && split.numPtsToMove > 0);
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: SplitPolygonAroundPoint <TPolygonArray>
// Desc: Splits a polygon outline along the radial line around the point
// Note: Removes verts from input data, then creates the INNER polygon piece.
// Does not do anything if polygon fully contains circle
//--------------------------------------------------------------------------------------------------
void SplitPolygonAroundPoint(TPolygonArray& outline, const Vec2& splitPt, const float splitRadius, TPolygonArray& splitInnerOutline)
{
const Vec2* pOutlinePts = outline.begin();
const int outlineSize = outline.size();
// Build inner polygon if both split points where found, and they create a valid segment
SPolyCircleSplit split;
if (FindPolygonCircleSplitPoints(pOutlinePts, outlineSize, splitPt, splitRadius, split))
{
// Create new inner polygon from split points and old polygon segment (if arrays large enough)
if (split.numPtsToMove > 0 && split.numPtsToMove <= POLY_ARRAY_SIZE - 2)
{
splitInnerOutline.resize(split.numPtsToMove + 2);
splitInnerOutline[0] = split.ptA;
splitInnerOutline[split.numPtsToMove + 1] = split.ptB;
for (int i = 1; i < split.numPtsToMove + 1; ++i)
{
int j = split.A + i;
j = (j >= outlineSize) ? j - outlineSize : j;
splitInnerOutline[i] = pOutlinePts[j];
}
}
else
{
splitInnerOutline.clear();
}
// Cyclic segment - need to delete both ends, then add intersect points
if (split.cyclicSegment)
{
const int numStartPts = split.B + 1;
const int numEndPts = outlineSize - (split.A + 1);
const bool canAddMidPt = (numStartPts + numEndPts >= 3);
if (numEndPts > 0)
{
outline.erase(split.A + 1, numEndPts);
}
if (numStartPts > 0)
{
outline.erase(0, numStartPts);
}
outline.push_back(split.ptA);
if (canAddMidPt)
{
outline.push_back(split.ptMid);
}
outline.push_back(split.ptB);
}
// Contiguous segment - single delete then insert intersect points
else
{
outline.erase(split.ANext, split.numPtsToMove);
const bool splitTouchesEnd = (split.B == outlineSize - 1);
const bool canAddMidPt = (split.numPtsToMove >= 3);
if (splitTouchesEnd)
{
outline.push_back(split.ptA);
if (canAddMidPt)
{
outline.push_back(split.ptMid);
}
outline.push_back(split.ptB);
}
else
{
outline.insert_before(split.ptB, split.A + 1);
if (canAddMidPt)
{
outline.insert_before(split.ptMid, split.A + 1);
}
outline.insert_before(split.ptA, split.A + 1);
}
}
}
// If failed, might be the case where entire polygon is inside
else if (split.allPtsInsideCircle)
{
// Move the polygon to the output list
splitInnerOutline.resize(outlineSize);
for (int i = 0; i < outlineSize; ++i)
{
splitInnerOutline[i] = pOutlinePts[i];
}
outline.clear();
}
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: SplitPolygonAroundPoint <PodArray>
// Desc: Splits a polygon outline along the radial line around the point
// Note: Removes verts from input data, then creates the INNER polygon piece.
// Does not do anything if polygon fully contains circle
//--------------------------------------------------------------------------------------------------
void SplitPolygonAroundPoint(PodArray<Vec2>& outline, const Vec2& splitPt, const float splitRadius, TPolygonArray& splitInnerOutline)
{
const Vec2* pOutlinePts = outline.begin();
const int outlineSize = outline.Count();
// Build inner polygon if both split points where found, and they create a valid segment
SPolyCircleSplit split;
if (FindPolygonCircleSplitPoints(pOutlinePts, outlineSize, splitPt, splitRadius, split))
{
// Create new inner polygon from split points and old polygon segment
splitInnerOutline.resize(split.numPtsToMove + 2);
splitInnerOutline[0] = split.ptA;
splitInnerOutline[split.numPtsToMove + 1] = split.ptB;
for (int i = 1; i < split.numPtsToMove + 1; ++i)
{
int j = split.A + i;
j = (j >= outlineSize) ? j - outlineSize : j;
splitInnerOutline[i] = pOutlinePts[j];
}
// Cyclic segment - need to delete both ends, then add intersect points
if (split.cyclicSegment)
{
const int numStartPts = split.B + 1;
const int numEndPts = outlineSize - (split.A + 1);
if (numEndPts > 0)
{
outline.Delete(split.A + 1, numEndPts);
}
if (numStartPts > 0)
{
outline.Delete(0, numStartPts);
}
outline.push_back(split.ptA);
outline.push_back(split.ptMid);
outline.push_back(split.ptB);
}
// Contiguous segment - single delete then insert intersect points
else
{
outline.Delete(split.ANext, split.numPtsToMove);
const bool splitTouchesEnd = split.B == outlineSize - 1;
if (splitTouchesEnd)
{
outline.push_back(split.ptA);
outline.push_back(split.ptMid);
outline.push_back(split.ptB);
}
else
{
outline.InsertBefore(split.ptB, split.A + 1);
outline.InsertBefore(split.ptMid, split.A + 1);
outline.InsertBefore(split.ptA, split.A + 1);
}
}
}
// If failed, might be the case where entire polygon is inside
else if (split.allPtsInsideCircle)
{
// Move the polygon to the output list
splitInnerOutline.resize(outlineSize);
for (int i = 0; i < outlineSize; ++i)
{
splitInnerOutline[i] = pOutlinePts[i];
}
outline.Clear();
}
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: PolygonInCircle2D
// Desc: Determines if a polygon is contained within the specified circle
//--------------------------------------------------------------------------------------------------
EPolygonInCircle2D PolygonInCircle2D(const Vec2& center, const float radius, const Vec2* pPolygon, const int numPts)
{
EPolygonInCircle2D state = EPolygonInCircle2D_Outside;
if (pPolygon && numPts >= 3)
{
const float radiusSq = radius * radius;
Vec2 centerDir;
float centerDistSq;
int numPtsOutside = 0;
// Check state of each point
for (int i = 0; i < numPts; ++i)
{
centerDir = center - pPolygon[i];
centerDistSq = centerDir.GetLength2();
if (centerDistSq > radiusSq)
{
++numPtsOutside;
}
}
// Determine state
if (numPtsOutside == numPts)
{
state = EPolygonInCircle2D_Outside;
}
else if (numPtsOutside > 0)
{
state = EPolygonInCircle2D_Overlap;
}
else
{
state = EPolygonInCircle2D_Inside;
}
}
return state;
}//-------------------------------------------------------------------------------------------------
@@ -0,0 +1,153 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_UTILS_POLYGONMATH2D_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_UTILS_POLYGONMATH2D_H
#pragma once
#include "CryFixedArray.h"
//==================================================================================================
// Name: FixedPodArray
// Desc: Extension of CryFixedArray to add useful functionality
// Note: This should be promoted into CryFixedArray in the long term
// Author: Chris Bunner
//==================================================================================================
template <class T, unsigned int N>
class FixedPodArray
: public CryFixedArray<T, N>
{
typedef CryFixedArray<T, N> CFA;
public:
ILINE void resize(const uint size)
{
if (size <= N)
{
CFA::m_curSize[0] = size;
}
else
{
CryLogAlways("FixedPodArray::resize() failing as size too large - NOT resizing array");
CRY_ASSERT_MESSAGE(0, "FixedPodArray::resize() failing as size too large - NOT resizing array");
}
}
ILINE void erase(const uint index, const uint count = 1)
{
const uint size = CFA::m_curSize[0];
if (index == size - count)
{
// Simple remove
CFA::m_curSize[0] -= count;
}
else if (index + count < size)
{
// Shuffle set of elements along
const uint range = size - (index + count);
memmove(&CFA::at(index), &CFA::at(index + count), sizeof(T) * range);
CFA::m_curSize[0] -= count;
}
else
{
CryLogAlways("FixedPodArray::erase() failing as element range invalid - NOT removing element");
CRY_ASSERT_MESSAGE(0, "FixedPodArray::erase() failing as element range invalid - NOT removing element");
}
}
ILINE void insert_before(const T& elem, const uint index)
{
const uint size = CFA::m_curSize[0];
if (index < size && size < N)
{
// Shuffle set of elements along
const uint count = size - index;
memmove(&CFA::at(index + 1), &CFA::at(index), sizeof(T) * count);
// Add new element
memcpy(&CFA::at(index), &elem, sizeof(T));
++CFA::m_curSize[0];
}
else
{
CryLogAlways("FixedPodArray::insert_before() failing as element index invalid - NOT inserting element");
CRY_ASSERT_MESSAGE(0, "FixedPodArray::insert_before() failing as element index invalid - NOT inserting element");
}
}
ILINE int find(const T& elem)
{
const uint size = CFA::m_curSize[0];
const int invalid = -1;
int index = invalid;
for (uint i = 0; i < size; ++i)
{
if (CFA::at(i) == elem)
{
index = i;
break;
}
}
return index;
}
};
//==================================================================================================
// Name: PolygonMath2D
// Desc: Polygon math helper functions optimized for breakable glass sim
// Note: Functions often assume clockwise polygon point order
// Author: Chris Bunner
//==================================================================================================
// Common polygon array types
#define POLY_ARRAY_SIZE 45
typedef FixedPodArray<Vec2, POLY_ARRAY_SIZE> TPolygonArray;
typedef FixedPodArray<int, POLY_ARRAY_SIZE> TPolyIndexArray;
// 2D triangle helpers
bool PointInTriangle2D(const Vec2& pt, const Vec2& a, const Vec2& b, const Vec2& c);
bool TriangleIsConvex2D(const Vec2& a, const Vec2& b, const Vec2& c);
// 2D intersection helpers
int LineCircleIntersect2D(const Vec2& pt0, const Vec2& pt1, const Vec2& center, const float radiusSq, float& intersectA, float& intersectB);
// 2D polygon helpers
bool PointInPolygon2D(const Vec2& pt, const Vec2* pPolygon, const int numPts);
float CalculatePolygonArea2D(const Vec2* pPolygon, const int numPts);
Vec2 CalculatePolygonBounds2D(const Vec2* pPolygon, const int numPts);
Vec2 CalculatePolygonCenter2D(const Vec2* pPolygon, const int numPts);
bool CalculatePolygonSharedPerimeter2D(const Vec2* pPolygonA, const int numPtsA, const Vec2* pPolygonB, const int numPtsB, float& connectionA, float& connectionB);
void TriangulatePolygon2D(const Vec2* pPolygon, const int numPolyPts, PodArray<Vec2>* pVertices, PodArray<uint8>* pIndices);
void SplitPolygonAroundPoint(TPolygonArray& outline, const Vec2& splitPt, const float splitRadius, TPolygonArray& splitInnerOutline);
void SplitPolygonAroundPoint(PodArray<Vec2>& outline, const Vec2& splitPt, const float splitRadius, TPolygonArray& splitInnerOutline);
// Helper with result enum
enum EPolygonInCircle2D
{
EPolygonInCircle2D_Inside = 0,
EPolygonInCircle2D_Outside,
EPolygonInCircle2D_Overlap
};
EPolygonInCircle2D PolygonInCircle2D(const Vec2& center, const float radius, const Vec2* pPolygon, const int numPts);
#endif // _POLYGON_MATH_2D_
@@ -0,0 +1,288 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_UTILS_SPATIALHASHGRID_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDELEMENTS_UTILS_SPATIALHASHGRID_H
#pragma once
#if GLASSCFG_USE_HASH_GRID
//==================================================================================================
// Name: CSpatialHashGrid
// Desc: Templated 2D spatial hashing grid spanning positively from origin
// Author: Chris Bunner
//==================================================================================================
template <class T, uint32 GridSize, uint32 BucketSize>
class CSpatialHashGrid
{
public:
CSpatialHashGrid(const float gridWidth, const float gridHeight);
~CSpatialHashGrid();
uint32 HashPosition(const float x, const float y);
void AddElementToGrid(const float x, const float y, const T& elem);
void AddElementToGrid(const uint32 index, const T& elem);
void RemoveElementFromGrid(const float x, const float y, const T& elem);
void RemoveElementFromGrid(const uint32 index, const T& elem);
void ClearGrid();
#ifndef RELEASE
void DebugDraw();
#endif
// Bucket accessors
ILINE const CryFixedArray<T, BucketSize>* const GetBucket(const uint32 index)
{
return (index < m_area) ? &m_buckets[index] : NULL;
}
ILINE uint32 GetNumBuckets()
{
return m_area;
}
// Resizing
ILINE void Resize(const float gridWidth, const float gridHeight)
{
m_invCellWidth = m_fGridSize / gridWidth;
m_invCellHeight = m_fGridSize / gridHeight;
}
private:
CSpatialHashGrid(const CSpatialHashGrid& rhs);
CSpatialHashGrid& operator = (const CSpatialHashGrid& rhs);
uint32 m_gridSize;
uint32 m_area;
float m_fGridSize;
float m_invCellWidth;
float m_invCellHeight;
CryFixedArray<T, BucketSize> m_buckets[GridSize * GridSize];
};//------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: Constructor
//--------------------------------------------------------------------------------------------------
template <class T, uint32 GridSize, uint32 BucketSize>
CSpatialHashGrid<T, GridSize, BucketSize>::CSpatialHashGrid(const float gridWidth, const float gridHeight)
: m_gridSize(GridSize)
, m_area(GridSize * GridSize)
, m_fGridSize((float)GridSize)
{
Resize(gridWidth, gridHeight);
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: Destructor
//--------------------------------------------------------------------------------------------------
template <class T, uint32 GridSize, uint32 BucketSize>
CSpatialHashGrid<T, GridSize, BucketSize>::~CSpatialHashGrid()
{
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: HashPosition
// Desc: Hashes a position to cell index and performs simple bounds checking
//--------------------------------------------------------------------------------------------------
template <class T, uint32 GridSize, uint32 BucketSize>
uint32 CSpatialHashGrid<T, GridSize, BucketSize>::HashPosition(const float x, const float y)
{
const uint32 actualCellIndex = (uint32)(y * m_invCellHeight * m_fGridSize + x * m_invCellWidth);
const uint32 errorCellIndex = (uint32) - 1;
float cellX = x * m_invCellWidth;
float cellY = y * m_invCellHeight;
// Handle out of bounds
cellX = (float)fsel(cellX, cellX, -1.0f);
cellX = (float)fsel(m_fGridSize - cellX, cellX, -1.0f);
cellY = (float)fsel(cellY, cellY, -1.0f);
cellY = (float)fsel(m_fGridSize - cellY, cellY, -1.0f);
cellX = min(cellX, cellY);
const uint32 cellIndex = (cellX < 0.0f) ? errorCellIndex : actualCellIndex;
return cellIndex;
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: AddElementToGrid
// Desc: Hashes and adds a unique element to the grid buckets
//--------------------------------------------------------------------------------------------------
template <class T, uint32 GridSize, uint32 BucketSize>
void CSpatialHashGrid<T, GridSize, BucketSize>::AddElementToGrid(const float x, const float y, const T& elem)
{
uint32 elemCell = HashPosition(x, y);
AddElementToGrid(elemCell, elem);
}
template <class T, uint32 GridSize, uint32 BucketSize>
void CSpatialHashGrid<T, GridSize, BucketSize>::AddElementToGrid(const uint32 index, const T& elem)
{
if (index < m_area)
{
// Only add unique elements
CryFixedArray<T, BucketSize>* pBucket = &m_buckets[index];
const uint numElems = pBucket->size();
const T* pElems = pBucket->begin();
int elemIndex = -1;
if (numElems < BucketSize)
{
for (uint i = 0; i < numElems; ++i)
{
if (pElems[i] == elem)
{
elemIndex = i;
break;
}
}
if (elemIndex == -1)
{
pBucket->push_back(elem);
}
}
}
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: RemoveElementFromGrid
// Desc: Hashes and removes an element from the grid buckets
//--------------------------------------------------------------------------------------------------
template <class T, uint32 GridSize, uint32 BucketSize>
void CSpatialHashGrid<T, GridSize, BucketSize>::RemoveElementFromGrid(const float x, const float y, const T& elem)
{
uint32 elemCell = HashPosition(x, y);
RemoveElementFromGrid(elemCell, elem);
}
template <class T, uint32 GridSize, uint32 BucketSize>
void CSpatialHashGrid<T, GridSize, BucketSize>::RemoveElementFromGrid(const uint32 index, const T& elem)
{
if (index < m_area)
{
CryFixedArray<T, BucketSize>* pBucket = &m_buckets[index];
const uint numElems = pBucket->size();
T* pElems = pBucket->begin();
for (uint i = 0; i < numElems; ++i)
{
if (pElems[i] == elem)
{
pElems[i] = pElems[numElems - 1];
pBucket->pop_back();
break;
}
}
}
}//-------------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------------
// Name: ClearGrid
// Desc: Clears all grid buckets
//--------------------------------------------------------------------------------------------------
template <class T, uint32 GridSize, uint32 BucketSize>
void CSpatialHashGrid<T, GridSize, BucketSize>::ClearGrid()
{
for (uint32 i = 0; i < m_area; ++i)
{
m_buckets[i].clear();
}
}//-------------------------------------------------------------------------------------------------
#ifndef RELEASE
//--------------------------------------------------------------------------------------------------
// Name: DebugDraw
// Desc: Draws the grid element counts to the screen
//--------------------------------------------------------------------------------------------------
template <class T, uint32 GridSize, uint32 BucketSize>
void CSpatialHashGrid<T, GridSize, BucketSize>::DebugDraw()
{
IRenderAuxGeom* pRenderer = gEnv->pRenderer->GetIRenderAuxGeom();
SAuxGeomRenderFlags oldFlags = pRenderer->GetRenderFlags();
SAuxGeomRenderFlags newFlags = e_Def2DPublicRenderflags;
newFlags.SetCullMode(e_CullModeNone);
newFlags.SetDepthWriteFlag(e_DepthWriteOff);
newFlags.SetAlphaBlendMode(e_AlphaBlended);
pRenderer->SetRenderFlags(newFlags);
// Draw black backing
const float invWidth = 1.0f / (float)gEnv->pRenderer->GetWidth();
const float invHeight = 1.0f / (float)gEnv->pRenderer->GetHeight();
const float minX = (322.5f - m_fGridSize * 15.0f) * invWidth;
const float maxX = (322.5f) * invWidth;
const float minY = (370.0f) * invHeight;
const float maxY = (370.0f + m_fGridSize * 15.0f) * invHeight;
Vec3 quad[6] =
{
Vec3(minX, minY, 0.0f),
Vec3(minX, maxY, 0.0f),
Vec3(maxX, maxY, 0.0f),
Vec3(minX, minY, 0.0f),
Vec3(maxX, maxY, 0.0f),
Vec3(maxX, minY, 0.0f)
};
pRenderer->DrawTriangles(quad, 6, ColorB(0, 0, 0, 127));
pRenderer->SetRenderFlags(oldFlags);
// Draw hash grid data
const ColorF col[8] =
{
ColorF(0.0f, 0.0f, 0.0f, 1.0f),
ColorF(1.0f, 0.0f, 0.0f, 1.0f),
ColorF(0.5f, 1.0f, 0.0f, 1.0f),
ColorF(0.0f, 1.0f, 0.0f, 1.0f),
ColorF(0.0f, 1.0f, 0.5f, 1.0f),
ColorF(0.0f, 0.5f, 1.0f, 1.0f),
ColorF(0.0f, 0.0f, 1.0f, 1.0f),
ColorF(0.5f, 0.0f, 1.0f, 1.0f),
};
float x = 315.0f, y = 370.0f;
for (uint32 i = 0; i < m_gridSize; ++i)
{
for (uint32 j = 0; j < m_gridSize; ++j)
{
int index = i * m_gridSize + j;
int count = (int)m_buckets[index].size();
ColorF textCol = col[min < int > (count, 7)];
if (count > 0)
{
textCol.r = textCol.r * 0.4f + 0.6f;
textCol.g = textCol.g * 0.4f + 0.6f;
textCol.b = textCol.b * 0.4f + 0.6f;
}
gEnv->pRenderer->Draw2dLabel(x, y, 1.0f, &textCol.r, false, "%i", count);
y += 15.0f;
}
x -= 15.0f;
y = 370.0f;
}
}//-------------------------------------------------------------------------------------------------
#endif // !RELEASE
#endif // GLASSCFG_USE_HASH_GRID
#endif // _SPATIAL_HASH_GRID_
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,636 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef _RENDERAUXGEOM_H_
#define _RENDERAUXGEOM_H_
#if defined(ENABLE_PROFILING_CODE) || !defined(_RELEASE)
# define ENABLE_RENDER_AUX_GEOM
#endif
#if defined(ENABLE_RENDER_AUX_GEOM)
#include "IRenderAuxGeom.h"
#include "VertexFormats.h"
#include <CrySizer.h>
#include <CryCommon/stl/STLAlignedAlloc.h>
class ICrySizer;
class CAuxGeomCB;
struct SAuxGeomCBRawDataPackaged;
struct IRenderAuxGeomImpl
{
public:
virtual ~IRenderAuxGeomImpl(){}
virtual void Flush(SAuxGeomCBRawDataPackaged& data, size_t begin, size_t end, bool reset = false) = 0;
virtual void RT_Flush(SAuxGeomCBRawDataPackaged& data, size_t begin, size_t end, bool reset = false) = 0;
virtual void FlushTextMessages(CTextMessages& tMessages, bool reset) = 0;
};
class CAuxGeomCB
: public IRenderAuxGeom
{
public:
// interface
virtual void SetRenderFlags(const SAuxGeomRenderFlags& renderFlags);
virtual SAuxGeomRenderFlags GetRenderFlags();
virtual void DrawPoint(const Vec3& v, const ColorB& col, uint8 size = 1);
virtual void DrawPoints(const Vec3* v, uint32 numPoints, const ColorB& col, uint8 size = 1);
virtual void DrawPoints(const Vec3* v, uint32 numPoints, const ColorB* col, uint8 size = 1);
virtual void DrawLine(const Vec3& v0, const ColorB& colV0, const Vec3& v1, const ColorB& colV1, float thickness = 1.0f);
virtual void DrawLines(const Vec3* v, uint32 numPoints, const ColorB& col, float thickness = 1.0f);
virtual void DrawLines(const Vec3* v, uint32 numPoints, const ColorB* col, float thickness = 1.0f);
virtual void DrawLines(const Vec3* v, uint32 numPoints, const vtx_idx* ind, uint32 numIndices, const ColorB& col, float thickness = 1.0f);
virtual void DrawLines(const Vec3* v, uint32 numPoints, const vtx_idx* ind, uint32 numIndices, const ColorB* col, float thickness = 1.0f);
virtual void DrawPolyline(const Vec3* v, uint32 numPoints, bool closed, const ColorB& col, float thickness = 1.0f);
virtual void DrawPolyline(const Vec3* v, uint32 numPoints, bool closed, const ColorB* col, float thickness = 1.0f);
virtual void DrawTriangle(const Vec3& v0, const ColorB& colV0, const Vec3& v1, const ColorB& colV1, const Vec3& v2, const ColorB& colV2);
virtual void DrawTriangles(const Vec3* v, uint32 numPoints, const ColorB& col);
virtual void DrawTriangles(const Vec3* v, uint32 numPoints, const ColorB* col);
virtual void DrawTriangles(const Vec3* v, uint32 numPoints, const vtx_idx* ind, uint32 numIndices, const ColorB& col);
virtual void DrawTriangles(const Vec3* v, uint32 numPoints, const vtx_idx* ind, uint32 numIndices, const ColorB* col);
virtual void DrawQuad(float width, float height, const Matrix34& matWorld, const ColorB& col, bool drawShaded = true);
virtual void DrawAABB(const AABB& aabb, bool bSolid, const ColorB& col, const EBoundingBoxDrawStyle& bbDrawStyle);
virtual void DrawAABBs(const AABB* aabbs, uint32 aabbCount, bool bSolid, const ColorB& col, const EBoundingBoxDrawStyle& bbDrawStyle);
virtual void DrawAABB(const AABB& aabb, const Matrix34& matWorld, bool bSolid, const ColorB& col, const EBoundingBoxDrawStyle& bbDrawStyle);
virtual void DrawOBB(const OBB& obb, const Vec3& pos, bool bSolid, const ColorB& col, const EBoundingBoxDrawStyle& bbDrawStyle);
virtual void DrawOBB(const OBB& obb, const Matrix34& matWorld, bool bSolid, const ColorB& col, const EBoundingBoxDrawStyle& bbDrawStyle);
virtual void DrawSphere(const Vec3& pos, float radius, const ColorB& col, bool drawShaded = true);
virtual void DrawDisk(const Vec3& pos, const Vec3& dir, float radius, const ColorB& col, bool drawShaded = true);
virtual void DrawCone(const Vec3& pos, const Vec3& dir, float radius, float height, const ColorB& col, bool drawShaded = true);
virtual void DrawCylinder(const Vec3& pos, const Vec3& dir, float radius, float height, const ColorB& col, bool drawShaded = true);
virtual void DrawBone(const Vec3& rParent, const Vec3& rBone, ColorB col);
virtual void RenderText(Vec3 pos, SDrawTextInfo& ti, const char* format, va_list args);
void Flush(bool reset);
virtual void Flush();
virtual void Commit(uint frames = 0);
virtual void Process();
public:
enum EPrimType
{
e_PtList,
e_LineList,
e_LineListInd,
e_TriList,
e_TriListInd,
e_Obj,
e_NumPrimTypes,
e_PrimTypeInvalid
};
enum EAuxDrawObjType
{
eDOT_Sphere,
eDOT_Cone,
eDOT_Cylinder,
eDOT_Disk,
eDOT_Quad,
};
struct SAuxDrawObjParams
{
SAuxDrawObjParams()
{
m_matWorld.SetIdentity();
m_matWorldRotation.SetIdentity();
m_color = 0;
m_size = 0;
m_shaded = false;
}
Matrix34 m_matWorld;
Matrix33 m_matWorldRotation;
uint32 m_color;
float m_size;
bool m_shaded;
};
struct SAuxPushBufferEntry
{
SAuxPushBufferEntry()
{
}
SAuxPushBufferEntry(uint32 numVertices, uint32 numIndices, uint32 vertexOffs, uint32 indexOffs, uint32 transMatrixIdx, const SAuxGeomRenderFlags& renderFlags)
: m_numVertices(numVertices)
, m_numIndices(numIndices)
, m_vertexOffs(vertexOffs)
, m_indexOffs(indexOffs)
, m_transMatrixIdx(transMatrixIdx)
, m_renderFlags(renderFlags)
{
}
SAuxPushBufferEntry(uint32 drawParamOffs, uint32 transMatrixIdx, const SAuxGeomRenderFlags& renderFlags)
: m_numVertices(0)
, m_numIndices(0)
, m_vertexOffs(drawParamOffs)
, m_indexOffs(0)
, m_transMatrixIdx(transMatrixIdx)
, m_renderFlags(renderFlags)
{
assert(e_Obj == GetPrimType(m_renderFlags));
}
bool GetDrawParamOffs(uint32& drawParamOffs) const
{
if (e_Obj == GetPrimType(m_renderFlags))
{
drawParamOffs = m_vertexOffs;
return(true);
}
return(false);
}
void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->AddObject(this, sizeof(*this));
}
uint32 m_numVertices;
uint32 m_numIndices;
uint32 m_vertexOffs;
uint32 m_indexOffs;
int m_transMatrixIdx;
SAuxGeomRenderFlags m_renderFlags;
};
typedef std::vector< SAuxPushBufferEntry > AuxPushBuffer;
typedef std::vector< const SAuxPushBufferEntry* > AuxSortedPushBuffer;
typedef std::vector< SAuxVertex > AuxVertexBuffer;
typedef std::vector< vtx_idx > AuxIndexBuffer;
typedef std::vector< SAuxDrawObjParams > AuxDrawObjParamBuffer;
typedef stl::aligned_vector<Matrix44, 16> AuxOrthoMatrixBuffer;
struct SAuxGeomCBRawData
{
public:
SAuxGeomCBRawData()
: m_isUsed(false)
, m_curRenderFlags(e_Def3DPublicRenderflags)
, m_curTransMatIdx(-1)
, m_uCount(0) {}
void GetSortedPushBuffer(size_t begin, size_t end, AuxSortedPushBuffer& auxSortedPushBuffer) const;
void GetMemoryUsage(ICrySizer* pSizer) const;
void Reset()
{
m_auxPushBuffer.resize(0);
m_auxVertexBuffer.resize(0);
m_auxIndexBuffer.resize(0);
m_auxDrawObjParamBuffer.resize(0);
m_auxOrthoMatrices.resize(0);
m_TextMessages.Clear();
m_curRenderFlags = e_Def3DPublicRenderflags;
m_curTransMatIdx = -1;
m_uCount = 0;
}
bool IsUsed()
{
return m_isUsed;
}
void SetUsed(bool used)
{
m_isUsed = used;
}
void SetCount(uint count)
{
m_uCount = count;
}
uint Count()
{
return m_uCount > 0 ? m_uCount-- : m_uCount;
}
public:
AuxPushBuffer m_auxPushBuffer;
AuxVertexBuffer m_auxVertexBuffer;
AuxIndexBuffer m_auxIndexBuffer;
AuxDrawObjParamBuffer m_auxDrawObjParamBuffer;
AuxOrthoMatrixBuffer m_auxOrthoMatrices;
CTextMessages m_TextMessages;
SAuxGeomRenderFlags m_curRenderFlags;
int m_curTransMatIdx;
uint m_uCount;
bool m_isUsed;
};
public:
// c/dtor
CAuxGeomCB(IRenderAuxGeomImpl* pRenderAuxGeom);
virtual ~CAuxGeomCB();
// get methods for private flags
static EPrimType GetPrimType(const SAuxGeomRenderFlags& renderFlags);
static bool IsThickLine(const SAuxGeomRenderFlags& renderFlags);
static EAuxDrawObjType GetAuxObjType(const SAuxGeomRenderFlags& renderFlags);
static uint8 GetPointSize(const SAuxGeomRenderFlags& renderFlags);
// memory usage
void GetMemoryUsage(ICrySizer* pSizer) const
{
pSizer->Add(*this);
for (CBList::const_iterator it = m_cbData.begin(); it != m_cbData.end(); ++it)
{
(*it)->GetMemoryUsage(pSizer);
}
}
void FreeMemory()
{
for (CBList::iterator it = m_cbData.begin(); it != m_cbData.end(); ++it)
{
stl::reconstruct(**it);
}
}
// setting orthogonal projection
void SetOrthoMode(bool enable, Matrix44A* pMatrix = 0)
{
if (enable)
{
assert(pMatrix);
m_cbCurrent->m_curTransMatIdx = m_cbCurrent->m_auxOrthoMatrices.size();
m_cbCurrent->m_auxOrthoMatrices.push_back(*pMatrix);
}
else
{
m_cbCurrent->m_curTransMatIdx = -1;
}
}
private:
enum EAuxGeomPrivateRenderflagBitMasks
{
// public field starts at bit 22
e_PrimTypeShift = 19,
e_PrimTypeMask = 0x7 << e_PrimTypeShift,
e_PrivateRenderflagsMask = (1 << 19) - 1
};
enum EAuxGeomPrivateRenderflags
{
// for non-indexed triangles
e_TriListParam_ProcessThickLines = 0x00000001,
// for triangles
// for lines
// for points
// for objects
};
private:
uint32 CreatePointRenderFlags(uint8 size);
uint32 CreateLineRenderFlags(bool indexed);
uint32 CreateTriangleRenderFlags(bool indexed);
uint32 CreateObjectRenderFlags(const EAuxDrawObjType& objType);
void DrawThickLine(const Vec3& v0, const ColorB& colV0, const Vec3& v1, const ColorB& colV1, float thickness);
void AddPushBufferEntry(uint32 numVertices, uint32 numIndices, const SAuxGeomRenderFlags& renderFlags);
void AddPrimitive(SAuxVertex*& pVertices, uint32 numVertices, const SAuxGeomRenderFlags& renderFlags);
void AddIndexedPrimitive(SAuxVertex*& pVertices, uint32 numVertices, vtx_idx*& pIndices, uint32 numIndices, const SAuxGeomRenderFlags& renderFlags);
void AddObject(SAuxDrawObjParams*& pDrawParams, const SAuxGeomRenderFlags& renderFlags);
protected:
size_t GetLastFlushPos() const
{
return m_lastFlushPos;
}
size_t GetCurFlushPos() const
{
return m_cbCurrent->m_auxPushBuffer.size();
}
void UpdateLastFlushPos();
int GetTransMatrixIndex() const
{
return m_cbCurrent->m_curTransMatIdx;
}
SAuxGeomCBRawData* AccessData()
{
return m_cbCurrent;
}
protected:
struct PushBufferSortFunc
{
bool operator() (const SAuxPushBufferEntry* lhs, const SAuxPushBufferEntry* rhs) const
{
if (lhs->m_renderFlags.m_renderFlags != rhs->m_renderFlags.m_renderFlags)
{
return lhs->m_renderFlags.m_renderFlags < rhs->m_renderFlags.m_renderFlags;
}
return lhs->m_transMatrixIdx < rhs->m_transMatrixIdx;
}
};
IRenderAuxGeomImpl* m_pRenderAuxGeom;
size_t m_lastFlushPos;
typedef std::list<SAuxGeomCBRawData*> CBList;
CBList m_cbData;
SAuxGeomCBRawData* m_cbCurrent;
SAuxGeomCBRawData* AddCBuffer()
{
SAuxGeomCBRawData* ptr = new SAuxGeomCBRawData;
m_cbData.push_back(ptr);
return ptr;
}
};
class CAuxGeomCBMainThread
: public CAuxGeomCB
{
public:
// Triple-buffered including base class's m_cbCurrent
static const int c_numCBReadyBuffers = 2;
CAuxGeomCBMainThread(IRenderAuxGeomImpl* pRenderAuxGeom)
: CAuxGeomCB(pRenderAuxGeom)
{
for (int i = 0; i < c_numCBReadyBuffers; ++i)
{
m_CBReady[i] = AddCBuffer();
}
}
virtual void Commit(uint frames = 0);
virtual void Process();
protected:
SAuxGeomCBRawData* volatile m_CBReady[c_numCBReadyBuffers];
unsigned char m_currentReadyBuffer = 0;
};
class CAuxGeomCBWorkerThread
: public CAuxGeomCB
{
SAuxGeomCBRawData* m_cbProcessed = nullptr;
SAuxGeomCBRawData* volatile m_CBReady = nullptr;
public:
CAuxGeomCBWorkerThread(IRenderAuxGeomImpl* pRenderAuxGeom)
: CAuxGeomCB(pRenderAuxGeom)
, m_cbProcessed(0) {}
virtual void Flush();
virtual void Commit(uint frames = 0);
virtual void Process();
};
// package CAuxGeomCB::SAuxGeomCBRawData ptr via seperate struct as nested types cannot be forward declared
struct SAuxGeomCBRawDataPackaged
{
SAuxGeomCBRawDataPackaged(CAuxGeomCB::SAuxGeomCBRawData* pData)
: m_pData(pData)
{
assert(m_pData);
}
CAuxGeomCB::SAuxGeomCBRawData* m_pData;
};
inline uint32 CAuxGeomCB::CreatePointRenderFlags(uint8 size)
{
return(m_cbCurrent->m_curRenderFlags.m_renderFlags | (e_PtList << e_PrimTypeShift) | size);
}
inline uint32 CAuxGeomCB::CreateLineRenderFlags(bool indexed)
{
if (false != indexed)
{
return(m_cbCurrent->m_curRenderFlags.m_renderFlags | (e_LineListInd << e_PrimTypeShift));
}
else
{
return(m_cbCurrent->m_curRenderFlags.m_renderFlags | (e_LineList << e_PrimTypeShift));
}
}
inline uint32 CAuxGeomCB::CreateTriangleRenderFlags(bool indexed)
{
if (false != indexed)
{
return(m_cbCurrent->m_curRenderFlags.m_renderFlags | (e_TriListInd << e_PrimTypeShift));
}
else
{
return(m_cbCurrent->m_curRenderFlags.m_renderFlags | (e_TriList << e_PrimTypeShift));
}
}
inline uint32 CAuxGeomCB::CreateObjectRenderFlags(const EAuxDrawObjType& objType)
{
return(m_cbCurrent->m_curRenderFlags.m_renderFlags | (e_Obj << e_PrimTypeShift) | objType);
}
inline CAuxGeomCB::EPrimType CAuxGeomCB::GetPrimType(const SAuxGeomRenderFlags& renderFlags)
{
uint32 primType((renderFlags.m_renderFlags & e_PrimTypeMask) >> e_PrimTypeShift);
switch (primType)
{
case e_PtList:
{
return(e_PtList);
}
case e_LineList:
{
return(e_LineList);
}
case e_LineListInd:
{
return(e_LineListInd);
}
case e_TriList:
{
return(e_TriList);
}
case e_TriListInd:
{
return(e_TriListInd);
}
case e_Obj:
default:
{
assert(e_Obj == primType);
return(e_Obj);
}
}
}
inline bool CAuxGeomCB::IsThickLine(const SAuxGeomRenderFlags& renderFlags)
{
EPrimType primType(GetPrimType(renderFlags));
assert(e_TriList == primType);
if (e_TriList == primType)
{
return(0 != (renderFlags.m_renderFlags & e_TriListParam_ProcessThickLines));
}
else
{
return(false);
}
}
inline CAuxGeomCB::EAuxDrawObjType CAuxGeomCB::GetAuxObjType(const SAuxGeomRenderFlags& renderFlags)
{
EPrimType primType(GetPrimType(renderFlags));
assert(e_Obj == primType);
uint32 objType((renderFlags.m_renderFlags & e_PrivateRenderflagsMask));
switch (objType)
{
case eDOT_Sphere:
default:
{
assert(eDOT_Sphere == objType);
return(eDOT_Sphere);
}
case eDOT_Disk:
{
assert(eDOT_Disk == objType);
return(eDOT_Disk);
}
case eDOT_Quad:
{
assert(eDOT_Quad == objType);
return(eDOT_Quad);
}
case eDOT_Cone:
{
assert(eDOT_Cone == objType);
return(eDOT_Cone);
}
case eDOT_Cylinder:
{
assert(eDOT_Cylinder == objType);
return(eDOT_Cylinder);
}
}
}
inline uint8 CAuxGeomCB::GetPointSize(const SAuxGeomRenderFlags& renderFlags)
{
EPrimType primType(GetPrimType(renderFlags));
assert(e_PtList == primType);
if (e_PtList == primType)
{
return(renderFlags.m_renderFlags & e_PrivateRenderflagsMask);
}
else
{
return(0);
}
}
#endif // #if defined(ENABLE_RENDER_AUX_GEOM)
class CAuxGeomCB_Null
: public IRenderAuxGeom
{
public:
// interface
virtual void SetRenderFlags([[maybe_unused]] const SAuxGeomRenderFlags& renderFlags) {}
virtual SAuxGeomRenderFlags GetRenderFlags() {return SAuxGeomRenderFlags(); }
virtual void DrawPoint([[maybe_unused]] const Vec3& v, [[maybe_unused]] const ColorB& col, [[maybe_unused]] uint8 size = 1) {}
virtual void DrawPoints([[maybe_unused]] const Vec3* v, [[maybe_unused]] uint32 numPoints, [[maybe_unused]] const ColorB& col, [[maybe_unused]] uint8 size = 1) {}
virtual void DrawPoints([[maybe_unused]] const Vec3* v, [[maybe_unused]] uint32 numPoints, [[maybe_unused]] const ColorB* col, [[maybe_unused]] uint8 size = 1) {}
virtual void DrawLine([[maybe_unused]] const Vec3& v0, [[maybe_unused]] const ColorB& colV0, [[maybe_unused]] const Vec3& v1, [[maybe_unused]] const ColorB& colV1, [[maybe_unused]] float thickness = 1.0f) {}
virtual void DrawLines([[maybe_unused]] const Vec3* v, [[maybe_unused]] uint32 numPoints, [[maybe_unused]] const ColorB& col, [[maybe_unused]] float thickness = 1.0f) {}
virtual void DrawLines([[maybe_unused]] const Vec3* v, [[maybe_unused]] uint32 numPoints, [[maybe_unused]] const ColorB* col, [[maybe_unused]] float thickness = 1.0f) {}
virtual void DrawLines([[maybe_unused]] const Vec3* v, [[maybe_unused]] uint32 numPoints, [[maybe_unused]] const vtx_idx* ind, [[maybe_unused]] uint32 numIndices, [[maybe_unused]] const ColorB& col, [[maybe_unused]] float thickness = 1.0f) {}
virtual void DrawLines([[maybe_unused]] const Vec3* v, [[maybe_unused]] uint32 numPoints, [[maybe_unused]] const vtx_idx* ind, [[maybe_unused]] uint32 numIndices, [[maybe_unused]] const ColorB* col, [[maybe_unused]] float thickness = 1.0f) {}
virtual void DrawPolyline([[maybe_unused]] const Vec3* v, [[maybe_unused]] uint32 numPoints, [[maybe_unused]] bool closed, [[maybe_unused]] const ColorB& col, [[maybe_unused]] float thickness = 1.0f) {}
virtual void DrawPolyline([[maybe_unused]] const Vec3* v, [[maybe_unused]] uint32 numPoints, [[maybe_unused]] bool closed, [[maybe_unused]] const ColorB* col, [[maybe_unused]] float thickness = 1.0f) {}
virtual void DrawTriangle([[maybe_unused]] const Vec3& v0, [[maybe_unused]] const ColorB& colV0, [[maybe_unused]] const Vec3& v1, [[maybe_unused]] const ColorB& colV1, [[maybe_unused]] const Vec3& v2, [[maybe_unused]] const ColorB& colV2) {}
virtual void DrawTriangles([[maybe_unused]] const Vec3* v, [[maybe_unused]] uint32 numPoints, [[maybe_unused]] const ColorB& col) {}
virtual void DrawTriangles([[maybe_unused]] const Vec3* v, [[maybe_unused]] uint32 numPoints, [[maybe_unused]] const ColorB* col) {}
virtual void DrawTriangles([[maybe_unused]] const Vec3* v, [[maybe_unused]] uint32 numPoints, [[maybe_unused]] const vtx_idx* ind, [[maybe_unused]] uint32 numIndices, [[maybe_unused]] const ColorB& col) {}
virtual void DrawTriangles([[maybe_unused]] const Vec3* v, [[maybe_unused]] uint32 numPoints, [[maybe_unused]] const vtx_idx* ind, [[maybe_unused]] uint32 numIndices, [[maybe_unused]] const ColorB* col) {}
virtual void DrawQuad([[maybe_unused]] float width, [[maybe_unused]] float height, [[maybe_unused]] const Matrix34& matWorld, [[maybe_unused]] const ColorB& col, [[maybe_unused]] bool drawShaded = true) {}
virtual void DrawAABB([[maybe_unused]] const AABB& aabb, [[maybe_unused]] bool bSolid, [[maybe_unused]] const ColorB& col, [[maybe_unused]] const EBoundingBoxDrawStyle& bbDrawStyle) {}
virtual void DrawAABBs([[maybe_unused]] const AABB* aabbs, [[maybe_unused]] uint32 aabbCount, [[maybe_unused]] bool bSolid, [[maybe_unused]] const ColorB& col, [[maybe_unused]] const EBoundingBoxDrawStyle& bbDrawStyle) {}
virtual void DrawAABB([[maybe_unused]] const AABB& aabb, [[maybe_unused]] const Matrix34& matWorld, [[maybe_unused]] bool bSolid, [[maybe_unused]] const ColorB& col, [[maybe_unused]] const EBoundingBoxDrawStyle& bbDrawStyle) {}
virtual void DrawOBB([[maybe_unused]] const OBB& obb, [[maybe_unused]] const Vec3& pos, [[maybe_unused]] bool bSolid, [[maybe_unused]] const ColorB& col, [[maybe_unused]] const EBoundingBoxDrawStyle& bbDrawStyle) {}
virtual void DrawOBB([[maybe_unused]] const OBB& obb, [[maybe_unused]] const Matrix34& matWorld, [[maybe_unused]] bool bSolid, [[maybe_unused]] const ColorB& col, [[maybe_unused]] const EBoundingBoxDrawStyle& bbDrawStyle) {}
virtual void DrawSphere([[maybe_unused]] const Vec3& pos, [[maybe_unused]] float radius, [[maybe_unused]] const ColorB& col, [[maybe_unused]] bool drawShaded = true) {}
virtual void DrawDisk([[maybe_unused]] const Vec3& pos, [[maybe_unused]] const Vec3& dir, [[maybe_unused]] float radius, [[maybe_unused]] const ColorB& col, [[maybe_unused]] bool drawShaded = true) {}
virtual void DrawCone([[maybe_unused]] const Vec3& pos, [[maybe_unused]] const Vec3& dir, [[maybe_unused]] float radius, [[maybe_unused]] float height, [[maybe_unused]] const ColorB& col, [[maybe_unused]] bool drawShaded = true) {}
virtual void DrawCylinder([[maybe_unused]] const Vec3& pos, [[maybe_unused]] const Vec3& dir, [[maybe_unused]] float radius, [[maybe_unused]] float height, [[maybe_unused]] const ColorB& col, [[maybe_unused]] bool drawShaded = true) {}
virtual void DrawBone([[maybe_unused]] const Vec3& rParent, [[maybe_unused]] const Vec3& rBone, [[maybe_unused]] ColorB col) {}
virtual void RenderText([[maybe_unused]] Vec3 pos, [[maybe_unused]] SDrawTextInfo& ti, [[maybe_unused]] const char* format, [[maybe_unused]] va_list args) {}
virtual void Flush() {}
virtual void Commit([[maybe_unused]] uint frames = 0) {}
virtual void Process() {}
public:
CAuxGeomCB_Null() {}
~CAuxGeomCB_Null() {}
};
#endif // #ifndef _RENDERAUXGEOM_H_
@@ -0,0 +1,86 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#ifndef CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDERCAPABILITIES_H
#define CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDERCAPABILITIES_H
#pragma once
#include <XRenderD3D9/DeviceManager/Enums.h>
#include <AzCore/std/containers/bitset.h>
namespace RenderCapabilities
{
// GPU Vendor ID list
static const unsigned int s_gpuVendorIdNVIDIA = 0x10de;
static const unsigned int s_gpuVendorIdAMD = 0x1002;
static const unsigned int s_gpuVendorIdIntel = 0x8086;
static const unsigned int s_gpuVendorIdQualcomm = 0x5143;
static const unsigned int s_gpuVendorIdSamsung = 0x1099;
static const unsigned int s_gpuVendorIdARM = 0x13B5;
//Note that for platforms that don't support texture views, you are still allowed to create a single view, that view must "match" the creation parameters of
//the texture.
bool SupportsTextureViews();
// Test to determine if stencil textures are supported
bool SupportsStencilTextures();
#if defined(OPENGL_ES) || defined(CRY_USE_METAL)
// Test to determine how much MRT bpp is available. (-1 means no restriction)
int GetAvailableMRTbpp();
// Tests to see if GMEM 128bpp path is supported.
bool Supports128bppGmemPath();
// Tests to see if GMEM 256bpp path is supported.
bool Supports256bppGmemPath();
// Tests to see if the device can support enough renderTargets.
bool SupportsRenderTargets(int numRTs);
#endif
#if defined(OPENGL_ES)
bool SupportsHalfFloatRendering();
#endif
#if defined(OPENGL_ES) || defined(OPENGL)
uint32 GetDeviceGLVersion();
#endif
//Check if Depth clipping API is enabled
bool SupportsDepthClipping();
// Flags for Frame Buffer Fetch capabilities
enum
{
FBF_ALL_COLORS = 0,// Can fetch from any color render target that is bound.
FBF_COLOR0, // Some devices only allows fetching from the first color render target.
FBF_DEPTH, // Can fetch the depth value from the attached buffer.
FBF_STENCIL, // Can fetch the stencil value from the attached buffer.
FBF_COUNT
};
using FrameBufferFetchMask = AZStd::bitset<FBF_COUNT>;
FrameBufferFetchMask GetFrameBufferFetchCapabilities();
// Extracting this out as to not pollute rest of code base with a bunch of "if defined(OPENGL_ES)"
bool SupportsPLSExtension();
bool SupportsDualSourceBlending();
bool SupportsStructuredBuffer(EShaderStage stage);
bool SupportsIndependentBlending();
}
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDERCAPABILITIES_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,613 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef __RENDERMESH_H__
#define __RENDERMESH_H__
#include <intrusive_list.hpp>
#include <CryPool/PoolAlloc.h>
#include <VectorMap.h>
#include <VectorSet.h>
#include <GeomQuery.h>
#include "Shaders/Vertex.h"
#include <AzCore/Jobs/LegacyJobExecutor.h>
// Enable the below to get fatal error is some holds a rendermesh buffer lock for longer than 1 second
//#define RM_CATCH_EXCESSIVE_LOCKS
#define DELETE_SUBSET_MESHES_AFTER_NOTUSED_FRAMES 30
struct SMeshSubSetIndicesJobEntry
{
AZ::LegacyJobExecutor jobExecutor;
_smart_ptr<IRenderMesh> m_pSrcRM; // source mesh to create a new index mesh from
_smart_ptr<IRenderMesh> m_pIndexRM; // when finished: newly created index mesh for this mask, else NULL
uint64 m_nMeshSubSetMask; // mask to use
void CreateSubSetRenderMesh();
};
class RenderMesh_hash_int32
{
public:
ILINE size_t operator()(int32 key) const
{
return stl::hash_uint32()((uint32)key);
}
};
struct SBufInfoTable
{
int OffsTC;
int OffsColor;
int OffsNorm;
};
struct SMeshStream
{
buffer_handle_t m_nID; // device buffer handle from device buffer manager
void* m_pUpdateData; // system buffer for updating (used for async. mesh updates)
void* m_pLockedData; // locked device buffer data (hmm, not a good idea to store)
uint32 m_nLockFlags : 16;
uint32 m_nLockCount : 16;
uint32 m_nElements;
int32 m_nFrameAccess;
int32 m_nFrameRequest;
int32 m_nFrameUpdate;
int32 m_nFrameCreate;
SMeshStream()
{
m_nID = ~0u;
m_pUpdateData = NULL;
m_pLockedData = NULL;
m_nFrameRequest = 0;
m_nFrameUpdate = -1;
m_nFrameAccess = -1;
m_nFrameCreate = -1;
m_nLockFlags = 0;
m_nLockCount = 0;
m_nElements = 0;
}
~SMeshStream() { memset(this, 0x0, sizeof(*this)); }
};
// CRenderMesh::m_nFlags
#define FRM_RELEASED 1
#define FRM_DEPRECTATED_FLAG 2
#define FRM_READYTOUPLOAD 4
#define FRM_ALLOCFAILURE 8
#define FRM_SKINNED 0x10
#define FRM_SKINNEDNEXTDRAW 0x20 // no proper support yet for objects that can be skinned and not skinned.
#define FRM_ENABLE_NORMALSTREAM 0x40
#define MAX_RELEASED_MESH_FRAMES (2)
struct SSetMeshIntData
{
CMesh* m_pMesh;
char* m_pVBuff;
SPipTangents* m_pTBuff;
SPipQTangents* m_pQTBuff;
SVF_P3F* m_pVelocities;
uint32 m_nVerts;
uint32 m_nInds;
vtx_idx* m_pInds;
uint32 m_flags;
Vec3* m_pNormalsBuff;
};
class CRenderMesh
: public IRenderMesh
{
friend class CREMeshImpl;
public:
static void ClearJobResources();
private:
friend class CD3D9Renderer;
SMeshStream m_IBStream;
SMeshStream* m_VBStream[VSF_NUM];
struct SBoneIndexStream
{
buffer_handle_t buffer;
uint32 guid;
uint32 refcount;
};
struct SBoneIndexStreamRequest
{
SBoneIndexStreamRequest(uint32 _guid, SVF_W4B_I4S* _pStream)
: pStream(_pStream)
, guid(_guid)
, refcount(1) {}
SVF_W4B_I4S* pStream;
uint32 guid;
uint32 refcount;
};
std::vector<SBoneIndexStream> m_RemappedBoneIndices;
std::vector< SBoneIndexStreamRequest > m_CreatedBoneIndices[2];
std::vector< uint32 > m_DeletedBoneIndices[2];
uint32 m_nInds;
uint32 m_nVerts;
int m_nRefCounter;
AZ::Vertex::Format m_vertexFormat; // Base stream vertex format (optional streams are hardcoded: VSF_)
Vec3* m_pCachePos; // float positions (cached)
int m_nFrameRequestCachePos;
std::vector<Vec2*> m_UVCache; // float UVs (cached)
int m_nFrameRequestCacheUVs;
CRenderMesh* m_pVertexContainer;
PodArray<CRenderMesh*> m_lstVertexContainerUsers;
#ifdef RENDER_MESH_TRIANGLE_HASH_MAP_SUPPORT
typedef AZStd::unordered_map<int, PodArray< std::pair<int, int> >, RenderMesh_hash_int32> TrisMap;
TrisMap* m_pTrisMap;
#endif
SRecursiveSpinLock m_sResLock;
AZStd::atomic<int> m_nThreadAccessCounter;// counter to ensure that no system rendermesh streams are freed since they are in use
volatile int m_asyncUpdateState[2];
int m_asyncUpdateStateCounter[2];
eRenderPrimitiveType m_nPrimetiveType : 8;
ERenderMeshType m_eType : 4;
uint16 m_nFlags : 8; // FRM_
int16 m_nLod : 4; // used for LOD debug visualization
bool m_keepSysMesh : 1;
bool m_nFlagsCachePos : 1; // only checked for FSL_WRITE, which can be represented as a single bit
bool m_nFlagsCacheUVs : 1;
public:
enum ESizeUsageArg
{
SIZE_ONLY_SYSTEM = 0,
SIZE_VB = 1,
SIZE_IB = 2,
};
private:
SMeshStream* GetVertexStream(int nStream, uint32 nFlags = 0);
SMeshStream* GetVertexStream(int nStream, [[maybe_unused]] uint32 nFlags = 0) const { return m_VBStream[nStream]; }
bool UpdateVidIndices(SMeshStream& IBStream, bool stall = true);
bool CreateVidVertices(int nStream = VSF_GENERAL);
bool UpdateVidVertices(int nStream, bool stall = true);
bool CopyStreamToSystemForUpdate(SMeshStream& MS, size_t nSize);
void ReleaseVB(int nStream);
void ReleaseIB();
void InitTriHash(_smart_ptr<IMaterial> pMaterial);
bool CreateCachePos(byte* pSrc, uint32 nStrideSrc, uint32 nFlags);
bool PrepareCachePos();
bool CreateUVCache(byte* pSrc, uint32 nStrideSrc, uint32 nFlags, uint32 uvSetIndex);
//Internal versions of funcs - no lock
bool UpdateVertices_Int(const void* pVertBuffer, int nVertCount, int nOffset, int nStream, uint32 copyFlags);
bool UpdateIndices_Int(const vtx_idx* pNewInds, int nInds, int nOffsInd, uint32 copyFlags);
size_t SetMesh_Int(CMesh& mesh, int nSecColorsSetOffset, uint32 flags);
#ifdef MESH_TESSELLATION_RENDERER
template<class VecPos, class VecUV>
bool UpdateUVCoordsAdjacency(SMeshStream& IBStream, const AZ::Vertex::Format& vertexFormat);
template<class VecPos, class VecUV>
static void BuildAdjacency(const byte* pVerts, const AZ::Vertex::Format& vertexFormat, uint nVerts, const vtx_idx* pIndexBuffer, uint nTrgs, std::vector<VecUV>& pTxtAdjBuffer);
#endif
void Cleanup();
public:
void AddShadowPassMergedChunkIndicesAndVertices(CRenderChunk* pCurrentChunk, _smart_ptr<IMaterial> pMaterial, int& rNumVertices, int& rNumIndices);
static bool RenderChunkMergeAbleInShadowPass(CRenderChunk* pPreviousChunk, CRenderChunk* pCurrentChunk, _smart_ptr<IMaterial> pMaterial);
inline void PrefetchVertexStreams() const
{
for (int i = 0; i < VSF_NUM; CryPrefetch(m_VBStream[i++]))
{
;
}
}
void SetMesh_IntImpl(SSetMeshIntData data);
//! constructor
//! /param szSource this pointer is stored - make sure the memory stays
CRenderMesh(const char* szType, const char* szSourceName, bool bLock = false);
CRenderMesh();
//! destructor
~CRenderMesh();
virtual bool CanRender(){return (m_nFlags & FRM_ALLOCFAILURE) == 0; }
virtual void AddRef()
{
# if !defined(_RELEASE)
if (m_nFlags & FRM_RELEASED)
{
CryFatalError("CRenderMesh::AddRef() mesh already in the garbage list (resurrecting deleted mesh)");
}
# endif
CryInterlockedIncrement(&m_nRefCounter);
}
virtual int Release();
void ReleaseForce()
{
while (true)
{
int nRef = Release();
if (nRef <= 0)
{
return;
}
}
}
// ----------------------------------------------------------------
// Helper functions
_inline int GetStreamStride(int nStream) const override
{
if (nStream == VSF_GENERAL)
{
return m_vertexFormat.GetStride();
}
else
{
return m_cSizeStream[nStream];
}
}
_inline uint32 _GetFlags() const { return m_nFlags; }
_inline int GetStreamSize(int nStream, int nVerts = 0) const { return GetStreamStride(nStream) * (nVerts ? nVerts : m_nVerts); }
_inline const buffer_handle_t GetVBStream(int nStream) const
{
if (!m_VBStream[nStream])
{
return ~0u;
}
return m_VBStream[nStream]->m_nID;
}
_inline const buffer_handle_t GetIBStream() const { return m_IBStream.m_nID; }
_inline bool _HasVBStream(int nStream) const { return m_VBStream[nStream] && m_VBStream[nStream]->m_nID != ~0u; }
_inline bool _HasIBStream() const { return m_IBStream.m_nID != ~0u; }
_inline int _IsVBStreamLocked(int nStream) const
{
if (!m_VBStream[nStream])
{
return 0;
}
return (m_VBStream[nStream]->m_nLockFlags & FSL_LOCKED);
}
_inline int _IsIBStreamLocked() const { return m_IBStream.m_nLockFlags & FSL_LOCKED; }
_inline AZ::Vertex::Format _GetVertexFormat() const { return m_vertexFormat; }
_inline void _SetVertexFormat(const AZ::Vertex::Format& vertexFormat) { m_vertexFormat = vertexFormat; }
_inline int GetNumVerts() const override { return m_nVerts; }
_inline void _SetNumVerts(int nVerts) { m_nVerts = max(nVerts, 0); }
_inline int GetNumInds() const override { return m_nInds; }
_inline void _SetNumInds(int nInds) { m_nInds = nInds; }
_inline const eRenderPrimitiveType GetPrimitiveType() const override { return m_nPrimetiveType; }
_inline void _SetPrimitiveType(const eRenderPrimitiveType nPrimType) { m_nPrimetiveType = nPrimType; }
_inline void _SetRenderMeshType(ERenderMeshType eType) { m_eType = eType; }
_inline CRenderMesh* _GetVertexContainer()
{
if (m_pVertexContainer)
{
return m_pVertexContainer;
}
return this;
}
# if !defined(NULL_RENDERER)
D3DBuffer* _GetD3DVB(int nStream, size_t* offs) const;
D3DBuffer* _GetD3DIB(size_t* offs) const;
# endif
size_t Size(uint32 nFlags) const;
void Size(uint32 nFlags, ICrySizer* pSizer) const;
void* LockVB(int nStream, uint32 nFlags, int nVerts = 0, int* nStride = NULL, bool prefetchIB = false, bool inplaceCachePos = false);
template<class T>
T* GetStridedArray(strided_pointer<T>& arr, EStreamIDs stream)
{
arr.data = (T*)LockVB(stream, FSL_READ, 0, &arr.iStride);
assert(!arr.data || arr.iStride >= sizeof(T));
return arr.data;
}
vtx_idx* LockIB(uint32 nFlags, int nOffset = 0, int nInds = 0);
void UnlockVB(int nStream);
void UnlockIB();
bool RT_CheckUpdate(CRenderMesh* pVContainer, uint32 nStreamMask, bool bTessellation = false, bool stall = true);
void RT_SetMeshCleanup();
void RT_AllocationFailure(const char* sPurpose, uint32 nSize);
bool CheckUpdate(uint32 nStreamMask) override;
void AssignChunk(CRenderChunk * pChunk, class CREMeshImpl * pRE);
void InitRenderChunk(CRenderChunk& rChunk);
void FreeVB(int nStream);
void FreeIB();
void FreeDeviceBuffers(bool bRestoreSys);
void FreeSystemBuffers();
void FreePreallocatedData();
bool SyncAsyncUpdate(int threadId, bool block = true);
//===========================================================================================
// IRenderMesh interface
virtual const char* GetTypeName() { return m_sType; }
virtual const char* GetSourceName() const { return m_sSource; }
virtual int GetIndicesCount() { return m_nInds; }
virtual int GetVerticesCount() { return m_nVerts; }
virtual AZ::Vertex::Format GetVertexFormat() { return m_vertexFormat; }
virtual ERenderMeshType GetMeshType() { return m_eType; }
virtual void SetSkinned(bool bSkinned = true) override
{
if (bSkinned)
{
m_nFlags |= FRM_SKINNED;
}
else
{
m_nFlags &= ~FRM_SKINNED;
}
};
virtual uint GetSkinningWeightCount() const override;
virtual float GetGeometricMeanFaceArea() const{ return m_fGeometricMeanFaceArea; }
virtual void NextDrawSkinned() { m_nFlags |= FRM_SKINNEDNEXTDRAW; }
virtual void GenerateQTangents();
virtual void CreateChunksSkinned();
virtual void CopyTo(IRenderMesh* pDst, int nAppendVtx = 0, bool bDynamic = false, bool fullCopy = true);
virtual void SetSkinningDataVegetation(struct SMeshBoneMapping_uint8* pBoneMapping);
virtual void SetSkinningDataCharacter(CMesh& mesh, struct SMeshBoneMapping_uint16* pBoneMapping, struct SMeshBoneMapping_uint16* pExtraBoneMapping);
// Creates an indexed mesh from this render mesh (accepts an optional pointer to an IIndexedMesh object that should be used)
virtual IIndexedMesh* GetIndexedMesh(IIndexedMesh* pIdxMesh = 0);
virtual int GetRenderChunksCount(_smart_ptr<IMaterial> pMat, int& nRenderTrisCount);
virtual IRenderMesh* GenerateMorphWeights() { return NULL; }
virtual IRenderMesh* GetMorphBuddy() { return NULL; }
virtual void SetMorphBuddy([[maybe_unused]] IRenderMesh* pMorph) {}
// Create render buffers from render mesh. Returns the final size of the render mesh or ~0U on failure
virtual size_t SetMesh(CMesh& mesh, int nSecColorsSetOffset, uint32 flags, bool requiresLock);
// Update system vertices buffer
virtual bool UpdateVertices(const void* pVertBuffer, int nVertCount, int nOffset, int nStream, uint32 copyFlags, bool requiresLock = true);
// Update system indices buffer
virtual bool UpdateIndices(const vtx_idx* pNewInds, int nInds, int nOffsInd, uint32 copyFlags, bool requiresLock = true);
virtual void SetCustomTexID(int nCustomTID);
virtual void SetChunk(int nIndex, CRenderChunk& chunk);
virtual void SetChunk(_smart_ptr<IMaterial> pNewMat, int nFirstVertId, int nVertCount, int nFirstIndexId, int nIndexCount, float texelAreaDensity, const AZ::Vertex::Format& vertexFormat, int nMatID = 0);
virtual void SetRenderChunks(CRenderChunk* pChunksArray, int nCount, bool bSubObjectChunks);
virtual TRenderChunkArray& GetChunks() { return m_Chunks; }
virtual TRenderChunkArray& GetChunksSkinned() { return m_ChunksSkinned; }
virtual TRenderChunkArray& GetChunksSubObjects() { return m_ChunksSubObjects; }
virtual IRenderMesh* GetVertexContainer() { return _GetVertexContainer(); }
virtual void SetVertexContainer(IRenderMesh* pBuf);
virtual void Render(const struct SRendParams& rParams, CRenderObject* pObj, _smart_ptr<IMaterial> pMaterial, const SRenderingPassInfo& passInfo, bool bSkinned = false);
virtual void Render(CRenderObject* pObj, const SRenderingPassInfo& passInfo, const SRendItemSorter& rendItemSorter);
virtual void AddRenderElements(_smart_ptr<IMaterial> pIMatInfo, CRenderObject* pObj, const SRenderingPassInfo& passInfo, int nSortId = EFSLIST_GENERAL, int nAW = 1);
virtual void SetREUserData(float* pfCustomData, float fFogScale = 0, float fAlpha = 1);
virtual void AddRE(_smart_ptr<IMaterial> pMaterial, CRenderObject* pObj, IShader* pEf, const SRenderingPassInfo& passInfo, int nList, int nAW, const SRendItemSorter& rendItemSorter);
virtual void DrawImmediately();
virtual byte* GetPosPtrNoCache(int32& nStride, uint32 nFlags);
virtual byte* GetPosPtr(int32& nStride, uint32 nFlags);
virtual byte* GetNormPtr(int32& nStride, uint32 nFlags);
virtual byte* GetColorPtr(int32& nStride, uint32 nFlags);
virtual byte* GetUVPtrNoCache(int32& nStride, uint32 nFlags, uint32 uvSetIndex = 0);
virtual byte* GetUVPtr(int32& nStride, uint32 nFlags, uint32 uvSetIndex = 0);
virtual byte* GetTangentPtr(int32& nStride, uint32 nFlags);
virtual byte* GetQTangentPtr(int32& nStride, uint32 nFlags);
virtual byte* GetHWSkinPtr(int32& nStride, uint32 nFlags, bool remapped = false);
virtual byte* GetVelocityPtr(int32& nStride, uint32 nFlags);
virtual void UnlockStream(int nStream);
virtual void UnlockIndexStream();
virtual vtx_idx* GetIndexPtr(uint32 nFlags, int32 nOffset = 0);
virtual const PodArray<std::pair<int, int> >* GetTrisForPosition(const Vec3& vPos, _smart_ptr<IMaterial> pMaterial);
virtual float GetExtent(EGeomForm eForm);
virtual void GetRandomPos(PosNorm& ran, EGeomForm eForm, SSkinningData const* pSkinning = NULL);
virtual uint32* GetPhysVertexMap() { return NULL; }
virtual bool IsEmpty();
virtual size_t GetMemoryUsage(ICrySizer* pSizer, EMemoryUsageArgument nType) const;
virtual void GetMemoryUsage(ICrySizer* pSizer) const;
virtual float GetAverageTrisNumPerChunk(_smart_ptr<IMaterial> pMat);
virtual int GetTextureMemoryUsage(const _smart_ptr<IMaterial> pMaterial, ICrySizer* pSizer = NULL, bool bStreamedIn = true) const;
// Get allocated only in video memory or only in system memory.
virtual int GetAllocatedBytes(bool bVideoMem) const;
virtual void SetBBox(const Vec3& vBoxMin, const Vec3& vBoxMax) { m_vBoxMin = vBoxMin; m_vBoxMax = vBoxMax; }
virtual void GetBBox(Vec3& vBoxMin, Vec3& vBoxMax) { vBoxMin = m_vBoxMin; vBoxMax = m_vBoxMax; };
virtual void UpdateBBoxFromMesh();
// Debug draw this render mesh.
virtual void DebugDraw(const struct SGeometryDebugDrawInfo& info, uint32 nVisibleChunksMask = ~0, float fExtrdueScale = 0.01f);
virtual void KeepSysMesh(bool keep);
virtual void UnKeepSysMesh();
virtual void LockForThreadAccess();
virtual void UnLockForThreadAccess();
virtual void SetMeshLod(int nLod) { m_nLod = nLod; }
virtual volatile int* SetAsyncUpdateState();
void CreateRemappedBoneIndicesPair(const uint pairGuid, const TRenderChunkArray& Chunks);
virtual void CreateRemappedBoneIndicesPair(const DynArray<JointIdType>& arrRemapTable, const uint pairGuid);
virtual void ReleaseRemappedBoneIndicesPair(const uint pairGuid);
virtual void OffsetPosition(const Vec3& delta) { m_vBoxMin += delta; m_vBoxMax += delta; }
IRenderMesh* GetRenderMeshForSubsetMask(SRenderObjData* pOD, uint64 nMeshSubSetMask, _smart_ptr<IMaterial> pMaterial, const SRenderingPassInfo& passInfo);
void GarbageCollectSubsetRenderMeshes();
void CreateSubSetRenderMesh();
void ReleaseRenderChunks(TRenderChunkArray* pChunks);
void BindStreamsToRenderPipeline();
bool GetRemappedSkinningData(uint32 guid, CRendElementBase::SGeometryStreamInfo &streamInfo);
bool FillGeometryInfo(CRendElementBase::SGeometryInfo &geomInfo);
// --------------------------------------------------------------
// Members
static int32 m_cSizeStream[VSF_NUM];
// When modifying or traversing any of the lists below, be sure to always hold the link lock
static CryCriticalSection m_sLinkLock;
// intrusive list entries - a mesh can be in multiple lists at the same time
util::list<CRenderMesh> m_Chain; // mesh will either be in the mesh list or garbage mesh list
util::list<CRenderMesh> m_Dirty[2]; // if linked, mesh has volatile data (data read back from vram)
util::list<CRenderMesh> m_Modified[2]; // if linked, mesh has modified data (to be uploaded to vram)
// The static list heads, corresponds to the entries above
static util::list<CRenderMesh> m_MeshList;
static util::list<CRenderMesh> m_MeshGarbageList[MAX_RELEASED_MESH_FRAMES];
static util::list<CRenderMesh> m_MeshDirtyList[2];
static util::list<CRenderMesh> m_MeshModifiedList[2];
TRenderChunkArray m_Chunks;
TRenderChunkArray m_ChunksSubObjects; // Chunks of sub-objects.
TRenderChunkArray m_ChunksSkinned;
int m_nClientTextureBindID;
Vec3 m_vBoxMin;
Vec3 m_vBoxMax;
float m_fGeometricMeanFaceArea;
CGeomExtents m_Extents;
// Frame id when this render mesh was last rendered.
uint32 m_nLastRenderFrameID;
uint32 m_nLastSubsetGCRenderFrameID;
string m_sType; //!< pointer to the type name in the constructor call
string m_sSource; //!< pointer to the source name in the constructor call
// For debugging purposes to catch longstanding data accesses
# if !defined(_RELEASE) && defined(RM_CATCH_EXCESSIVE_LOCKS)
AZStd::atomic<float> m_lockTime;
# endif
typedef VectorMap<uint64, _smart_ptr<IRenderMesh> > MeshSubSetIndices;
MeshSubSetIndices m_meshSubSetIndices;
static TSRC_ALIGN CThreadSafeRendererContainer<SMeshSubSetIndicesJobEntry> m_meshSubSetRenderMeshJobs[RT_COMMAND_BUF_COUNT];
static TSRC_ALIGN CThreadSafeRendererContainer<CRenderMesh*> m_deferredSubsetGarbageCollection[RT_COMMAND_BUF_COUNT];
#ifdef RENDER_MESH_TRIANGLE_HASH_MAP_SUPPORT
CryCriticalSection m_getTrisForPositionLock;
#endif
#if !defined(NULL_RENDERER)
WrappedDX11Buffer m_extraBonesBuffer;
#ifdef MESH_TESSELLATION_RENDERER
WrappedDX11Buffer m_adjBuffer; // buffer containing adjacency information to fix displacement seams
#endif
#endif
static void Initialize();
static void ShutDown();
static void Tick();
static void UpdateModified();
static void UpdateModifiedMeshes(bool bLocked, int threadId);
static bool ClearStaleMemory(bool bLocked, int threadId);
static void PrintMeshLeaks();
static void GetPoolStats(SMeshPoolStatistics* stats);
void* operator new(size_t size);
void operator delete(void* ptr);
static void FinalizeRendItems(int nThreadID);
};
//////////////////////////////////////////////////////////////////////
// General VertexBuffer created by CreateVertexBuffer() function
class CVertexBuffer
{
public:
CVertexBuffer()
{
m_nVerts = 0;
}
CVertexBuffer(void* pData, const AZ::Vertex::Format& vertexFormat, int nVerts = 0)
{
m_VS.m_pLocalData = pData;
m_vertexFormat = vertexFormat;
m_nVerts = nVerts;
}
#ifdef _RENDERER
~CVertexBuffer();
#endif
SBufferStream m_VS;
AZ::Vertex::Format m_vertexFormat;
int32 m_nVerts;
};
class CIndexBuffer
{
public:
CIndexBuffer()
{
m_nInds = 0;
}
CIndexBuffer(uint16* pData)
{
m_VS.m_pLocalData = pData;
m_nInds = 0;
}
#ifdef _RENDERER
~CIndexBuffer();
#endif
SBufferStream m_VS;
int32 m_nInds;
};
#endif // CRYINCLUDE_CRYENGINE_RENDERDLL_COMMON_RENDERMESH_H
@@ -0,0 +1,454 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include <AzCore/Debug/Profiler.h>
#include "RenderMesh.h"
#include "PostProcess/PostEffects.h"
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
namespace
{
inline uint32 GetCurrentRenderFrameID(const SRenderingPassInfo& passInfo)
{
return gRenDev->m_RP.m_TI[passInfo.ThreadID()].m_nFrameUpdateID;
};
}
///////////////////////////////////////////////////////////////////////////////
void CRenderMesh::Render(CRenderObject* pObj, const SRenderingPassInfo& passInfo, const SRendItemSorter& rendItemSorter)
{
_smart_ptr<IMaterial> pMaterial = pObj->m_pCurrMaterial;
if (!pMaterial || !m_nVerts || !m_nInds || m_Chunks.empty() || (m_nFlags & FRM_ALLOCFAILURE) != 0)
{
return;
}
FUNCTION_PROFILER_FAST(GetISystem(), PROFILE_RENDERER, g_bProfilerEnabled);
IF (!CanRender(), 0)
{
return;
}
CRenderer* __restrict rd = gRenDev;
bool bSkinned = (GetChunksSkinned().size() && (pObj->m_ObjFlags & (FOB_SKINNED)));
uint64 nMeshSubSetMask = 0;
#if !defined(_RELEASE)
const char* szExcl = CRenderer::CV_r_excludemesh->GetString();
if (szExcl[0] && m_sSource)
{
char szMesh[1024];
cry_strcpy(szMesh, this->m_sSource);
azstrlwr(szMesh, AZ_ARRAY_SIZE(szMesh));
if (szExcl[0] == '!')
{
if (!strstr(&szExcl[1], m_sSource))
{
return;
}
}
else
if (strstr(szExcl, m_sSource))
{
return;
}
}
#endif
if (rd->m_pDefaultMaterial && pMaterial)
{
pMaterial = rd->m_pDefaultMaterial;
}
assert(pMaterial);
if (!pMaterial)
{
return;
}
m_nLastRenderFrameID = GetCurrentRenderFrameID(passInfo);
//////////////////////////////////////////////////////////////////////////
if (!m_meshSubSetIndices.empty() && abs((int)m_nLastRenderFrameID - (int)m_nLastSubsetGCRenderFrameID) > DELETE_SUBSET_MESHES_AFTER_NOTUSED_FRAMES)
{
m_deferredSubsetGarbageCollection[passInfo.ThreadID()].push_back(this);
}
//////////////////////////////////////////////////////////////////////////
bool bRenderBreakableWithMultipleDrawCalls = false;
if (pObj->m_ObjFlags & FOB_MESH_SUBSET_INDICES && m_nVerts >= 3)
{
SRenderObjData* pOD = pObj->GetObjData();
if (pOD)
{
if (pOD->m_nSubObjHideMask != 0)
{
IRenderMesh* pRM = GetRenderMeshForSubsetMask(pOD, pOD->m_nSubObjHideMask, pMaterial, passInfo);
// if pRM is null, it means that this subset rendermesh is not computed yet, thus we render it with multiple draw calls
if (pRM)
{
static_cast<CRenderMesh*>(pRM)->CRenderMesh::Render(pObj, passInfo, rendItemSorter);
pOD->m_nSubObjHideMask = 0;
return;
}
// compute the needed mask
const uint32 ni = m_ChunksSubObjects.size();
nMeshSubSetMask = pOD->m_nSubObjHideMask & (((uint64)1 << ni) - 1);
pOD->m_nSubObjHideMask = 0;
bRenderBreakableWithMultipleDrawCalls = true;
}
}
}
int nList = EFSLIST_GENERAL;
const int nAW = (pObj->m_ObjFlags & FOB_AFTER_WATER) || (pObj->m_ObjFlags & FOB_NEAREST) ? 1 : 0;
//////////////
if (gRenDev->CV_r_MotionVectors && passInfo.IsGeneralPass() && ((pObj->m_ObjFlags & FOB_DYNAMIC_OBJECT) != 0))
{
CMotionBlur::SetupObject(pObj, passInfo);
}
TRenderChunkArray* pChunks = bSkinned ? &m_ChunksSkinned : &m_Chunks;
// for rendering with multiple drawcalls, use ChunksSubObjects
if (bRenderBreakableWithMultipleDrawCalls)
{
pChunks = &m_ChunksSubObjects;
}
const uint32 ni = (uint32)pChunks->size();
CRenderChunk* pPrevChunk = NULL;
for (uint32 i = 0; i < ni; i++)
{
CRenderChunk* pChunk = &pChunks->at(i);
CRendElementBase* __restrict pREMesh = pChunk->pRE;
SShaderItem& ShaderItem = pMaterial->GetShaderItem(pChunk->m_nMatID);
CShaderResources* pR = (CShaderResources*)ShaderItem.m_pShaderResources;
CShader* __restrict pS = (CShader*)ShaderItem.m_pShader;
if (pR && pR->IsDeforming())
{
pObj->m_ObjFlags |= FOB_MOTION_BLUR;
}
// don't render this chunk if the hide mask for it is set
if (bRenderBreakableWithMultipleDrawCalls && (nMeshSubSetMask & ((uint64)1 << pChunk->nSubObjectIndex)))
{
goto SkipChunk;
}
if (pREMesh == NULL || pS == NULL || pR == NULL)
{
goto SkipChunk;
}
if (pS->m_Flags2 & EF2_NODRAW)
{
goto SkipChunk;
}
if (passInfo.IsShadowPass() && (pR->m_ResFlags & MTL_FLAG_NOSHADOW))
{
goto SkipChunk;
}
if (passInfo.IsShadowPass() && !passInfo.IsDisableRenderChunkMerge() && CRenderMesh::RenderChunkMergeAbleInShadowPass(pPrevChunk, pChunk, pMaterial))
{
continue; // skip the merged chunk, but keep the PrevChunkReference for further merging
}
PrefetchLine(pREMesh, 0);
PrefetchLine(pObj, 0);
rd->EF_AddEf_NotVirtual(pREMesh, ShaderItem, pObj, passInfo, nList, nAW, rendItemSorter);
pPrevChunk = pChunk;
continue;
SkipChunk:
pPrevChunk = NULL;
}
}
void CRenderMesh::AddShadowPassMergedChunkIndicesAndVertices(CRenderChunk* pCurrentChunk, _smart_ptr<IMaterial> pMaterial, int& rNumVertices, int& rNumIndices)
{
if (m_Chunks.size() == 0)
{
return;
}
if (gRenDev->m_RP.m_pCurObject->m_ObjFlags & (FOB_SKINNED))
{
return;
}
if (pMaterial == NULL)
{
return;
}
AUTO_LOCK(pMaterial->GetSubMaterialResizeLock());
for (uint32 i = (uint32)(pCurrentChunk - &m_Chunks[0]) + 1; i < (uint32)m_Chunks.size(); ++i)
{
if (!CRenderMesh::RenderChunkMergeAbleInShadowPass(pCurrentChunk, &m_Chunks[i], pMaterial))
{
return;
}
rNumVertices += m_Chunks[i].nNumVerts;
rNumIndices += m_Chunks[i].nNumIndices;
}
}
bool CRenderMesh::RenderChunkMergeAbleInShadowPass(CRenderChunk* pPreviousChunk, CRenderChunk* pCurrentChunk, _smart_ptr<IMaterial> pMaterial)
{
if IsCVarConstAccess(constexpr) (!CRenderer::CV_r_MergeShadowDrawcalls)
{
return false;
}
if (pPreviousChunk == NULL || pCurrentChunk == NULL || pMaterial == NULL)
{
return false;
}
SShaderItem& rCurrentShaderItem = pMaterial->GetShaderItem(pCurrentChunk->m_nMatID);
SShaderItem& rPreviousShaderItem = pMaterial->GetShaderItem(pPreviousChunk->m_nMatID);
CShaderResources* pCurrentShaderResource = (CShaderResources*)rCurrentShaderItem.m_pShaderResources;
CShaderResources* pPreviousShaderResource = (CShaderResources*)rPreviousShaderItem.m_pShaderResources;
CShader* pCurrentShader = (CShader*)rCurrentShaderItem.m_pShader;
CShader* pPreviousShader = (CShader*)rPreviousShaderItem.m_pShader;
if (!pCurrentShaderResource || !pPreviousShaderResource || !pCurrentShader || !pPreviousShader)
{
return false;
}
bool bCurrentAlphaTested = pCurrentShaderResource->CShaderResources::IsAlphaTested();
bool bPreviousAlphaTested = pPreviousShaderResource->CShaderResources::IsAlphaTested();
if (bCurrentAlphaTested != bPreviousAlphaTested)
{
return false;
}
if (bCurrentAlphaTested)
{
const SEfResTexture* pCurrentResTex = pCurrentShaderResource->GetTextureResource(EFTT_DIFFUSE);
const SEfResTexture* pPreviousResTex = pPreviousShaderResource->GetTextureResource(EFTT_DIFFUSE);
const CTexture* pCurrentDiffuseTex = pCurrentResTex ? pCurrentResTex->m_Sampler.m_pTex : nullptr;
const CTexture* pPreviousDiffuseTex = pPreviousResTex ? pPreviousResTex->m_Sampler.m_pTex : nullptr;
if (pCurrentDiffuseTex != pPreviousDiffuseTex)
{
return false;
}
}
if (((pPreviousShaderResource->m_ResFlags & MTL_FLAG_NOSHADOW) != 0) || ((pCurrentShaderResource->m_ResFlags & MTL_FLAG_NOSHADOW) != 0))
{
return false;
}
if ((pPreviousShaderResource->m_ResFlags & MTL_FLAG_2SIDED) != (pCurrentShaderResource->m_ResFlags & MTL_FLAG_2SIDED))
{
return false;
}
if (((pPreviousShader->m_Flags & EF_NODRAW) != 0) || ((pCurrentShader->m_Flags & EF_NODRAW) != 0))
{
return false;
}
return true;
}
// break-ability support
IRenderMesh* CRenderMesh::GetRenderMeshForSubsetMask([[maybe_unused]] SRenderObjData* pOD, uint64 nMeshSubSetMask, _smart_ptr<IMaterial> pMaterial, const SRenderingPassInfo& passInfo)
{
// TODO: If only one bit is set in mask - there is no need to build new index buffer - small part of main index buffer can be re-used
// TODO: Add auto releasing of not used for long time index buffers
// TODO: Take into account those induces when computing render mesh memory size for CGF streaming
// TODO: Support for multiple materials
assert(nMeshSubSetMask != 0);
IRenderMesh* pSrcRM = this;
TRenderChunkArray& renderChunks = m_ChunksSubObjects;
uint32 nChunkCount = renderChunks.size();
nMeshSubSetMask &= (((uint64)1 << nChunkCount) - 1);
// try to find the index mesh in the already finished list
const MeshSubSetIndices::iterator meshSubSet = m_meshSubSetIndices.find(nMeshSubSetMask);
if (meshSubSet != m_meshSubSetIndices.end())
{
return meshSubSet->second;
}
// subset mesh was not found, start job to create one
SMeshSubSetIndicesJobEntry* pSubSetJob = m_meshSubSetRenderMeshJobs[passInfo.ThreadID()].push_back_new();
pSubSetJob->m_pSrcRM = pSrcRM;
pSubSetJob->m_pIndexRM = NULL;
pSubSetJob->m_nMeshSubSetMask = nMeshSubSetMask;
pSubSetJob->jobExecutor.StartJob([pSubSetJob]()
{
pSubSetJob->CreateSubSetRenderMesh();
}); // Legacy JobManager used SJobState::SetBlocking
return NULL;
}
void CRenderMesh::FinalizeRendItems(int nThreadID)
{
// perform all requiered garbage collections
m_deferredSubsetGarbageCollection[nThreadID].CoalesceMemory();
for (size_t i = 0; i < m_deferredSubsetGarbageCollection[nThreadID].size(); ++i)
{
if (m_deferredSubsetGarbageCollection[nThreadID][i])
{
m_deferredSubsetGarbageCollection[nThreadID][i]->GarbageCollectSubsetRenderMeshes();
}
}
m_deferredSubsetGarbageCollection[nThreadID].resize(0);
// add all newly generated subset meshes
bool bJobsStillRunning = false;
size_t nNumSubSetRenderMeshJobs = m_meshSubSetRenderMeshJobs[nThreadID].size();
for (size_t i = 0; i < nNumSubSetRenderMeshJobs; ++i)
{
SMeshSubSetIndicesJobEntry& rSubSetJob = m_meshSubSetRenderMeshJobs[nThreadID][i];
if (rSubSetJob.jobExecutor.IsRunning())
{
bJobsStillRunning = true;
}
else if (rSubSetJob.m_pSrcRM) // finished job, which needs to be assigned
{
CRenderMesh* pSrcMesh = static_cast<CRenderMesh*>(rSubSetJob.m_pSrcRM.get());
// check that we didn't create the same subset mesh twice, if we did, clean up the duplicate
if (pSrcMesh->m_meshSubSetIndices.find(rSubSetJob.m_nMeshSubSetMask) == pSrcMesh->m_meshSubSetIndices.end())
{
pSrcMesh->m_meshSubSetIndices.insert(std::make_pair(rSubSetJob.m_nMeshSubSetMask, rSubSetJob.m_pIndexRM));
}
// mark job as assigned
rSubSetJob.m_pIndexRM = NULL;
rSubSetJob.m_pSrcRM = NULL;
}
}
if (!bJobsStillRunning)
{
m_meshSubSetRenderMeshJobs[nThreadID].resize(0);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void CRenderMesh::ClearJobResources()
{
for (int i = 0; i < RT_COMMAND_BUF_COUNT; ++i)
{
for (size_t j = 0; j < m_deferredSubsetGarbageCollection[i].size(); ++j)
{
if (m_deferredSubsetGarbageCollection[i][j])
{
m_deferredSubsetGarbageCollection[i][j]->GarbageCollectSubsetRenderMeshes();
}
}
stl::free_container(m_deferredSubsetGarbageCollection[i]);
for (size_t j = 0; j < m_deferredSubsetGarbageCollection[i].size(); ++j)
{
m_meshSubSetRenderMeshJobs[i][j].jobExecutor.WaitForCompletion();
}
stl::free_container(m_meshSubSetRenderMeshJobs[i]);
}
}
void SMeshSubSetIndicesJobEntry::CreateSubSetRenderMesh()
{
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::Renderer);
CRenderMesh* pSrcMesh = static_cast<CRenderMesh*>(m_pSrcRM.get());
TRenderChunkArray& renderChunks = pSrcMesh->m_ChunksSubObjects;
uint32 nChunkCount = renderChunks.size();
pSrcMesh->LockForThreadAccess();
int nIndCount = pSrcMesh->GetIndicesCount();
if (vtx_idx* pInds = pSrcMesh->GetIndexPtr(FSL_READ))
{
TRenderChunkArray newChunks;
newChunks.reserve(3);
int nMatId = -1;
PodArray<vtx_idx> lstIndices;
for (uint32 c = 0; c < nChunkCount; c++)
{
CRenderChunk& srcChunk = renderChunks[c];
if (0 == (m_nMeshSubSetMask & ((uint64)1 << srcChunk.nSubObjectIndex)))
{
uint32 nLastIndex = lstIndices.size();
lstIndices.AddList(&pInds[srcChunk.nFirstIndexId], srcChunk.nNumIndices);
if (newChunks.empty() || nMatId != srcChunk.m_nMatID)
{
// New chunk needed.
newChunks.push_back(srcChunk);
newChunks.back().nFirstIndexId = nLastIndex;
newChunks.back().nNumIndices = 0;
newChunks.back().nNumVerts = 0;
newChunks.back().pRE = 0;
}
nMatId = srcChunk.m_nMatID;
newChunks.back().nNumIndices += srcChunk.nNumIndices;
newChunks.back().nNumVerts = max((int)srcChunk.nFirstVertId + (int)srcChunk.nNumVerts - (int)newChunks.back().nFirstVertId, (int)newChunks.back().nNumVerts);
}
}
pSrcMesh->UnLockForThreadAccess();
IRenderMesh::SInitParamerers params;
SVF_P3S_C4B_T2S tempVertex;
params.pVertBuffer = &tempVertex;
params.nVertexCount = 1;
params.vertexFormat = eVF_P3S_C4B_T2S;
params.pIndices = lstIndices.GetElements();
params.nIndexCount = lstIndices.Count();
params.nPrimetiveType = prtTriangleList;
params.eType = eRMT_Static;
params.nRenderChunkCount = 1;
params.bOnlyVideoBuffer = false;
params.bPrecache = false;
_smart_ptr<IRenderMesh> pIndexMesh = gRenDev->CreateRenderMesh(pSrcMesh->m_sType, pSrcMesh->m_sSource, &params);
pIndexMesh->SetVertexContainer(pSrcMesh);
if (!newChunks.empty())
{
pIndexMesh->SetRenderChunks(&newChunks.front(), newChunks.size(), false);
pIndexMesh->SetBBox(pSrcMesh->m_vBoxMin, pSrcMesh->m_vBoxMax);
}
m_pIndexRM = pIndexMesh;
}
}
@@ -0,0 +1,348 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "RenderMesh.h"
#include "IIndexedMesh.h"
#define TRANSFER_ALIGNMENT 1
static void transfer_writecombined(void* pDst, const void* pSrc, size_t size)
{
cryMemcpy(pDst, pSrc, size, MC_CPU_TO_GPU);
}
template<EStreamIDs stream, size_t Size>
struct StreamCompactor;
template<EStreamIDs stream, size_t Size>
uint32 CompactStream(uint8 (&buffer)[Size], SSetMeshIntData& data, CMesh& mesh, uint32 beg, uint32 end)
{
return StreamCompactor<stream, Size>::Compact(buffer, data, mesh, beg, end);
}
// Override for the VSF_GENERAL stream that can be used with arbitrary vertex data
template<EStreamIDs stream, size_t Size>
uint32 CompactStream(uint8(&buffer)[Size], SSetMeshIntData& data, CMesh& mesh, uint32 beg, uint32 end, const AZ::Vertex::Format& vertexFormat)
{
return StreamCompactor<stream, Size>::Compact(buffer, data, mesh, beg, end, vertexFormat);
}
template<size_t Size>
struct StreamCompactor<VSF_GENERAL, Size>
{
static void CompactPositions(uint8* stagingBuffer, [[maybe_unused]] SSetMeshIntData& data, CMesh& mesh, uint32 beg, uint32 end, uint32 streamIndex, uint32 vertexStride, uint32 attributeOffset, uint32 attributeByteLength)
{
if (mesh.Has32BitPositions())
{
Vec3* positions = mesh.GetStreamPtr<Vec3>(CMesh::POSITIONS, streamIndex);
AZ_Assert(attributeByteLength == sizeof(Vec3), "Mesh uses three 32 bit floats for positions, but vertex format is expecting a different size");
for (size_t i = 0; i < end; ++i)
{
memcpy(stagingBuffer + i * vertexStride + attributeOffset, &positions[beg + i], attributeByteLength);
}
}
else if (mesh.Has16BitPositions())
{
Vec3f16* positions = mesh.GetStreamPtr<Vec3f16>(CMesh::POSITIONSF16, streamIndex);
AZ_Assert(attributeByteLength == sizeof(Vec3f16), "Mesh uses three 16 bit floats for positions, but vertex format is expecting a different size");
for (size_t i = 0; i < end; ++i)
{
memcpy(stagingBuffer + i * vertexStride + attributeOffset, &positions[beg + i], attributeByteLength);
}
}
else
{
AZ_Assert(false, "Mesh has no per-vertex positions.");
}
}
static void CompactNormals(SVF_P3S_N4B_C4B_T2S* pVBuff, SSetMeshIntData& data, CMesh& mesh, uint32 beg, uint32 end)
{
SMeshNormal* normals = mesh.GetStreamPtr<SMeshNormal>(CMesh::NORMALS);
if (normals)
{
for (size_t i = 0; i < end; ++i)
{
Vec3 n = normals[beg + i].GetN();
pVBuff[i].normal.bcolor[0] = (byte)(n[0] * 127.5f + 128.0f);
pVBuff[i].normal.bcolor[1] = (byte)(n[1] * 127.5f + 128.0f);
pVBuff[i].normal.bcolor[2] = (byte)(n[2] * 127.5f + 128.0f);
SwapEndian(pVBuff[i].normal.dcolor);
}
}
}
static void CompactColors(uint8* stagingBuffer, [[maybe_unused]] SSetMeshIntData& data, CMesh& mesh, uint32 beg, uint32 end, uint32 streamIndex, uint32 vertexStride, uint32 attributeOffset, uint32 attributeByteLength)
{
SMeshColor* colors = mesh.GetStreamPtr<SMeshColor>(CMesh::COLORS, streamIndex);
if (colors)
{
for (size_t i = 0; i < end; ++i)
{
ColorB color = colors[beg + i].GetRGBA();
UCol uColor;
uColor.bcolor[0] = color.b;
uColor.bcolor[1] = color.g;
uColor.bcolor[2] = color.r;
uColor.bcolor[3] = color.a;
SwapEndian(uColor.dcolor);
memcpy(stagingBuffer + i * vertexStride + attributeOffset, &uColor, attributeByteLength);
}
}
else
{
for (size_t i = 0; i < end; ++i)
{
UCol defaultColor;
defaultColor.dcolor = ~0;
memcpy(stagingBuffer + i * vertexStride + attributeOffset, &defaultColor, attributeByteLength);
}
}
}
static void CompactUVs(uint8* stagingBuffer, [[maybe_unused]] SSetMeshIntData& data, CMesh& mesh, uint32 beg, uint32 end, uint32 streamIndex, uint32 vertexStride, uint32 attributeOffset, uint32 attributeByteLength)
{
SMeshTexCoord* texCoords = mesh.GetStreamPtr<SMeshTexCoord>(CMesh::TEXCOORDS, streamIndex);
if (texCoords)
{
for (size_t i = 0; i < end; ++i)
{
SMeshTexCoord meshTexCoord = texCoords[beg + i];
// If the vertex format uses two 32 bit floats for texture coordinates, copy them to the staging buffer
if (attributeByteLength == sizeof(Vec2))
{
Vec2 texCoord = meshTexCoord.GetUV();
memcpy(stagingBuffer + i * vertexStride + attributeOffset, &texCoord, attributeByteLength);
}
// If the vertex format uses two 16 bit floats for texture coordinates, convert the CMesh texture coordinates to 16 bit floats and then copy them to the staging buffer
else if (attributeByteLength == sizeof(Vec2f16))
{
Vec2f16 texCoord;
meshTexCoord.ExportTo(texCoord);
memcpy(stagingBuffer + i * vertexStride + attributeOffset, &texCoord, attributeByteLength);
}
else
{
AZ_Assert(false, "Invalid byte length for texture coordinates");
}
}
}
}
static uint32 Compact(uint8 (&buffer)[Size], SSetMeshIntData& data, CMesh& mesh, uint32 beg, uint32 end, const AZ::Vertex::Format& vertexFormat)
{
if (data.m_pVBuff)
{
size_t dstPad = (size_t)&data.m_pVBuff[beg * vertexFormat.GetStride()] & (TRANSFER_ALIGNMENT - 1);
uint8* stagingBuffer = &buffer[dstPad];
uint32 amount = min((uint32)(end - beg), (uint32)(Size / vertexFormat.GetStride()));
if (mesh.m_pP3S_C4B_T2S)
{
// Do a straight copy of mesh data that has already been interleaved
memcpy(stagingBuffer, &mesh.m_pP3S_C4B_T2S[beg], sizeof(SVF_P3S_C4B_T2S) * amount);
}
else
{
uint32 attributeCount = 0;
const uint8* attributes = vertexFormat.GetAttributes(attributeCount);
int attributeCounter[(int)AZ::Vertex::AttributeUsage::NumUsages] = { 0 };
uint32 attributeOffset = 0;
// Iterate over each attribute in the vertex format and interleave that attribute into the staging buffer
for (uint ii = 0; ii < attributeCount; ++ii)
{
const uint8 attribute = attributes[ii];
const AZ::Vertex::AttributeUsage usage = AZ::Vertex::Attribute::GetUsage(attribute);
switch (usage)
{
case AZ::Vertex::AttributeUsage::Position:
CompactPositions(stagingBuffer, data, mesh, beg, amount, attributeCounter[(int)AZ::Vertex::AttributeUsage::Position], vertexFormat.GetStride(), attributeOffset, AZ::Vertex::Attribute::GetByteLength(attribute));
break;
case AZ::Vertex::AttributeUsage::Color:
CompactColors(stagingBuffer, data, mesh, beg, amount, attributeCounter[(int)AZ::Vertex::AttributeUsage::Color], vertexFormat.GetStride(), attributeOffset, AZ::Vertex::Attribute::GetByteLength(attribute));
break;
case AZ::Vertex::AttributeUsage::TexCoord:
CompactUVs(stagingBuffer, data, mesh, beg, amount, attributeCounter[(int)AZ::Vertex::AttributeUsage::TexCoord], vertexFormat.GetStride(), attributeOffset, AZ::Vertex::Attribute::GetByteLength(attribute));
break;
default:
AZ_Assert(false, "No case to handle per vertex data in the VSF_GENERAL stream for usage %d.", AZ::Vertex::Attribute::GetUsage(attribute));
break;
}
// Keep track of the offset of the current attribute
attributeOffset += AZ::Vertex::Attribute::GetByteLength(attribute);
// Keep track of the number of attributes with a given usage so we can use that to index into the CMesh's vertex streams for that usage
attributeCounter[static_cast<uint8>(usage)]++;
}
}
transfer_writecombined(&data.m_pVBuff[beg * vertexFormat.GetStride()], &buffer[dstPad], amount * vertexFormat.GetStride());
return amount;
}
CryFatalError("CRenderMesh::SetMesh_Impl: invalid vertex format for general stream");
return 0;
}
};
template<size_t Size>
struct StreamCompactor<VSF_TANGENTS, Size>
{
static uint32 Compact(uint8 (&buffer)[Size], SSetMeshIntData& data, CMesh& mesh, uint32 beg, uint32 end)
{
if (mesh.m_pTangents == NULL || data.m_pTBuff == NULL)
{
return end;
}
uint32 dstPad = 0;
SPipTangents* pTBuff = alias_cast<SPipTangents*>(&buffer[dstPad]);
uint32 amount = min((uint32)(end - beg), (uint32)(Size / sizeof(pTBuff[0])));
for (size_t i = 0; i < amount; ++i)
{
mesh.m_pTangents[beg + i].ExportTo(pTBuff[i]);
}
transfer_writecombined(&data.m_pTBuff[beg], &buffer[dstPad], amount * sizeof(data.m_pTBuff[0]));
return amount;
}
};
template<size_t Size>
struct StreamCompactor<VSF_QTANGENTS, Size>
{
static uint32 Compact(uint8 (&buffer)[Size], SSetMeshIntData& data, CMesh& mesh, uint32 beg, uint32 end)
{
if (mesh.m_pQTangents == NULL || data.m_pQTBuff == NULL)
{
return end;
}
uint32 dstPad = 0;
SPipQTangents* pQTBuff = alias_cast<SPipQTangents*>(&buffer[dstPad]);
uint32 amount = min((uint32)(end - beg), (uint32)(Size / sizeof(pQTBuff[0])));
for (size_t i = 0; i < amount; ++i)
{
mesh.m_pQTangents[beg + i].ExportTo(pQTBuff[i]);
}
transfer_writecombined(&data.m_pQTBuff[beg], &buffer[dstPad], amount * sizeof(pQTBuff[0]));
return amount;
}
};
#if ENABLE_NORMALSTREAM_SUPPORT
template<size_t Size>
struct StreamCompactor<VSF_NORMALS, Size>
{
static uint32 Compact(uint8 (&buffer)[Size], SSetMeshIntData& data, CMesh& mesh, uint32 beg, uint32 end)
{
if (mesh.m_pNorms == NULL || data.m_pNormalsBuff == NULL)
{
return end;
}
uint32 dstPad = 0;
uint32 amount = min((uint32)(end - beg), (uint32)(Size / sizeof(data.m_pNormalsBuff[0])));
memcpy(&buffer[dstPad], &mesh.m_pNorms[beg], amount * sizeof(data.m_pNormalsBuff[0]));
transfer_writecombined(&data.m_pNormalsBuff[beg], &buffer[dstPad], amount * sizeof(data.m_pNormalsBuff[0]));
return amount;
}
};
#endif
template<size_t Size>
struct StreamCompactor<VSF_VERTEX_VELOCITY, Size>
{
static uint32 Compact(uint8 (&buffer)[Size], SSetMeshIntData& data, [[maybe_unused]] CMesh& mesh, uint32 beg, uint32 end)
{
if (data.m_pVelocities == NULL)
{
return end;
}
uint32 dstPad = 0;
uint32 amount = min((uint32)(end - beg), (uint32)(Size / sizeof(data.m_pVelocities[0])));
memset(&buffer[dstPad], 0x0, amount * sizeof(data.m_pVelocities[0]));
transfer_writecombined(&data.m_pVelocities[beg], &buffer[dstPad], amount * sizeof(data.m_pVelocities[0]));
return amount;
}
};
template<size_t Size>
uint32 CompactIndices(uint8 (&buffer)[Size], SSetMeshIntData& data, CMesh& mesh, uint32 beg, uint32 end)
{
if (mesh.m_pIndices == NULL || data.m_pInds == NULL)
{
return end;
}
uint32 dstPad = 0;
uint32 amount = min((uint32)(end - beg), (uint32)(Size / sizeof(mesh.m_pIndices[0])));
memcpy(&buffer[dstPad], &mesh.m_pIndices[beg], amount * sizeof(mesh.m_pIndices[0]));
transfer_writecombined(&data.m_pInds[beg], &buffer[dstPad], amount * sizeof(data.m_pInds[0]));
return amount;
}
typedef _MS_ALIGN (128) uint8 AlignedStagingBufferT[(8 << 10) + 128];
void CRenderMesh::SetMesh_IntImpl(SSetMeshIntData data)
{
CMesh& mesh = *data.m_pMesh;
AlignedStagingBufferT stagingBuffer;
//////////////////////////////////////////////////////////////////////////
// Compact the seperate streams from the CMesh instance into a general
//////////////////////////////////////////////////////////////////////////
for (uint32 iter = 0; iter < data.m_nVerts; iter += CompactStream<VSF_GENERAL>(stagingBuffer, data, mesh, iter, data.m_nVerts, m_vertexFormat))
{
;
}
for (uint32 iter = 0; iter < data.m_nVerts; iter += CompactStream<VSF_TANGENTS>(stagingBuffer, data, mesh, iter, data.m_nVerts))
{
;
}
for (uint32 iter = 0; iter < data.m_nVerts; iter += CompactStream<VSF_QTANGENTS>(stagingBuffer, data, mesh, iter, data.m_nVerts))
{
;
}
# if ENABLE_NORMALSTREAM_SUPPORT
for (uint32 iter = 0; iter < data.m_nVerts; iter += CompactStream<VSF_NORMALS>(stagingBuffer, data, mesh, iter, data.m_nVerts))
{
;
}
# endif
for (uint32 iter = 0; iter < data.m_nVerts; iter += CompactStream<VSF_VERTEX_VELOCITY>(stagingBuffer, data, mesh, iter, data.m_nVerts))
{
;
}
for (uint32 iter = 0; iter < data.m_nInds; iter += CompactIndices(stagingBuffer, data, mesh, iter, data.m_nInds))
{
;
}
}
@@ -0,0 +1,22 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "RenderDll_precompiled.h"
#include "Shadow_Renderer.h"
#include "RenderView.h"
int SRendItem::m_RecurseLevel[RT_COMMAND_BUF_COUNT];
int SRendItem::m_StartFrust[RT_COMMAND_BUF_COUNT][MAX_REND_LIGHTS + MAX_DEFERRED_LIGHTS];
int SRendItem::m_EndFrust[RT_COMMAND_BUF_COUNT][MAX_REND_LIGHTS + MAX_DEFERRED_LIGHTS];
int SRendItem::m_ShadowsStartRI[RT_COMMAND_BUF_COUNT][MAX_SHADOWMAP_FRUSTUMS];
int SRendItem::m_ShadowsEndRI[RT_COMMAND_BUF_COUNT][MAX_SHADOWMAP_FRUSTUMS];
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More