Integrating latest 47acbe8

This commit is contained in:
alexpete
2021-03-25 13:57:57 -07:00
parent 448c549698
commit 75dc720198
10312 changed files with 2711566 additions and 671451 deletions
-3
View File
@@ -21,9 +21,6 @@ ly_add_target(
INCLUDE_DIRECTORIES
PRIVATE
.
COMPILE_DEFINITIONS
PRIVATE
METRICS_ENABLED
BUILD_DEPENDENCIES
PUBLIC
AZ::AzToolsFramework
@@ -31,6 +31,7 @@
#include <AzFramework/Input/System/InputSystemComponent.h>
#include <AzFramework/Platform/PlatformDefaults.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzFramework/Components/AzFrameworkConfigurationSystemComponent.h>
#include <AzToolsFramework/Archive/ArchiveComponent.h>
#include <AzToolsFramework/Asset/AssetDebugInfo.h>
@@ -192,6 +193,7 @@ namespace AssetBundler
for (auto iter = components.begin(); iter != components.end();)
{
if (*iter == azrtti_typeid<AzFramework::GameEntityContextComponent>() ||
*iter == azrtti_typeid<AzFramework::AzFrameworkConfigurationSystemComponent>() ||
*iter == azrtti_typeid<AzFramework::InputSystemComponent>() ||
*iter == azrtti_typeid<AzFramework::DrillerNetworkAgentComponent>() ||
*iter == azrtti_typeid<AZ::SliceSystemComponent>())
@@ -121,7 +121,7 @@ namespace AssetBundler
namespace Internal
{
const AZ::u32 PlatformFlags_RESTRICTED = aznumeric_cast<AZ::u32>(AzFramework::PlatformFlags::Platform_JASPER | AzFramework::PlatformFlags::Platform_PROVO | AzFramework::PlatformFlags::Platform_SALEM | AzFramework::PlatformFlags::Platform_XENIA);
const AZ::u32 PlatformFlags_RESTRICTED = aznumeric_cast<AZ::u32>(AzFramework::PlatformFlags::Platform_JASPER | AzFramework::PlatformFlags::Platform_PROVO | AzFramework::PlatformFlags::Platform_SALEM);
void AddPlatformSeeds(
AZStd::string rootFolder,
@@ -3,7 +3,6 @@
es3=enabled
;ios=enabled
;osx_gl=enabled
;xenia=enabled
;provo=enabled
;server=enabled
@@ -3,6 +3,5 @@
;es3=enabled
ios=enabled
;osx_gl=enabled
;xenia=enabled
;provo=enabled
;server=enabled
@@ -3,7 +3,6 @@
;es3=enabled
;ios=enabled
;osx_gl=enabled
;xenia=enabled
provo=enabled
;server=enabled
@@ -30,6 +30,7 @@
#include <AzToolsFramework/Entity/EditorEntityContextComponent.h>
#include <AzToolsFramework/Entity/EditorEntityModelComponent.h>
#include <AzToolsFramework/Entity/EditorEntitySearchComponent.h>
#include <AzToolsFramework/Prefab/PrefabSystemComponent.h>
#include <AzToolsFramework/Slice/SliceMetadataEntityContextComponent.h>
#include <AzToolsFramework/ToolsComponents/ToolsAssetCatalogComponent.h>
@@ -81,6 +82,7 @@ AZ::ComponentTypeList AssetBuilderApplication::GetRequiredSystemComponents() con
azrtti_typeid<AzToolsFramework::Components::EditorEntitySearchComponent>(),
azrtti_typeid<AzToolsFramework::Components::EditorEntityModelComponent>(),
azrtti_typeid<AzToolsFramework::EditorEntityContextComponent>(),
azrtti_typeid<AzToolsFramework::Prefab::PrefabSystemComponent>(),
});
return components;
@@ -90,17 +90,10 @@ namespace AssetBuilderSDK
{
return AssetBuilderSDK::Platform_OSX;
}
if (azstricmp(newPlatformName, "xenia") == 0)
{
return AssetBuilderSDK::Platform_XENIA;
}
if (azstricmp(newPlatformName, "provo") == 0)
{
return AssetBuilderSDK::Platform_PROVO;
}
#if defined(AZ_PLATFORM_XENIA) || defined(TOOLS_SUPPORT_XENIA)
#include AZ_RESTRICTED_FILE_EXPLICIT(AssetBuilderSDK_cpp, xenia)
#endif
#if defined(AZ_PLATFORM_JASPER) || defined(TOOLS_SUPPORT_JASPER)
#include AZ_RESTRICTED_FILE_EXPLICIT(AssetBuilderSDK_cpp, jasper)
#endif
@@ -128,8 +121,6 @@ namespace AssetBuilderSDK
return "ios";
case AssetBuilderSDK::Platform_OSX:
return "osx_gl";
case AssetBuilderSDK::Platform_XENIA:
return "xenia";
case AssetBuilderSDK::Platform_PROVO:
return "provo";
case AssetBuilderSDK::Platform_SALEM:
@@ -151,13 +151,12 @@ namespace AssetBuilderSDK
Platform_ES3 = 0x02,
Platform_IOS = 0x04,
Platform_OSX = 0x08,
Platform_XENIA = 0x10,
Platform_PROVO = 0x20,
Platform_SALEM = 0x40,
Platform_JASPER = 0x80,
//! if you add a new platform entry to this enum, you must add it to allplatforms as well otherwise that platform would not be considered valid.
AllPlatforms = Platform_PC | Platform_ES3 | Platform_IOS | Platform_OSX | Platform_XENIA | Platform_PROVO | Platform_SALEM | Platform_JASPER
AllPlatforms = Platform_PC | Platform_ES3 | Platform_IOS | Platform_OSX | Platform_PROVO | Platform_SALEM | Platform_JASPER
};
#endif // defined(ENABLE_LEGACY_PLATFORMFLAGS_SUPPORT)
//! Map data structure to holder parameters that are passed into a job for ProcessJob requests.
+1 -6
View File
@@ -41,7 +41,7 @@ ly_add_target(
3rdParty::Qt::Network
3rdParty::RapidJSON
3rdParty::SQLite
3rdParty::XXHash
3rdParty::xxhash
AZ::AzCore
AZ::AzFramework
AZ::AzQtComponents
@@ -82,11 +82,6 @@ ly_add_target(
PRIVATE
AZ::AssetProcessor.Static
)
ly_add_source_properties(
SOURCES native/utilities/BatchApplicationManager.cpp
PROPERTY COMPILE_DEFINITIONS
VALUES LY_METRICS_BUILD_TIME=${LY_METRICS_BUILD_TIME}
)
# Adds the AssetProcessor target as a C preprocessor define so that it can be used as a Settings Registry
# specialization in order to look up the generated .setreg which contains the dependencies
@@ -86,8 +86,8 @@ Connection::Connection(bool isUserCreatedConnection, qintptr socketDescriptor, Q
connect(m_connectionWorker, &AssetProcessor::ConnectionWorker::ConnectionEstablished, this, &Connection::OnConnectionEstablished, Qt::BlockingQueuedConnection);
connect(m_connectionWorker, &AssetProcessor::ConnectionWorker::ErrorMessage, this, &Connection::ErrorMessage);
connect(m_connectionWorker, &AssetProcessor::ConnectionWorker::IsAddressWhiteListed, this, &Connection::IsAddressWhiteListed);
connect(this, &Connection::AddressIsWhiteListed, m_connectionWorker, &AssetProcessor::ConnectionWorker::AddressIsWhiteListed);
connect(m_connectionWorker, &AssetProcessor::ConnectionWorker::IsAddressInAllowedList, this, &Connection::IsAddressInAllowedList);
connect(this, &Connection::AddressIsInAllowedList, m_connectionWorker, &AssetProcessor::ConnectionWorker::AddressIsInAllowedList);
}
void Connection::Activate(qintptr socketDescriptor)
@@ -202,9 +202,9 @@ Q_SIGNALS:
void Error(unsigned int connId, QString errorString);
// the token is just any identifier to identify a particular connection, potentially from the same host.
// the response (AddressIsWhiteListed) will have the same token as was sent.
void IsAddressWhiteListed(QHostAddress hostAddress, void* token);
void AddressIsWhiteListed(void* token, bool result);
// the response (AddressIsInAllowedList) will have the same token as was sent.
void IsAddressInAllowedList(QHostAddress hostAddress, void* token);
void AddressIsInAllowedList(void* token, bool result);
//metrics
void NumOpenRequestsChanged();
@@ -51,20 +51,20 @@ ConnectionManager::ConnectionManager(QObject* parent)
ConnectionManagerRequestBus::Handler::BusConnect();
QTimer::singleShot(0, this, SLOT(UpdateWhiteListFromBootStrap()));
QTimer::singleShot(0, this, SLOT(UpdateAllowedListFromBootStrap()));
}
void ConnectionManager::UpdateWhiteListFromBootStrap()
void ConnectionManager::UpdateAllowedListFromBootStrap()
{
m_whiteListedAddresses.clear();
QString whitelist = AssetUtilities::ReadWhitelistFromSettingsRegistry();
AZStd::vector<AZStd::string> whitelistaddressList;
AzFramework::StringFunc::Tokenize(whitelist.toUtf8().constData(), whitelistaddressList, ", \t\n\r");
for (const AZStd::string& whitelistaddress : whitelistaddressList)
m_allowedListAddresses.clear();
QString allowedlist = AssetUtilities::ReadAllowedlistFromSettingsRegistry();
AZStd::vector<AZStd::string> allowedlistaddressList;
AzFramework::StringFunc::Tokenize(allowedlist.toUtf8().constData(), allowedlistaddressList, ", \t\n\r");
for (const AZStd::string& allowedlistaddress : allowedlistaddressList)
{
m_whiteListedAddresses << whitelistaddress.c_str();
m_allowedListAddresses << allowedlistaddress.c_str();
}
Q_EMIT SyncWhiteListAndRejectedList(m_whiteListedAddresses, m_rejectedAddresses);
Q_EMIT SyncAllowedListAndRejectedList(m_allowedListAddresses, m_rejectedAddresses);
}
@@ -121,8 +121,8 @@ unsigned int ConnectionManager::internalAddConnection(bool isUserConnection, qin
}
Connection* connection = new Connection(isUserConnection, socketDescriptor, this);
connect(connection, &Connection::IsAddressWhiteListed, this, &ConnectionManager::IsAddressWhiteListed);
connect(this, &ConnectionManager::AddressIsWhiteListed, connection, &Connection::AddressIsWhiteListed);
connect(connection, &Connection::IsAddressInAllowedList, this, &ConnectionManager::IsAddressInAllowedList);
connect(this, &ConnectionManager::AddressIsInAllowedList, connection, &Connection::AddressIsInAllowedList);
connection->SetConnectionId(connectionId);
connect(connection, &Connection::StatusChanged, this, &ConnectionManager::OnStatusChanged);
@@ -496,31 +496,31 @@ void ConnectionManager::NewConnection(qintptr socketDescriptor)
addConnection(socketDescriptor);
}
void ConnectionManager::WhiteListingEnabled(bool enabled)
void ConnectionManager::AllowedListingEnabled(bool enabled)
{
m_whiteListingEnabled = enabled;
m_allowedListingEnabled = enabled;
}
void ConnectionManager::AddWhiteListedAddress(QString address)
void ConnectionManager::AddAddressToAllowedList(QString address)
{
UpdateWhiteListFromBootStrap();
while (m_whiteListedAddresses.removeOne(address)) {}
m_whiteListedAddresses << address;
AssetUtilities::WriteWhitelistToBootstrap(m_whiteListedAddresses);
Q_EMIT SyncWhiteListAndRejectedList(m_whiteListedAddresses, m_rejectedAddresses);
UpdateAllowedListFromBootStrap();
while (m_allowedListAddresses.removeOne(address)) {}
m_allowedListAddresses << address;
AssetUtilities::WriteAllowedlistToBootstrap(m_allowedListAddresses);
Q_EMIT SyncAllowedListAndRejectedList(m_allowedListAddresses, m_rejectedAddresses);
}
void ConnectionManager::RemoveWhiteListedAddress(QString address)
void ConnectionManager::RemoveAddressFromAllowedList(QString address)
{
UpdateWhiteListFromBootStrap();
while (m_whiteListedAddresses.removeOne(address)) {}
AssetUtilities::WriteWhitelistToBootstrap(m_whiteListedAddresses);
Q_EMIT SyncWhiteListAndRejectedList(m_whiteListedAddresses, m_rejectedAddresses);
UpdateAllowedListFromBootStrap();
while (m_allowedListAddresses.removeOne(address)) {}
AssetUtilities::WriteAllowedlistToBootstrap(m_allowedListAddresses);
Q_EMIT SyncAllowedListAndRejectedList(m_allowedListAddresses, m_rejectedAddresses);
}
void ConnectionManager::AddRejectedAddress(QString address, bool surpressWarning)
{
UpdateWhiteListFromBootStrap();
UpdateAllowedListFromBootStrap();
bool alreadyRejected = false;
while (m_rejectedAddresses.removeOne(address)) { alreadyRejected = true; }
m_rejectedAddresses << address;
@@ -528,21 +528,21 @@ void ConnectionManager::AddRejectedAddress(QString address, bool surpressWarning
{
Q_EMIT FirstTimeAddedToRejctedList(address);
}
Q_EMIT SyncWhiteListAndRejectedList(m_whiteListedAddresses, m_rejectedAddresses);
Q_EMIT SyncAllowedListAndRejectedList(m_allowedListAddresses, m_rejectedAddresses);
}
void ConnectionManager::RemoveRejectedAddress(QString address)
{
UpdateWhiteListFromBootStrap();
UpdateAllowedListFromBootStrap();
while (m_rejectedAddresses.removeOne(address)) {}
Q_EMIT SyncWhiteListAndRejectedList(m_whiteListedAddresses, m_rejectedAddresses);
Q_EMIT SyncAllowedListAndRejectedList(m_allowedListAddresses, m_rejectedAddresses);
}
void ConnectionManager::IsAddressWhiteListed(QHostAddress incominghostaddr, void* token)
void ConnectionManager::IsAddressInAllowedList(QHostAddress incominghostaddr, void* token)
{
if (!m_whiteListingEnabled)
if (!m_allowedListingEnabled)
{
Q_EMIT AddressIsWhiteListed(token, true);
Q_EMIT AddressIsInAllowedList(token, true);
return;
}
@@ -550,9 +550,9 @@ void ConnectionManager::IsAddressWhiteListed(QHostAddress incominghostaddr, void
if (incominghostaddr != QHostAddress::Null)
{
// any ipv4 address will be like ::ffff:A.B.C.D, we have to retrieve A.B.C.D for comparision with the whitelisted addresses.
// any ipv4 address will be like ::ffff:A.B.C.D, we have to retrieve A.B.C.D for comparision with the allowedlisted addresses.
// for example Qt will tell us the ipv6 (::ffff:127.0.0.1) for 127.0.0.1,
// but the whitelist below will report ipv4 (127.0.0.1) and ipv6 (::1), and they both won't match to ipv6 (::ffff:127.0.0.1).
// but the allowedlist below will report ipv4 (127.0.0.1) and ipv6 (::1), and they both won't match to ipv6 (::ffff:127.0.0.1).
bool wasConverted = false;
quint32 incomingIPv4 = incominghostaddr.toIPv4Address(&wasConverted);
if (wasConverted)
@@ -567,29 +567,29 @@ void ConnectionManager::IsAddressWhiteListed(QHostAddress incominghostaddr, void
QHostInfo incomingInfo = QHostInfo::fromName(incomingIpAddress);
QString whitelist = AssetUtilities::ReadWhitelistFromSettingsRegistry();
QString allowedlist = AssetUtilities::ReadAllowedlistFromSettingsRegistry();
AZStd::vector<AZStd::string> whitelistaddressList;
AzFramework::StringFunc::Tokenize(whitelist.toUtf8().constData(), whitelistaddressList, ", \t\n\r");
AZStd::vector<AZStd::string> allowedlistaddressList;
AzFramework::StringFunc::Tokenize(allowedlist.toUtf8().constData(), allowedlistaddressList, ", \t\n\r");
// allow localhost, loopback regardless, there's no good reason to accidentally lock yourself out your own computer.
for (const auto& address : QNetworkInterface::allAddresses()) // allAdresses returns the ip address of all local interfaces.
{
whitelistaddressList.push_back(address.toString().toUtf8().constData());
allowedlistaddressList.push_back(address.toString().toUtf8().constData());
}
// does the incoming connection match any entries?
for (const AZStd::string& whitelistaddress : whitelistaddressList)
for (const AZStd::string& allowedListaddress : allowedlistaddressList)
{
//address range matching
size_t maskLocation = whitelistaddress.find('/');
size_t maskLocation = allowedListaddress.find('/');
if (maskLocation != AZStd::string::npos)
{
//x.x.x.x/0 is all addresses
int mask = atoi(whitelistaddress.substr(maskLocation + 1).c_str());
int mask = atoi(allowedListaddress.substr(maskLocation + 1).c_str());
if (mask == 0)
{
Q_EMIT AddressIsWhiteListed(token, true);
Q_EMIT AddressIsInAllowedList(token, true);
return;
}
else
@@ -602,35 +602,35 @@ void ConnectionManager::IsAddressWhiteListed(QHostAddress incominghostaddr, void
//QT should first do a check and see if we are comparing convertible protocols before just early outing.
//If it wasn't convertible to ipv4 then we know it is ipv6 in which case the protocols will match which make this unnecessary, but still correct.
QHostAddress ha(incomingIpAddress);
if (ha.isInSubnet(QHostAddress::parseSubnet(whitelistaddress.c_str())))
if (ha.isInSubnet(QHostAddress::parseSubnet(allowedListaddress.c_str())))
{
Q_EMIT AddressIsWhiteListed(token, true);
Q_EMIT AddressIsInAllowedList(token, true);
return;
}
}
}
else//direct address matching
{
QHostInfo whiteInfo;
QHostAddress whiteHostAddress(whitelistaddress.c_str());
if ((whiteHostAddress.isNull()))
QHostInfo allowedInfo;
QHostAddress allowedHostAddress(allowedListaddress.c_str());
if ((allowedHostAddress.isNull()))
{
whiteInfo = QHostInfo::fromName(QString::fromUtf8(whitelistaddress.c_str()));
allowedInfo = QHostInfo::fromName(QString::fromUtf8(allowedListaddress.c_str()));
}
else
{
QList<QHostAddress> addresses;
addresses << whiteHostAddress;
whiteInfo.setAddresses(addresses);
addresses << allowedHostAddress;
allowedInfo.setAddresses(addresses);
}
for (const auto& whiteAddress : whiteInfo.addresses())
for (const auto& allowedAddress : allowedInfo.addresses())
{
for (const auto& address : incomingInfo.addresses())
{
if (address == whiteAddress)
if (address == allowedAddress)
{
Q_EMIT AddressIsWhiteListed(token, true);
Q_EMIT AddressIsInAllowedList(token, true);
return;
}
}
@@ -639,7 +639,7 @@ void ConnectionManager::IsAddressWhiteListed(QHostAddress incominghostaddr, void
}
AddRejectedAddress(incomingIpAddress);
Q_EMIT AddressIsWhiteListed(token, false);
Q_EMIT AddressIsInAllowedList(token, false);
}
void ConnectionManager::AddBytesReceived(unsigned int connId, qint64 add, bool update)
@@ -109,10 +109,10 @@ Q_SIGNALS:
void ReadyToQuit(QObject* source);
void SyncWhiteListAndRejectedList(QStringList whiteList, QStringList rejectedList);
void SyncAllowedListAndRejectedList(QStringList allowedList, QStringList rejectedList);
// this is a response to the whitelist request with that same token.
void AddressIsWhiteListed(void* token, bool result);
// this is a response to the allowedlist request with that same token.
void AddressIsInAllowedList(void* token, bool result);
void FirstTimeAddedToRejctedList(QString ipAddress);
@@ -123,10 +123,10 @@ public Q_SLOTS:
void MakeSureConnectionMapEmpty();
void NewConnection(qintptr socketDescriptor);
void WhiteListingEnabled(bool enabled);
void IsAddressWhiteListed(QHostAddress hostAddress, void* token);
void AddWhiteListedAddress(QString address);
void RemoveWhiteListedAddress(QString address);
void AllowedListingEnabled(bool enabled);
void IsAddressInAllowedList(QHostAddress hostAddress, void* token);
void AddAddressToAllowedList(QString address);
void RemoveAddressFromAllowedList(QString address);
void AddRejectedAddress(QString address, bool surpressWarning = false);
void RemoveRejectedAddress(QString address);
@@ -185,7 +185,7 @@ public Q_SLOTS:
void OnStatusChanged(unsigned int connId);
void UpdateWhiteListFromBootStrap();
void UpdateAllowedListFromBootStrap();
private:
@@ -205,11 +205,11 @@ private:
// the key is the name of the platform, and the value is the number of those kind of platforms.
QHash<QString, int> m_platformsConnected;
//white listing
bool m_whiteListingEnabled = true;
//allowed listing
bool m_allowedListingEnabled = true;
//these lists are just caches, only used for updating
QStringList m_whiteListedAddresses;
QStringList m_allowedListAddresses;
QStringList m_rejectedAddresses;
};
@@ -378,11 +378,11 @@ void ConnectionWorker::ConnectSocket(qintptr socketDescriptor)
disconnect(&m_engineSocket, &QTcpSocket::stateChanged, this, &ConnectionWorker::EngineSocketStateChanged);
m_engineSocket.setSocketDescriptor(socketDescriptor, QAbstractSocket::ConnectedState, QIODevice::ReadWrite);
Q_EMIT IsAddressWhiteListed(m_engineSocket.peerAddress(), reinterpret_cast<void*>(this));
Q_EMIT IsAddressInAllowedList(m_engineSocket.peerAddress(), reinterpret_cast<void*>(this));
}
}
void ConnectionWorker::AddressIsWhiteListed(void* token, bool result)
void ConnectionWorker::AddressIsInAllowedList(void* token, bool result)
{
if (reinterpret_cast<void*>(this) == token)
{
@@ -395,7 +395,7 @@ void ConnectionWorker::AddressIsWhiteListed(void* token, bool result)
else
{
// this address has been rejected, disconnect immediately!!!
AZ_TracePrintf(AssetProcessor::ConsoleChannel, " A connection attempt was ignored because it is not whitelisted. Please consider adding white_list=(IP ADDRESS),localhost to the bootstrap.cfg");
AZ_TracePrintf(AssetProcessor::ConsoleChannel, " A connection attempt was ignored because it is not in the allowed list. Please consider adding allowed_list=(IP ADDRESS),localhost to the bootstrap.cfg");
disconnect(&m_engineSocket, &QTcpSocket::readyRead, this, &ConnectionWorker::EngineSocketHasData);
@@ -58,7 +58,7 @@ Q_SIGNALS:
void ErrorMessage(QString msg);
// the token identifies the unique connection instance, since multiple may have the same address
void IsAddressWhiteListed(QHostAddress hostAddress, void* token);
void IsAddressInAllowedList(QHostAddress hostAddress, void* token);
public Q_SLOTS:
void ConnectSocket(qintptr socketDescriptor);
@@ -70,8 +70,8 @@ Q_SIGNALS:
void RequestTerminate();
bool NegotiateDirect(bool initiate);
// the token will be the same token sent in the whitelisting request.
void AddressIsWhiteListed(void* token, bool result);
// the token will be the same token sent in the allowedlisting request.
void AddressIsInAllowedList(void* token, bool result);
private Q_SLOTS:
void TerminateConnection();
@@ -85,6 +85,7 @@ namespace AssetProcessorMessagesTests
public:
void SetUp() override
{
#if !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
AssetUtilities::ResetGameName();
m_temporarySourceDir = QDir(m_temporaryDir.path());
@@ -165,10 +166,12 @@ namespace AssetProcessorMessagesTests
});
#endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
}
void TearDown() override
{
#if !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
QEventLoop eventLoop;
QObject::connect(m_batchApplicationManager->m_connectionManager, &ConnectionManager::ReadyToQuit, &eventLoop, &QEventLoop::quit);
@@ -179,6 +182,7 @@ namespace AssetProcessorMessagesTests
m_assetSystemComponent->Deactivate();
m_batchApplicationManager->Destroy();
#endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
}
void RunNetworkRequest(AZStd::function<void()> func) const
@@ -222,7 +226,11 @@ namespace AssetProcessorMessagesTests
AZStd::unique_ptr<AzFramework::AssetSystem::BaseAssetProcessorMessage> m_response;
};
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(AssetProcessorMessages, DISABLED_All)
#else
TEST_F(AssetProcessorMessages, All)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
// Test that we can successfully send network messages and have them arrive for processing
// For messages that have a response, it also verifies the response comes back
@@ -300,7 +308,11 @@ namespace AssetProcessorMessagesTests
});
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(AssetProcessorMessages, DISABLED_GetUnresolvedProductReferences_Succeeds)
#else
TEST_F(AssetProcessorMessages, GetUnresolvedProductReferences_Succeeds)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
using namespace AzToolsFramework::AssetDatabase;
@@ -25,6 +25,8 @@
#include <utility>
#include <AzTest/AzTest.h>
namespace UnitTests
{
//using namespace testing;
@@ -478,12 +480,20 @@ namespace UnitTests
TestGetSourcesByPath("dev/", { }, false);
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(SourceFileRelocatorTest, DISABLED_GetSources_MultipleScanFolders_Fails)
#else
TEST_F(SourceFileRelocatorTest, GetSources_MultipleScanFolders_Fails)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
TestGetSourcesByPath("*", { }, false);
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(SourceFileRelocatorTest, DISABLED_GetSources_PartialPath_FailsWithNoResults)
#else
TEST_F(SourceFileRelocatorTest, GetSources_PartialPath_FailsWithNoResults)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
TestGetSourcesByPath("older/*", { }, false);
}
@@ -530,7 +540,11 @@ namespace UnitTests
TestGetSourcesByPath(filePath.toUtf8().constData(), { "folder/file.foo" }, true, true);
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(SourceFileRelocatorTest, DISABLED_GetSources_HaveMetadataDifferentFileCase_AbsolutePath_Succeeds)
#else
TEST_F(SourceFileRelocatorTest, GetSources_HaveMetadataDifferentFileCase_AbsolutePath_Succeeds)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
QDir tempPath(m_tempDir.path());
@@ -900,7 +914,11 @@ namespace UnitTests
ASSERT_FALSE(AZ::IO::FileIOBase::GetInstance()->Exists(filePath.toUtf8().constData()));
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(SourceFileRelocatorTest, DISABLED_Delete_Real_Readonly_Fails)
#else
TEST_F(SourceFileRelocatorTest, Delete_Real_Readonly_Fails)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
QDir tempPath(m_tempDir.path());
@@ -83,15 +83,6 @@ namespace AssetProcessor
ASSERT_EQ(createJobsRequest.GetEnabledPlatformAt(3), AssetBuilderSDK::Platform_OSX);
ASSERT_EQ(createJobsRequest.GetEnabledPlatformAt(4), AssetBuilderSDK::Platform_NONE);
#if defined(TOOLS_SUPPORT_XENIA)
createJobsRequest.m_enabledPlatforms = {
{ "xenia", {}
}
};
ASSERT_EQ(createJobsRequest.GetEnabledPlatformAt(0), AssetBuilderSDK::Platform_XENIA);
ASSERT_EQ(createJobsRequest.GetEnabledPlatformAt(1), AssetBuilderSDK::Platform_NONE);
#endif
createJobsRequest.m_enabledPlatforms = {
{ "pc", {}
}, { "es3", {}
@@ -145,7 +136,6 @@ namespace AssetProcessor
ASSERT_TRUE(createJobsRequest.IsPlatformValid(AssetBuilderSDK::Platform_ES3));
ASSERT_TRUE(createJobsRequest.IsPlatformValid(AssetBuilderSDK::Platform_IOS));
ASSERT_TRUE(createJobsRequest.IsPlatformValid(AssetBuilderSDK::Platform_OSX));
ASSERT_TRUE(createJobsRequest.IsPlatformValid(AssetBuilderSDK::Platform_XENIA));
ASSERT_TRUE(createJobsRequest.IsPlatformValid(AssetBuilderSDK::Platform_PROVO));
ASSERT_TRUE(createJobsRequest.IsPlatformValid(AssetBuilderSDK::Platform_SALEM));
ASSERT_TRUE(createJobsRequest.IsPlatformValid(AssetBuilderSDK::Platform_JASPER));
@@ -14,6 +14,7 @@
#include "native/AssetManager/PathDependencyManager.h"
#include <AzToolsFramework/ToolsFileUtils/ToolsFileUtils.h>
#include <AzTest/AzTest.h>
#include <limits>
@@ -27,7 +28,13 @@ public:
friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies);
friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies_DeferredResolution);
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, DISABLED_AssetProcessed_Impl_MultiplatformDependencies_SourcePath);
#else
friend class GTEST_TEST_CLASS_NAME_(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies_SourcePath);
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, DeleteFolder_SignalsDeleteOfContainedFiles);
friend class GTEST_TEST_CLASS_NAME_(AssetProcessorManagerTest, QueryAbsolutePathDependenciesRecursive_BasicTest);
@@ -69,9 +76,20 @@ public:
friend class GTEST_TEST_CLASS_NAME_(AbsolutePathProductDependencyTest, UnresolvedProductPathDependency_AssetProcessedTwice_ValidatePathDependenciesMap);
friend class GTEST_TEST_CLASS_NAME_(AbsolutePathProductDependencyTest, UnresolvedSourceFileTypeProductPathDependency_DependencyHasNoProductOutput_ValidatePathDependenciesMap);
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, DISABLED_ModtimeSkipping_FileUnchanged_WithoutModtimeSkipping);
#else
friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, ModtimeSkipping_FileUnchanged_WithoutModtimeSkipping);
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, ModtimeSkipping_FileUnchanged);
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, DISABLED_ModtimeSkipping_EnablePlatform_ShouldProcessFilesForPlatform);
#else
friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, ModtimeSkipping_EnablePlatform_ShouldProcessFilesForPlatform);
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, ModtimeSkipping_ModifyFile);
friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, ModtimeSkipping_ModifyFile_AndThenRevert_ProcessesAgain);
friend class GTEST_TEST_CLASS_NAME_(ModtimeScanningTest, ModtimeSkipping_ModifyFilesSameHash_BothProcess);
@@ -2413,7 +2431,11 @@ TEST_F(PathDependencyTest, ChangeDependencies_Existing_ResolveCorrectly)
);
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(PathDependencyTest, DISABLED_MixedPathDependencies_Existing_ResolveCorrectly)
#else
TEST_F(PathDependencyTest, MixedPathDependencies_Existing_ResolveCorrectly)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
using namespace AssetProcessor;
using namespace AssetBuilderSDK;
@@ -2712,7 +2734,11 @@ TEST_F(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDepende
ASSERT_NE(SearchDependencies(dependencyContainer, asset1.m_products[0]), SearchDependencies(dependencyContainer, asset1.m_products[1]));
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(MultiplatformPathDependencyTest, DISABLED_AssetProcessed_Impl_MultiplatformDependencies_SourcePath)
#else
TEST_F(MultiplatformPathDependencyTest, AssetProcessed_Impl_MultiplatformDependencies_SourcePath)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
// One product will be pc, one will be console (order is non-deterministic)
TestAsset asset1("testAsset1");
@@ -4585,7 +4611,11 @@ void ModtimeScanningTest::SetFileContents(QString filePath, QString contents)
file.close();
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(ModtimeScanningTest, DISABLED_ModtimeSkipping_FileUnchanged_WithoutModtimeSkipping)
#else
TEST_F(ModtimeScanningTest, ModtimeSkipping_FileUnchanged_WithoutModtimeSkipping)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
using namespace AzToolsFramework::AssetSystem;
@@ -4614,7 +4644,11 @@ TEST_F(ModtimeScanningTest, ModtimeSkipping_FileUnchanged)
ExpectNoWork();
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(ModtimeScanningTest, DISABLED_ModtimeSkipping_EnablePlatform_ShouldProcessFilesForPlatform)
#else
TEST_F(ModtimeScanningTest, ModtimeSkipping_EnablePlatform_ShouldProcessFilesForPlatform)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
using namespace AzToolsFramework::AssetSystem;
@@ -5118,7 +5152,11 @@ TEST_F(AssetProcessorManagerTest, UpdateSourceFileDependenciesDatabase_WildcardM
dependList.clear();
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(AssetProcessorManagerTest, DISABLED_RemoveSource_RemoveCacheFolderIfEmpty_Ok)
#else
TEST_F(AssetProcessorManagerTest, RemoveSource_RemoveCacheFolderIfEmpty_Ok)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
using namespace AssetProcessor;
using namespace AssetBuilderSDK;
@@ -13,6 +13,8 @@
#include <AzCore/Settings/SettingsRegistryMergeUtils.h>
#include "native/tests/platformconfiguration/platformconfigurationtests.h"
#include <AzTest/AzTest.h>
const char TestAppRoot[] = ":/testdata";
const char EmptyDummyProjectName[] = "EmptyDummyProject";
const char DummyProjectName[] = "DummyProject";
@@ -111,7 +113,6 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Regular_Platforms)
ASSERT_NE(config.GetPlatformByIdentifier(AzToolsFramework::AssetSystem::GetHostAssetPlatform()), nullptr);
ASSERT_NE(config.GetPlatformByIdentifier("es3"), nullptr);
ASSERT_NE(config.GetPlatformByIdentifier("server"), nullptr);
ASSERT_EQ(config.GetPlatformByIdentifier("xenia"), nullptr);
ASSERT_TRUE(config.GetPlatformByIdentifier("es3")->HasTag("mobile"));
ASSERT_TRUE(config.GetPlatformByIdentifier("es3")->HasTag("renderer"));
@@ -431,7 +432,11 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_RegularExcludes)
ASSERT_FALSE(config.IsFileExcluded("blahblah/Levels/blahblahhold/whatever.test"));
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(PlatformConfigurationUnitTests, DISABLED_TestFailReadConfigFile_Recognizers)
#else
TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Recognizers)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
using namespace AzToolsFramework::AssetSystem;
using namespace AssetProcessor;
@@ -530,7 +535,6 @@ TEST_F(PlatformConfigurationUnitTests, TestFailReadConfigFile_Overrides)
ASSERT_NE(config.GetPlatformByIdentifier("es3"), nullptr);
ASSERT_NE(config.GetPlatformByIdentifier("provo"), nullptr);
// this override swaps server with provo in that it turns ON provo, turns off server
ASSERT_EQ(config.GetPlatformByIdentifier("xenia"), nullptr);
ASSERT_EQ(config.GetPlatformByIdentifier("server"), nullptr); // this should be off due to overrides
// there is a rule which only output on server, so that rule should be omitted
@@ -13,9 +13,9 @@
#include <QHash>
#include "native/tests/AssetProcessorTest.h"
#include <AzCore/std/parallel/thread.h>
#include <AzTest/AzTest.h>
using namespace AssetUtilities;
@@ -119,7 +119,11 @@ TEST_F(AssetUtilitiesTest, UpdateToCorrectCase_MissingFile_ReturnsFalse)
EXPECT_FALSE(AssetUtilities::UpdateToCorrectCase(canonicalTempDirPath, fileName));
}
#if AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
TEST_F(AssetUtilitiesTest, DISABLED_UpdateToCorrectCase_ExistingFile_ReturnsTrue_CorrectsCase)
#else
TEST_F(AssetUtilitiesTest, UpdateToCorrectCase_ExistingFile_ReturnsTrue_CorrectsCase)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
{
QTemporaryDir dir;
QDir tempPath(dir.path());
@@ -187,31 +187,31 @@ void MainWindow::Activate()
ui->connectionTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->connectionTreeView, &QTreeView::customContextMenuRequested, this, &MainWindow::OnConnectionContextMenu);
//white list connections
//allowed list connections
connect(m_guiApplicationManager->GetConnectionManager(), &ConnectionManager::FirstTimeAddedToRejctedList, this, &MainWindow::FirstTimeAddedToRejctedList);
connect(m_guiApplicationManager->GetConnectionManager(), &ConnectionManager::SyncWhiteListAndRejectedList, this, &MainWindow::SyncWhiteListAndRejectedList);
connect(ui->whiteListWhiteListedConnectionsListView, &QListView::clicked, this, &MainWindow::OnWhiteListedConnectionsListViewClicked);
ui->whiteListWhiteListedConnectionsListView->setModel(&m_whitelistedAddresses);
connect(ui->whiteListRejectedConnectionsListView, &QListView::clicked, this, &MainWindow::OnRejectedConnectionsListViewClicked);
ui->whiteListRejectedConnectionsListView->setModel(&m_rejectedAddresses);
connect(m_guiApplicationManager->GetConnectionManager(), &ConnectionManager::SyncAllowedListAndRejectedList, this, &MainWindow::SyncAllowedListAndRejectedList);
connect(ui->allowListAllowedListConnectionsListView, &QListView::clicked, this, &MainWindow::OnAllowedListConnectionsListViewClicked);
ui->allowListAllowedListConnectionsListView->setModel(&m_allowedListAddresses);
connect(ui->allowedListRejectedConnectionsListView, &QListView::clicked, this, &MainWindow::OnRejectedConnectionsListViewClicked);
ui->allowedListRejectedConnectionsListView->setModel(&m_rejectedAddresses);
connect(ui->whiteListEnableCheckBox, &QCheckBox::toggled, this, &MainWindow::OnWhiteListCheckBoxToggled);
connect(ui->allowedListEnableCheckBox, &QCheckBox::toggled, this, &MainWindow::OnAllowedListCheckBoxToggled);
connect(ui->whiteListAddHostNameToolButton, &QToolButton::clicked, this, &MainWindow::OnAddHostNameWhiteListButtonClicked);
connect(ui->whiteListAddIPToolButton, &QPushButton::clicked, this, &MainWindow::OnAddIPWhiteListButtonClicked);
connect(ui->allowedListAddHostNameToolButton, &QToolButton::clicked, this, &MainWindow::OnAddHostNameAllowedListButtonClicked);
connect(ui->allowedListAddIPToolButton, &QPushButton::clicked, this, &MainWindow::OnAddIPAllowedListButtonClicked);
connect(ui->whiteListToWhiteListToolButton, &QPushButton::clicked, this, &MainWindow::OnToWhiteListButtonClicked);
connect(ui->whiteListToRejectedListToolButton, &QToolButton::clicked, this, &MainWindow::OnToRejectedListButtonClicked);
connect(ui->allowedListToAllowedListToolButton, &QPushButton::clicked, this, &MainWindow::OnToAllowedListButtonClicked);
connect(ui->allowedListToRejectedListToolButton, &QToolButton::clicked, this, &MainWindow::OnToRejectedListButtonClicked);
//set the input validator for ip addresses on the add address line edit
QRegExp validHostName("^((?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|\\b-){0,61}[0-9A-Za-z])?(?:\\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|\\b-){0,61}[0-9A-Za-z])?)*\\.?)$");
QRegExp validIP("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/([0-9]|[1-2][0-9]|3[0-2]))?$|^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))?$");
QRegExpValidator* hostNameValidator = new QRegExpValidator(validHostName, this);
ui->whiteListAddHostNameLineEdit->setValidator(hostNameValidator);
ui->allowedListAddHostNameLineEdit->setValidator(hostNameValidator);
QRegExpValidator* ipValidator = new QRegExpValidator(validIP, this);
ui->whiteListAddIPLineEdit->setValidator(ipValidator);
ui->allowedListAddIPLineEdit->setValidator(ipValidator);
//Job view
m_jobSortFilterProxy->setSourceModel(m_jobsModel);
@@ -555,65 +555,65 @@ void MainWindow::OnAddConnection(bool /*checked*/)
m_guiApplicationManager->GetConnectionManager()->addUserConnection();
}
void MainWindow::OnWhiteListedConnectionsListViewClicked()
void MainWindow::OnAllowedListConnectionsListViewClicked()
{
ui->whiteListRejectedConnectionsListView->clearSelection();
ui->allowedListRejectedConnectionsListView->clearSelection();
}
void MainWindow::OnRejectedConnectionsListViewClicked()
{
ui->whiteListWhiteListedConnectionsListView->clearSelection();
ui->allowListAllowedListConnectionsListView->clearSelection();
}
void MainWindow::OnWhiteListCheckBoxToggled()
void MainWindow::OnAllowedListCheckBoxToggled()
{
if (!ui->whiteListEnableCheckBox->isChecked())
if (!ui->allowedListEnableCheckBox->isChecked())
{
//warn this is not safe
if(QMessageBox::Ok == QMessageBox::warning(this, tr("!!!WARNING!!!"), tr("Turning off white listing poses a significant security risk as it would allow any device to connect to your asset processor and that device will have READ/WRITE access to the Asset Processors file system. Only do this if you sure you know what you are doing and accept the risks."),
if(QMessageBox::Ok == QMessageBox::warning(this, tr("!!!WARNING!!!"), tr("Turning off allowed listing poses a significant security risk as it would allow any device to connect to your asset processor and that device will have READ/WRITE access to the Asset Processors file system. Only do this if you sure you know what you are doing and accept the risks."),
QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel))
{
ui->whiteListRejectedConnectionsListView->clearSelection();
ui->whiteListWhiteListedConnectionsListView->clearSelection();
ui->whiteListAddHostNameLineEdit->setEnabled(false);
ui->whiteListAddHostNameToolButton->setEnabled(false);
ui->whiteListAddIPLineEdit->setEnabled(false);
ui->whiteListAddIPToolButton->setEnabled(false);
ui->whiteListWhiteListedConnectionsListView->setEnabled(false);
ui->whiteListRejectedConnectionsListView->setEnabled(false);
ui->whiteListToWhiteListToolButton->setEnabled(false);
ui->whiteListToRejectedListToolButton->setEnabled(false);
ui->allowedListRejectedConnectionsListView->clearSelection();
ui->allowListAllowedListConnectionsListView->clearSelection();
ui->allowedListAddHostNameLineEdit->setEnabled(false);
ui->allowedListAddHostNameToolButton->setEnabled(false);
ui->allowedListAddIPLineEdit->setEnabled(false);
ui->allowedListAddIPToolButton->setEnabled(false);
ui->allowListAllowedListConnectionsListView->setEnabled(false);
ui->allowedListRejectedConnectionsListView->setEnabled(false);
ui->allowedListToAllowedListToolButton->setEnabled(false);
ui->allowedListToRejectedListToolButton->setEnabled(false);
}
else
{
ui->whiteListEnableCheckBox->setChecked(true);
ui->allowedListEnableCheckBox->setChecked(true);
}
}
else
{
ui->whiteListAddHostNameLineEdit->setEnabled(true);
ui->whiteListAddHostNameToolButton->setEnabled(true);
ui->whiteListAddIPLineEdit->setEnabled(true);
ui->whiteListAddIPToolButton->setEnabled(true);
ui->whiteListWhiteListedConnectionsListView->setEnabled(true);
ui->whiteListRejectedConnectionsListView->setEnabled(true);
ui->whiteListToWhiteListToolButton->setEnabled(true);
ui->whiteListToRejectedListToolButton->setEnabled(true);
ui->allowedListAddHostNameLineEdit->setEnabled(true);
ui->allowedListAddHostNameToolButton->setEnabled(true);
ui->allowedListAddIPLineEdit->setEnabled(true);
ui->allowedListAddIPToolButton->setEnabled(true);
ui->allowListAllowedListConnectionsListView->setEnabled(true);
ui->allowedListRejectedConnectionsListView->setEnabled(true);
ui->allowedListToAllowedListToolButton->setEnabled(true);
ui->allowedListToRejectedListToolButton->setEnabled(true);
}
m_guiApplicationManager->GetConnectionManager()->WhiteListingEnabled(ui->whiteListEnableCheckBox->isChecked());
m_guiApplicationManager->GetConnectionManager()->AllowedListingEnabled(ui->allowedListEnableCheckBox->isChecked());
}
void MainWindow::OnAddHostNameWhiteListButtonClicked()
void MainWindow::OnAddHostNameAllowedListButtonClicked()
{
QString text = ui->whiteListAddHostNameLineEdit->text();
const QRegExpValidator *hostnameValidator = static_cast<const QRegExpValidator *>(ui->whiteListAddHostNameLineEdit->validator());
QString text = ui->allowedListAddHostNameLineEdit->text();
const QRegExpValidator *hostnameValidator = static_cast<const QRegExpValidator *>(ui->allowedListAddHostNameLineEdit->validator());
int pos;
QValidator::State state = hostnameValidator->validate(text, pos);
if (state == QValidator::Acceptable)
{
auto lineEdit = ui->whiteListAddHostNameLineEdit;
m_guiApplicationManager->GetConnectionManager()->AddWhiteListedAddress(text);
auto lineEdit = ui->allowedListAddHostNameLineEdit;
m_guiApplicationManager->GetConnectionManager()->AddAddressToAllowedList(text);
lineEdit->clear();
// Clear error state set in LineEdit.
lineEdit->setProperty(AzQtComponents::HasError, false);
@@ -625,16 +625,16 @@ void MainWindow::OnAddHostNameWhiteListButtonClicked()
}
}
void MainWindow::OnAddIPWhiteListButtonClicked()
void MainWindow::OnAddIPAllowedListButtonClicked()
{
QString text = ui->whiteListAddIPLineEdit->text();
const QRegExpValidator *ipValidator = static_cast<const QRegExpValidator *>(ui->whiteListAddIPLineEdit->validator());
QString text = ui->allowedListAddIPLineEdit->text();
const QRegExpValidator *ipValidator = static_cast<const QRegExpValidator *>(ui->allowedListAddIPLineEdit->validator());
int pos;
QValidator::State state = ipValidator->validate(text, pos);
if (state== QValidator::Acceptable)
{
auto lineEdit = ui->whiteListAddIPLineEdit;
m_guiApplicationManager->GetConnectionManager()->AddWhiteListedAddress(text);
auto lineEdit = ui->allowedListAddIPLineEdit;
m_guiApplicationManager->GetConnectionManager()->AddAddressToAllowedList(text);
lineEdit->clear();
// Clear error state set in LineEdit.
lineEdit->setProperty(AzQtComponents::HasError, false);
@@ -648,23 +648,23 @@ void MainWindow::OnAddIPWhiteListButtonClicked()
void MainWindow::OnToRejectedListButtonClicked()
{
QModelIndexList indices = ui->whiteListWhiteListedConnectionsListView->selectionModel()->selectedIndexes();
QModelIndexList indices = ui->allowListAllowedListConnectionsListView->selectionModel()->selectedIndexes();
if(!indices.isEmpty() && indices.first().isValid())
{
QString itemText = indices.first().data(Qt::DisplayRole).toString();
m_guiApplicationManager->GetConnectionManager()->RemoveWhiteListedAddress(itemText);
m_guiApplicationManager->GetConnectionManager()->RemoveAddressFromAllowedList(itemText);
m_guiApplicationManager->GetConnectionManager()->AddRejectedAddress(itemText, true);
}
}
void MainWindow::OnToWhiteListButtonClicked()
void MainWindow::OnToAllowedListButtonClicked()
{
QModelIndexList indices = ui->whiteListRejectedConnectionsListView->selectionModel()->selectedIndexes();
QModelIndexList indices = ui->allowedListRejectedConnectionsListView->selectionModel()->selectedIndexes();
if (!indices.isEmpty() && indices.first().isValid())
{
QString itemText = indices.front().data(Qt::DisplayRole).toString();
m_guiApplicationManager->GetConnectionManager()->RemoveRejectedAddress(itemText);
m_guiApplicationManager->GetConnectionManager()->AddWhiteListedAddress(itemText);
m_guiApplicationManager->GetConnectionManager()->AddAddressToAllowedList(itemText);
}
}
@@ -715,9 +715,9 @@ void MainWindow::ShowWindow()
}
void MainWindow::SyncWhiteListAndRejectedList(QStringList whiteList, QStringList rejectedList)
void MainWindow::SyncAllowedListAndRejectedList(QStringList allowedList, QStringList rejectedList)
{
m_whitelistedAddresses.setStringList(whiteList);
m_allowedListAddresses.setStringList(allowedList);
m_rejectedAddresses.setStringList(rejectedList);
}
@@ -725,7 +725,7 @@ void MainWindow::FirstTimeAddedToRejctedList(QString ipAddress)
{
QMessageBox* msgBox = new QMessageBox(this);
msgBox->setText(tr("!!!Rejected Connection!!!"));
msgBox->setInformativeText(ipAddress + tr(" tried to connect and was rejected because it was not on the white list. If you want this connection to be allowed go to connections tab and add it to white list."));
msgBox->setInformativeText(ipAddress + tr(" tried to connect and was rejected because it was not on the allowed list. If you want this connection to be allowed go to connections tab and add it to allowed list."));
msgBox->setStandardButtons(QMessageBox::Ok);
msgBox->setDefaultButton(QMessageBox::Ok);
msgBox->setWindowModality(Qt::NonModal);
@@ -107,7 +107,7 @@ public:
public Q_SLOTS:
void ShowWindow();
void SyncWhiteListAndRejectedList(QStringList whiteList, QStringList rejectedList);
void SyncAllowedListAndRejectedList(QStringList allowedList, QStringList rejectedList);
void FirstTimeAddedToRejctedList(QString ipAddress);
void SaveLogPanelState();
void OnAssetProcessorStatusChanged(const AssetProcessor::AssetProcessorStatusEntry entry);
@@ -163,17 +163,17 @@ private:
void OnConnectionSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
QStringListModel m_rejectedAddresses;
QStringListModel m_whitelistedAddresses;
QStringListModel m_allowedListAddresses;
void OnWhiteListedConnectionsListViewClicked();
void OnAllowedListConnectionsListViewClicked();
void OnRejectedConnectionsListViewClicked();
void OnWhiteListCheckBoxToggled();
void OnAllowedListCheckBoxToggled();
void OnAddHostNameWhiteListButtonClicked();
void OnAddIPWhiteListButtonClicked();
void OnAddHostNameAllowedListButtonClicked();
void OnAddIPAllowedListButtonClicked();
void OnToWhiteListButtonClicked();
void OnToAllowedListButtonClicked();
void OnToRejectedListButtonClicked();
void UpdateJobLogView(QModelIndex selectedIndex);
@@ -917,11 +917,11 @@
<widget class="AzQtComponents::TableView" name="connectionTreeView"/>
</item>
<item>
<widget class="QFrame" name="whiteListOuterFrame">
<widget class="QFrame" name="allowedListOuterFrame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<layout class="QVBoxLayout" name="whiteListVerticalLayout">
<layout class="QVBoxLayout" name="allowedListVerticalLayout">
<property name="spacing">
<number>0</number>
</property>
@@ -938,8 +938,8 @@
<number>0</number>
</property>
<item>
<widget class="QWidget" name="whiteListTopBarWidget" native="true">
<layout class="QHBoxLayout" name="whiteListHorizontalBar">
<widget class="QWidget" name="allowedListTopBarWidget" native="true">
<layout class="QHBoxLayout" name="allowedListHorizontalBar">
<property name="spacing">
<number>6</number>
</property>
@@ -956,12 +956,12 @@
<number>4</number>
</property>
<item>
<widget class="QCheckBox" name="whiteListEnableCheckBox">
<widget class="QCheckBox" name="allowedListEnableCheckBox">
<property name="toolTip">
<string>Enable or Disable white listing. White listing is a security feature which limits what can connect to the asset processor.</string>
<string>Enable or Disable allowed listing. Allowed listing is a security feature which limits what can connect to the asset processor.</string>
</property>
<property name="text">
<string>Enable white listing</string>
<string>Enable allowed listing</string>
</property>
<property name="checked">
<bool>true</bool>
@@ -969,7 +969,7 @@
</widget>
</item>
<item>
<spacer name="whiteListBarSpacer">
<spacer name="allowedListBarSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -982,7 +982,7 @@
</spacer>
</item>
<item>
<widget class="Line" name="whiteListSeparatorLine">
<widget class="Line" name="allowedListSeparatorLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -992,8 +992,8 @@
</widget>
</item>
<item>
<widget class="QWidget" name="whiteListBottomBarWidget" native="true">
<layout class="QHBoxLayout" name="whiteListHorizontalBar2">
<widget class="QWidget" name="allowedListBottomBarWidget" native="true">
<layout class="QHBoxLayout" name="allowedListHorizontalBar2">
<property name="leftMargin">
<number>4</number>
</property>
@@ -1007,9 +1007,9 @@
<number>4</number>
</property>
<item>
<widget class="QLabel" name="whiteListAddHostNameLabel">
<widget class="QLabel" name="allowedListAddHostNameLabel">
<property name="toolTip">
<string>White list a hostname. EX. MyComputer321</string>
<string>Allowed list a hostname. EX. MyComputer321</string>
</property>
<property name="text">
<string>Add Host Name</string>
@@ -1017,12 +1017,12 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="whiteListAddHostNameLineEdit"/>
<widget class="QLineEdit" name="allowedListAddHostNameLineEdit"/>
</item>
<item>
<widget class="QToolButton" name="whiteListAddHostNameToolButton">
<widget class="QToolButton" name="allowedListAddHostNameToolButton">
<property name="toolTip">
<string>Add the hostname to the white list.</string>
<string>Add the hostname to the allowed list.</string>
</property>
<property name="text">
<string/>
@@ -1037,7 +1037,7 @@
</widget>
</item>
<item>
<spacer name="whiteListHorizontalBar2Spacer">
<spacer name="allowedListHorizontalBar2Spacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -1050,9 +1050,9 @@
</spacer>
</item>
<item>
<widget class="QLabel" name="whiteListAddIPLabel">
<widget class="QLabel" name="allowedListAddIPLabel">
<property name="toolTip">
<string>White list an ipv4 or ipv6 address with or without a CIDR range. EX. 192.168.0.20 or 192.168.0.0/24 or 2001:db8:85a3:8d3:1319:8a2e:370:7348 or 2001:db8:85a3:8d3:1319:8a2e:370:7348/32</string>
<string>Allowed list an ipv4 or ipv6 address with or without a CIDR range. EX. 192.168.0.20 or 192.168.0.0/24 or 2001:db8:85a3:8d3:1319:8a2e:370:7348 or 2001:db8:85a3:8d3:1319:8a2e:370:7348/32</string>
</property>
<property name="text">
<string>Add IP Address</string>
@@ -1060,12 +1060,12 @@
</widget>
</item>
<item>
<widget class="QLineEdit" name="whiteListAddIPLineEdit"/>
<widget class="QLineEdit" name="allowedListAddIPLineEdit"/>
</item>
<item>
<widget class="QToolButton" name="whiteListAddIPToolButton">
<widget class="QToolButton" name="allowedListAddIPToolButton">
<property name="toolTip">
<string>Add the ip address to the white list.</string>
<string>Add the ip address to the allowed list.</string>
</property>
<property name="text">
<string/>
@@ -1083,9 +1083,9 @@
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="whiteListHorizontalBar3">
<layout class="QHBoxLayout" name="allowedListHorizontalBar3">
<item>
<widget class="Line" name="whiteListLine">
<widget class="Line" name="allowedListLine">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -1094,22 +1094,22 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="whiteListHorizontalLabelsLayout">
<layout class="QHBoxLayout" name="allowedListHorizontalLabelsLayout">
<property name="leftMargin">
<number>4</number>
</property>
<item>
<widget class="QLabel" name="whiteListWhiteListedConnnectionListLabel">
<widget class="QLabel" name="allowedListAllowedListedConnnectionListLabel">
<property name="toolTip">
<string>White listed connection are addresses, ranges and name that will be allowed to connect to the asset processor.</string>
<string>Allowed listed connection are addresses, ranges and name that will be allowed to connect to the asset processor.</string>
</property>
<property name="text">
<string>White Listed Connections</string>
<string>Allowed Listed Connections</string>
</property>
</widget>
</item>
<item>
<spacer name="whiteListHorizontalLabelSpacer1">
<spacer name="allowedListHorizontalLabelSpacer1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -1122,7 +1122,7 @@
</spacer>
</item>
<item>
<widget class="QLabel" name="whiteListRejectedConnectionListLabel">
<widget class="QLabel" name="allowedListRejectedConnectionListLabel">
<property name="toolTip">
<string>Rejected connections are addresses that failed to connect to the asset processor.</string>
</property>
@@ -1132,7 +1132,7 @@
</widget>
</item>
<item>
<spacer name="whiteListHorizontalLabelSpacer2">
<spacer name="allowedListHorizontalLabelSpacer2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@@ -1147,7 +1147,7 @@
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="whiteListHorizontalViewsLayout">
<layout class="QHBoxLayout" name="allowedListHorizontalViewsLayout">
<property name="spacing">
<number>9</number>
</property>
@@ -1164,16 +1164,16 @@
<number>4</number>
</property>
<item>
<widget class="QListView" name="whiteListWhiteListedConnectionsListView">
<widget class="QListView" name="allowListAllowedListConnectionsListView">
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="whiteListButtonVerticalLayout">
<layout class="QVBoxLayout" name="allowedListButtonVerticalLayout">
<item>
<spacer name="whiteListVerticalSpacer1">
<spacer name="allowedListVerticalSpacer1">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@@ -1186,9 +1186,9 @@
</spacer>
</item>
<item>
<widget class="QToolButton" name="whiteListToWhiteListToolButton">
<widget class="QToolButton" name="allowedListToAllowedListToolButton">
<property name="toolTip">
<string>Move a entry from rejected to the white list.</string>
<string>Move a entry from rejected to the allowed list.</string>
</property>
<property name="text">
<string/>
@@ -1203,7 +1203,7 @@
</widget>
</item>
<item>
<widget class="QToolButton" name="whiteListToRejectedListToolButton">
<widget class="QToolButton" name="allowedListToRejectedListToolButton">
<property name="toolTip">
<string>Remove an entry from the whtie list.</string>
</property>
@@ -1220,7 +1220,7 @@
</widget>
</item>
<item>
<spacer name="whiteListVerticalSpacer2">
<spacer name="allowedListVerticalSpacer2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@@ -1235,7 +1235,7 @@
</layout>
</item>
<item>
<widget class="QListView" name="whiteListRejectedConnectionsListView">
<widget class="QListView" name="allowedListRejectedConnectionsListView">
<property name="showDropIndicator" stdset="0">
<bool>false</bool>
</property>
@@ -21,6 +21,7 @@
#include "native/FileWatcher/FileWatcher.h"
#include "native/unittests/MockConnectionHandler.h"
#include <AzTest/AzTest.h>
#include <QCoreApplication>
@@ -39,11 +40,14 @@ namespace AssetProcessor
: AssetProcessorManager(config, parent)
{}
friend class AssetProcessorManagerUnitTests;
friend class AssetProcessorManagerUnitTests_ScanFolders;
#if !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
friend class AssetProcessorManagerUnitTests;
friend class AssetProcessorManagerUnitTests_JobKeys;
friend class AssetProcessorManagerUnitTests_JobDependencies_Fingerprint;
friend class AssetProcessorManagerUnitTests_CheckOutputFolders;
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
public:
using GetRelativeProductPathFromFullSourceOrProductPathRequest = AzFramework::AssetSystem::GetRelativeProductPathFromFullSourceOrProductPathRequest;
@@ -54,11 +58,15 @@ namespace AssetProcessor
REGISTER_UNIT_TEST(AssetProcessorManagerUnitTests)
REGISTER_UNIT_TEST(AssetProcessorManagerUnitTests_ScanFolders)
#if !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
REGISTER_UNIT_TEST(AssetProcessorManagerUnitTests)
REGISTER_UNIT_TEST(AssetProcessorManagerUnitTests_JobKeys)
REGISTER_UNIT_TEST(AssetProcessorManagerUnitTests_JobDependencies_Fingerprint)
REGISTER_UNIT_TEST(AssetProcessorManagerUnitTests_CheckOutputFolders)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
namespace
{
@@ -45,7 +45,7 @@ Q_SIGNALS:
virtual void StartTest() override;
};
class AssetProcessorManagerUnitTests_CheckOutputFolders
class AssetProcessorManagerUnitTests_CheckOutputFolders
: public UnitTestRun
{
Q_OBJECT
@@ -12,6 +12,7 @@
#include "FileWatcherUnitTests.h"
#include "native/FileWatcher/FileWatcher.h"
#include "native/AssetManager/assetProcessorManager.h"
#include <AzTest/AzTest.h>
#include <QCoreApplication>
using namespace AssetProcessor;
@@ -305,4 +306,6 @@ void FileWatcherUnitTestRunner::StartTest()
Q_EMIT UnitTestPassed();
}
#if !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
REGISTER_UNIT_TEST(FileWatcherUnitTestRunner)
#endif // !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
@@ -10,6 +10,7 @@
*
*/
#include "RCcontrollerUnitTests.h"
#include <AzTest/AzTest.h>
#include <QCoreApplication>
#if defined(AZ_PLATFORM_LINUX)
@@ -770,7 +771,7 @@ void RCcontrollerUnitTests::RunRCControllerTests()
Q_EMIT UnitTestPassed();
}
#if !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
REGISTER_UNIT_TEST(RCcontrollerUnitTests)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
@@ -19,6 +19,7 @@
#include "native/utilities/ByteArrayStream.h"
#include <AzCore/Component/Entity.h>
#include <AzCore/Jobs/Job.h>
#include <AzTest/AzTest.h>
#include <QThread>
@@ -65,7 +66,9 @@ namespace AssetProcessor
};
}
#if !AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
REGISTER_UNIT_TEST(UtilitiesUnitTests)
#endif // AZ_TRAIT_DISABLE_FAILED_ASSET_PROCESSOR_TESTS
void UtilitiesUnitTests::StartTest()
{
@@ -674,7 +674,7 @@ void GUIApplicationManager::FileChanged(QString path)
if (m_connectionManager)
{
m_connectionManager->UpdateWhiteListFromBootStrap();
m_connectionManager->UpdateAllowedListFromBootStrap();
}
// Re-merge the Bootstrap.cfg into the SettingsRegistry
@@ -600,7 +600,7 @@ to ensure that the address is correct. Asset Processor won't be running in serve
return {};
}
QString ReadWhitelistFromSettingsRegistry(QString initialFolder /*= QString()*/)
QString ReadAllowedlistFromSettingsRegistry(QString initialFolder /*= QString()*/)
{
if (initialFolder.isEmpty())
{
@@ -613,14 +613,14 @@ to ensure that the address is correct. Asset Processor won't be running in serve
initialFolder = assetRoot.absolutePath();
}
constexpr size_t BufferSize = AZ_ARRAY_SIZE(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + AZStd::char_traits<char>::length("/white_list");
AZStd::fixed_string<BufferSize> whiteListKey{ AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey };
whiteListKey += "/white_list";
constexpr size_t BufferSize = AZ_ARRAY_SIZE(AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey) + AZStd::char_traits<char>::length("/allowed_list");
AZStd::fixed_string<BufferSize> allowedListKey{ AZ::SettingsRegistryMergeUtils::BootstrapSettingsRootKey };
allowedListKey += "/allowed_list";
AZ::SettingsRegistryInterface::FixedValueString whiteListIp;
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry && settingsRegistry->Get(whiteListIp, whiteListKey))
AZ::SettingsRegistryInterface::FixedValueString allowedListIp;
if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry && settingsRegistry->Get(allowedListIp, allowedListKey))
{
return QString::fromUtf8(whiteListIp.c_str(), aznumeric_cast<int>(whiteListIp.size()));
return QString::fromUtf8(allowedListIp.c_str(), aznumeric_cast<int>(allowedListIp.size()));
}
return {};
@@ -651,7 +651,7 @@ to ensure that the address is correct. Asset Processor won't be running in serve
return {};
}
bool WriteWhitelistToBootstrap(QStringList newWhiteList)
bool WriteAllowedlistToBootstrap(QStringList newAllowedList)
{
QDir assetRoot;
ComputeAssetRoot(assetRoot);
@@ -669,21 +669,21 @@ to ensure that the address is correct. Asset Processor won't be running in serve
return false;
}
// regexp that matches either the beginning of the file, some whitespace, and white_list, or,
// matches a newline, then whitespace, then white_list it will not match comments.
QRegExp whiteListPattern("(^|\\n)\\s*white_list\\s*=\\s*(.+)", Qt::CaseInsensitive, QRegExp::RegExp);
// regexp that matches either the beginning of the file, some whitespace, and allowed_list, or,
// matches a newline, then whitespace, then allowed_list it will not match comments.
QRegExp allowedListPattern("(^|\\n)\\s*allowed_list\\s*=\\s*(.+)", Qt::CaseInsensitive, QRegExp::RegExp);
//read the file line by line and try to find the white_list line
QString readWhiteList;
QString whiteListline;
//read the file line by line and try to find the allowed_list line
QString readAllowedList;
QString allowedListline;
while (!bootstrapFile.atEnd())
{
QString contents(bootstrapFile.readLine());
int matchIdx = whiteListPattern.indexIn(contents);
int matchIdx = allowedListPattern.indexIn(contents);
if (matchIdx != -1)
{
whiteListline = contents;
readWhiteList = whiteListPattern.cap(2);
allowedListline = contents;
readAllowedList = allowedListPattern.cap(2);
break;
}
}
@@ -694,15 +694,15 @@ to ensure that the address is correct. Asset Processor won't be running in serve
fileContents = bootstrapFile.readAll();
bootstrapFile.close();
//format the new white list
QString formattedNewWhiteList = newWhiteList.join(", ");
//format the new allowed list
QString formattedNewAllowedList = newAllowedList.join(", ");
//if we didn't find a white_list entry then append one
if (whiteListline.isEmpty())
//if we didn't find a allowed_list entry then append one
if (allowedListline.isEmpty())
{
fileContents.append("\nwhite_list = " + formattedNewWhiteList + "\n");
fileContents.append("\nallowed_list = " + formattedNewAllowedList + "\n");
}
else if (QString::compare(formattedNewWhiteList, readWhiteList, Qt::CaseInsensitive) == 0)
else if (QString::compare(formattedNewAllowedList, readAllowedList, Qt::CaseInsensitive) == 0)
{
// no need to update, they match
return true;
@@ -710,7 +710,7 @@ to ensure that the address is correct. Asset Processor won't be running in serve
else
{
//Replace the found line with a new one
fileContents.replace(whiteListline, "white_list = " + formattedNewWhiteList + "\n");
fileContents.replace(allowedListline, "allowed_list = " + formattedNewAllowedList + "\n");
}
// Make the bootstrap file writable
@@ -104,14 +104,14 @@ namespace AssetUtilities
//! force=true is supplied
QString ComputeGameName(QString gameNameOverride = QString(), bool force = false);
//! Reads the white list directly from the bootstrap file
QString ReadWhitelistFromSettingsRegistry(QString initialFolder = QString());
//! Reads the allowed list directly from the bootstrap file
QString ReadAllowedlistFromSettingsRegistry(QString initialFolder = QString());
//! Reads the white list directly from the bootstrap file
//! Reads the allowed list directly from the bootstrap file
QString ReadRemoteIpFromSettingsRegistry(QString initialFolder = QString());
//! Writes the white list directly to the bootstrap file
bool WriteWhitelistToBootstrap(QStringList whiteList);
//! Writes the allowed list directly to the bootstrap file
bool WriteAllowedlistToBootstrap(QStringList allowedList);
//! Writes the remote ip directly to the bootstrap file
bool WriteRemoteIpToBootstrap(QString remoteIp);
@@ -12,10 +12,6 @@ tags=tools,renderer
[Platform server]
tags=server
; we define an xenia platform in order to make sure that it does NOT show up anywhere
[Platform xenia]
tags=console,renderer
; for the purposes of this test, we enable only server and es3, but we make sure the CURRENT_PLATFORM is auto enabled.
[Platforms]
@@ -23,7 +19,6 @@ tags=console,renderer
es3=enabled
;ios=enabled
;osx_gl=enabled
;xenia=enabled
;provo=enabled
server=enabled
@@ -76,8 +71,6 @@ params=defaultparams
server=skip
; es3 should have this overridden
es3=mobile
; xenia is allowed here but should be skipped
xenia=copy
; host should have defaultparams
; make sure priority is used.
priority=5
+1 -1
View File
@@ -29,5 +29,5 @@ add_subdirectory(DeltaCataloger)
add_subdirectory(SerializeContextTools)
add_subdirectory(AssetBundler)
add_subdirectory(GridHub)
add_subdirectory(Woodpecker)
add_subdirectory(Standalone)
add_subdirectory(TestImpactFramework)
@@ -250,8 +250,6 @@ bool CCrySimpleJobCompile::Compile(const TiXmlElement* pElement, std::vector<uin
"METAL", SEnviropment::m_METAL_HLSLcc
},{
"ORBIS", SEnviropment::m_Orbis_DXC
},{
"DURANGO", SEnviropment::m_Durango_FXC
},{
"JASPER", SEnviropment::m_Jasper_FXC
}
@@ -457,10 +455,6 @@ bool CCrySimpleJobCompile::Compile(const TiXmlElement* pElement, std::vector<uin
AZStd::string hardwareTarget;
#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS)
#if defined(TOOLS_SUPPORT_XENIA)
#define AZ_RESTRICTED_SECTION CRYSIMPLEJOBCOMPILE_CPP_SECTION_1
#include AZ_RESTRICTED_FILE_EXPLICIT(CrySimpleJobCompile_cpp, xenia)
#endif
#if defined(TOOLS_SUPPORT_JASPER)
#define AZ_RESTRICTED_SECTION CRYSIMPLEJOBCOMPILE_CPP_SECTION_1
#include AZ_RESTRICTED_FILE_EXPLICIT(CrySimpleJobCompile_cpp, jasper)
@@ -113,7 +113,6 @@ SEnviropment& SEnviropment::Instance()
// Shader Compilers ID
// NOTE: Values must be in sync with CShaderSrv::GetShaderCompilerName() function in the engine side.
const char* SEnviropment::m_Orbis_DXC = "Orbis_DXC";
const char* SEnviropment::m_Durango_FXC = "Durango_FXC";
const char* SEnviropment::m_Jasper_FXC = "Jasper_FXC";
const char* SEnviropment::m_D3D11_FXC = "D3D11_FXC";
const char* SEnviropment::m_GLSL_HLSLcc = "GLSL_HLSLcc";
@@ -126,7 +125,6 @@ void SEnviropment::InitializePlatformAttributes()
// Initialize valid Plaforms
// NOTE: Values must be in sync with CShaderSrv::GetPlatformName() function in the engine side.
m_Platforms.insert("Orbis");
m_Platforms.insert("Durango");
m_Platforms.insert("Nx");
m_Platforms.insert("PC");
m_Platforms.insert("Mac");
@@ -138,7 +136,6 @@ void SEnviropment::InitializePlatformAttributes()
// Initialize valid Shader Languages
// NOTE: Values must be in sync with GetShaderLanguageName() function in the engine side.
m_ShaderLanguages.insert("Orbis");
m_ShaderLanguages.insert("Durango");
m_ShaderLanguages.insert("D3D11");
m_ShaderLanguages.insert("METAL");
m_ShaderLanguages.insert("GL4");
@@ -153,10 +150,6 @@ void SEnviropment::InitializePlatformAttributes()
// Initialize valid Shader Compilers ID and Executables.
// Intentionally put a space after the executable name so that attackers can't try to change the executable name that we are going to run.
#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS)
#if defined(TOOLS_SUPPORT_XENIA)
#define AZ_RESTRICTED_SECTION CRYSIMPLESERVER_CPP_SECTION_2
#include AZ_RESTRICTED_FILE_EXPLICIT(CrySimpleServer_cpp, xenia)
#endif
#if defined(TOOLS_SUPPORT_JASPER)
#define AZ_RESTRICTED_SECTION CRYSIMPLESERVER_CPP_SECTION_2
#include AZ_RESTRICTED_FILE_EXPLICIT(CrySimpleServer_cpp, jasper)
@@ -394,10 +387,6 @@ void CompileJob::Process()
}
#if defined(AZ_TOOLS_EXPAND_FOR_RESTRICTED_PLATFORMS)
#if defined(TOOLS_SUPPORT_XENIA)
#define AZ_RESTRICTED_SECTION CRYSIMPLESERVER_CPP_SECTION_1
#include AZ_RESTRICTED_FILE_EXPLICIT(CrySimpleServer_cpp, xenia)
#endif
#if defined(TOOLS_SUPPORT_JASPER)
#define AZ_RESTRICTED_SECTION CRYSIMPLESERVER_CPP_SECTION_1
#include AZ_RESTRICTED_FILE_EXPLICIT(CrySimpleServer_cpp, jasper)
@@ -69,7 +69,6 @@ public:
// Shader Compilers ID
static const char* m_Orbis_DXC;
static const char* m_Durango_FXC;
static const char* m_Jasper_FXC;
static const char* m_D3D11_FXC;
static const char* m_GLSL_HLSLcc;
@@ -142,9 +142,6 @@ public:
SEnviropment::Instance().m_RunAsRoot = (runAsRoot == 1);
}
#if defined(TOOLS_SUPPORT_XENIA)
#include AZ_RESTRICTED_FILE_EXPLICIT(CrySCompileServer_cpp, xenia)
#endif
#if defined(TOOLS_SUPPORT_JASPER)
#include AZ_RESTRICTED_FILE_EXPLICIT(CrySCompileServer_cpp, jasper)
#endif
-3
View File
@@ -37,7 +37,4 @@ ly_add_target(
3rdParty::Qt::Widgets
AZ::AzCore
AZ::GridMate
COMPILE_DEFINITIONS
PRIVATE
GRIDMATE_FOR_TOOLS
)
+2 -2
View File
@@ -621,8 +621,8 @@ int main(int argc, char *argv[])
{
bool failSilently = false;
// We are laucnhing this from Woodpecker all the time.
// When launching from Woodpecker, we don't want to show
// We are launching this from application all the time.
// When launching from the application, we don't want to show
// any of our error messages, which might be useful at other times.
// So, it passes along this fail_silently flag which lets us suppress
// our messages without disrupting any other flow.
@@ -1,60 +0,0 @@
#!/bin/bash
#
#
# 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.
#
# this script modifies a single app, passed in, on the command line, to use @rpath dirs for Qt libs
# you are expected to pass in the executable name on the command line as the first argument
# you are expected to set QTDIR.
# it works by searching all frameworks in QtDir/lib and seeing if your app has a reference to it
# if it does, it replaces that reference with a relative-path reference instead.
NEWLIBPATH="@rpath"
ORIGINALLIBPATH=${QTDIR}/lib
if [ -z "$1" ]; then
echo "Please input the application file to modify"
exit 1
fi
if [ -z "${QTDIR}" ]; then
echo "QTDIR IS NOT SET. PLease set QTDIR to the root of your Qt platform install, usually Qt/VersionNumber/clang_64"
exit 1
fi
if [ ! -d "$QTDIR" ]; then
echo "QTDIR does not appear to point at a directory ,currently its set to ${QTDIR}"
exit 1
fi
echo changebinary_rpaths.sh: Remapping paths in $1 to be rpath instead.
# for each original framework, amend all frameworks in the target folder:
ORIGINAL_LIBS=${ORIGINALLIBPATH}/*.framework
for ORIGINAL_LIB in ${ORIGINAL_LIBS} ; do
BIN_BASE_NAME=$(basename "${ORIGINALLIBPATH}/${ORIGINAL_LIB}" .framework)
ORIGINAL_BINARY_NAME=`otool -DX "${ORIGINALLIBPATH}/${BIN_BASE_NAME}.framework/${BIN_BASE_NAME}"`
NEWTARGETID=${NEWLIBPATH}/${BIN_BASE_NAME}.framework/${BIN_BASE_NAME}
# uncomment to debug:
echo Remapping ${ORIGINAL_BINARY_NAME} ==\> ${NEWTARGETID}
# BIN_BASE_NAME now contains the name of the lib, like 'QtCore'
# ORIGINAL_BINARY_NAME now contains the full path to the binary inside the framework
# for example /Users/lawsonn/Qt/5.3/clang_64/lib/Qt5Core.framework/Versions/5/Qt5Core
# NEWTARGETID is the one to change it to
# for example, @rpath/QtCore.framework/QtCore
# replace it in the executable:
install_name_tool -change "${ORIGINAL_BINARY_NAME}" "${NEWTARGETID}" "$1"
done
# now, we need to rename the dylib's own ID to be @rpath<currentId>
MY_NAME=`otool -DX "$1"`
install_name_tool -id "${NEWLIBPATH}/${MY_NAME}" "$1"
@@ -1,54 +0,0 @@
#!/bin/bash
#
#
# 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.
#
# Shell script to print out the various qt libraries that a Qt framework
# depends on. The libs that do not have @rpath in their name will need to
# either be copied into the app bundle and be updated to use rpath or be
# updated so that when an executable linking against them will pull in the
# rpath information and use that instead of the hardcoded lib id. The
# updateLibs.sh script will perform the necessary operations to update the lib
# to have an rpath ID and change the name of the dynamic Qt libs it depends on
# to use the rpath reference instead of a absolute path
DEBUG_PRINT=1
VERBOSE_DEBUG_PRINT=0
runInstallNameToolOn ()
{
pushd $1/Versions/Current > /dev/null
libs=$(find . -type f -depth 1)
for lib in $libs; do
lib=${lib:2} # Strip off the ./ from the front of the name
printf "\t$lib has these dependenices\n"
dependencies=$(otool -LX $lib | cut -d ' ' -f 1 | grep -i qt)
for qtLib in $dependencies; do
qtLibName=${qtLib##*/}
[ $qtLibName != $lib ] && printf "\t\t$qtLib\n"
done
done
popd > /dev/null
}
if [[ $1 != "" ]]; then
doPopDir=1
pushd $1 > /dev/null
fi
frameworks=$(find . -name "*.framework" -type d)
for framework in $frameworks; do
printf "$framework\n"
runInstallNameToolOn ${framework:2}
done
if [[ $doPopDir -eq 1 ]]; then
popd > /dev/null
fi
@@ -1,48 +0,0 @@
#!/bin/bash
#
#
# 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.
#
# Shell script that updates the Qt libraries and executables that are in the
# 3rd party directory so that they contain the correct rpath references so that
# the Qt command line executables can run properly as well as executables
# linking to the libraries will automatically get the rpath versions and no
# post build processing on them will need to be done.
DEBUG_PRINT=1
qtBaseDir="$1"
# Try and guess where 3rd party is located by seeing if we can sneak our way
# through the backdoor symbolic link in the sandbox
relativePathToSandboxSDKFromScriptLocaiton="../../Sandbox/SDKs/Qt"
if [[ $qtBaseDir == "" && -e $relativePathToSandboxSDKFromScriptLocaiton ]]; then
pushd $relativePathToSandboxSDKFromScriptLocaiton > /dev/null
qtBaseDir=`pwd`
popd > /dev/null
fi
shopt -s nocasematch
if [[ $qtBaseDir != "" ]]; then
read -e -p "Use the following Qt directory: $qtBaseDir? [y/n] " useQtBaseDir
fi
if [[ $qtBaseDir == "" || $useQtBaseDir == "n" ]]; then
read -e -p "Please enter the location of the Qt directory in the 3rd party directory: " qtBaseDir
fi
[ $DEBUG_PRINT -eq 1 ] && echo "qtBaseDir = *$qtBaseDir*"
#(exec ./printQtLibDependencies.sh $qtBaseDir)
echo "Updating Qt libraries..."
(exec ./updateQtLibs.sh $qtBaseDir/lib)
echo "Updating Qt executables..."
(exec ./updateQtExecs.sh $qtBaseDir/bin)
@@ -1,76 +0,0 @@
#!/bin/bash
#
#
# 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.
#
# Shell script to update all of the executables to use rpath to reference the
# Qt libs that are stored in 3rd party. Not doing this prevents the executables
# from running on the mac since they will have embedded in them the full
# pathname of the QtLib where it was installed on the person's maching that
# copied the libs into 3rd party. (use otool -LX [exe name] to find out the
# names)
DEBUG_PRINT=0
VERBOSE_DEBUG_PRINT=0
runInstallNameToolOn ()
{
# figure out how far back we need to go to get to the Qt/lib dir where the
# frameworks are and where rpath will be pointing to
IFS=/
backDirString=""
for dir in $1; do
[ $VERBOSE_DEBUG_PRINT -eq 1 ] && printf "testing $dir length: ${#dir}\n"
backDirString=$backDirString"/.."
done
unset IFS
[ $VERBOSE_DEBUG_PRINT -eq 1 ] && printf "backDirString = $backDirString\n"
pushd $1 > /dev/null
executables=$(find . -type f -d 1 -perm +1)
for file in $executables; do
file=${file:2} # strip ./ from the front of the file name
# Get all the Qt libraries that don't have an rpath in them
dependencies=$(otool -LX $file | cut -d ' ' -f 1 | grep -i qt | grep -v @rpath)
if [[ ${#dependencies} -gt 0 ]]; then
[ $DEBUG_PRINT -eq 1 ] && printf "\tUpdating $file to use rpath and relative qt libs\n"
cmd="chmod 777 $file"
[ $DEBUG_PRINT -eq 1 ] && printf "\tRunning $cmd\n"
`$cmd`
cmd="install_name_tool -add_rpath @executable_path$backDirString/lib $file"
[ $DEBUG_PRINT -eq 1 ] && printf "\tRunning $cmd\n"
`$cmd`
fi
for qtLib in $dependencies; do
qtLibName=${qtLib##*/}
cmd="install_name_tool -change $qtLib @rpath/$qtLibName.framework/$qtLibName $file"
[ $DEBUG_PRINT -eq 1 ] && printf "\tRunning $cmd\n"
`$cmd`
done
done
popd > /dev/null
}
if [[ $1 != "" ]]; then
doPopDir=1
pushd $1 > /dev/null
fi
directoriesToLookIn=$(find . -type d)
for dir in $directoriesToLookIn; do
printf "Looking in $dir for Qt executables...\n"
runInstallNameToolOn ${dir}
done
if [[ $doPopDir -eq 1 ]]; then
popd > /dev/null
fi
@@ -1,71 +0,0 @@
#!/bin/bash
#
#
# 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.
#
# Shell script to update all of the libraries to use rpath to reference the
# Qt libs. This only needs to be run once for the libs in 3rd party so that
# they use the rpath references to the other libraries instead of the hardcoded
# paths when Qt installs them on a machine. This will allow different users to
# use the libraries directly from perforce instead of requiring a local version
# to be installed
DEBUG_PRINT=0
VERBOSE_DEBUG_PRINT=0
runInstallNameToolOn ()
{
pushd $1/Versions/Current > /dev/null
libs=$(find . -type f -depth 1)
for lib in $libs; do
lib=${lib:2} # Strip off the ./ from the front of the name
cmd="chmod 666 $lib"
[ $DEBUG_PRINT -eq 1 ] && printf "\tRunning $cmd\n"
`$cmd`
# Don't update the id if it already uses rpath (grep -v returns things
# that don't match the specified pattern
if [[ `otool -DX $lib | grep -v @rpath` != "" ]]; then
cmd="install_name_tool -id @rpath/$1/$lib $lib"
[ $DEBUG_PRINT -eq 1 ] && printf "\tRunning $cmd\n"
`$cmd`
fi
# only update qt dependencies that don't have an rpath in them
dependencies=$(otool -LX $lib | cut -d ' ' -f 1 | grep -i qt | grep -v @)
for qtLib in $dependencies; do
[ $VERBOSE_DEBUG_PRINT -eq 1 ] && printf "\tTrying to extract lib name from $qtLib\n"
qtLibName=${qtLib##*/}
[ $VERBOSE_DEBUG_PRINT -eq 1 ] && printf "\tComparing $qtLibName with $lib\n"
if [[ $qtLibName != $lib ]]; then
cmd="install_name_tool -change $qtLib @rpath/$qtLibName.framework/$qtLibName $lib"
[ $DEBUG_PRINT -eq 1 ] && printf "\tRunning $cmd\n"
`$cmd`
fi
done
done
popd > /dev/null
}
if [[ $1 != "" ]]; then
doPopDir=1
pushd $1 > /dev/null
fi
frameworksToModify=$(find . -name "*.framework" -type d)
for framework in $frameworksToModify; do
printf "Looking at $framework...\n"
runInstallNameToolOn ${framework:2}
done
if [[ $doPopDir -eq 1 ]]; then
popd > /dev/null
fi
-5
View File
@@ -18,11 +18,6 @@ name=provo
bigendian=0
pointersize=8
[_platform]
name=xenia
bigendian=0
pointersize=8
[_platform]
name=salem
bigendian=0
@@ -1,223 +0,0 @@
/*
* 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 <Cry_Geo.h> // Needed for CGFContent.h
#include <CGFContent.h>
#include <PropertyHelpers.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/ITouchBendingRule.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/IBoneData.h>
#include <SceneAPI/SceneCore/Containers/Views/PairIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphDownwardsIterator.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/Utilities/SceneGraphSelector.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <RC/ResourceCompilerScene/Common/ExportContextGlobal.h>
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <RC/ResourceCompilerScene/Common/TouchBendingExporter.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IMeshGroup.h> //Needed by CgfExportContexts.h
#include <RC/ResourceCompilerScene/Cgf/CgfExportContexts.h>
#include <RC/ResourceCompilerScene/Cgf/CgfUtils.h>
namespace AZ
{
namespace RC
{
namespace SceneEvents = AZ::SceneAPI::Events;
namespace SceneDataTypes = AZ::SceneAPI::DataTypes;
namespace SceneContainers = AZ::SceneAPI::Containers;
namespace SceneUtil = AZ::SceneAPI::Utilities;
namespace SceneViews = AZ::SceneAPI::Containers::Views;
namespace AzStringFunc = AzFramework::StringFunc;
TouchBendingExporter::TouchBendingExporter()
: AZ::SceneAPI::SceneCore::RCExportingComponent()
{
BindToCall(&TouchBendingExporter::ConfigureContainer);
BindToCall(&TouchBendingExporter::ProcessSkinnedMesh);
}
void TouchBendingExporter::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<TouchBendingExporter, AZ::SceneAPI::SceneCore::RCExportingComponent>()->Version(1);
}
}
SceneEvents::ProcessingResult TouchBendingExporter::ConfigureContainer(ContainerExportContext& context)
{
switch (context.m_phase)
{
case Phase::Filling:
{
AZStd::shared_ptr<const SceneDataTypes::ITouchBendingRule> touchBendingRule = context.m_group.GetRuleContainerConst().FindFirstByType<SceneDataTypes::ITouchBendingRule>();
if (!touchBendingRule)
{
return SceneEvents::ProcessingResult::Ignored;
}
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
AZStd::vector<AZStd::string> noCollideTargetNodes = SceneUtil::SceneGraphSelector::GenerateTargetNodes(graph, touchBendingRule->GetSceneNodeSelectionList(), SceneUtil::SceneGraphSelector::IsMesh);
ProcessMeshType(context, context.m_container, noCollideTargetNodes, PHYS_GEOM_TYPE_NO_COLLIDE);
}
return SceneEvents::ProcessingResult::Success;
case Phase::Finalizing:
{
AZStd::shared_ptr<const SceneDataTypes::ITouchBendingRule> touchBendingRule = context.m_group.GetRuleContainerConst().FindFirstByType<SceneDataTypes::ITouchBendingRule>();
if (!touchBendingRule)
{
return SceneEvents::ProcessingResult::Ignored;
}
//Let's make sure we have valid CSkinningInfo, otherwise,
//there's no point in adding the Bone Tree helper nodes.
CSkinningInfo* skinningInfo = context.m_container.GetSkinningInfo();
if (skinningInfo->m_arrBonesDesc.size() < 1)
{
return SceneEvents::ProcessingResult::Ignored;
}
AZStd::string rootBoneName = touchBendingRule->GetRootBoneName();
AddHelperBoneNodes(context, context.m_container, rootBoneName,
touchBendingRule->ShouldOverrideDamping(), touchBendingRule->GetOverrideDamping(),
touchBendingRule->ShouldOverrideStiffness(), touchBendingRule->GetOverrideStiffness(),
touchBendingRule->ShouldOverrideThickness(), touchBendingRule->GetOverrideThickness());
}
return SceneEvents::ProcessingResult::Success;
default:
return SceneEvents::ProcessingResult::Ignored;
}
}
SceneEvents::ProcessingResult TouchBendingExporter::ProcessSkinnedMesh(AZ::RC::MeshNodeExportContext& context)
{
if (context.m_physicalizeType != PHYS_GEOM_TYPE_NONE)
{
return SceneEvents::ProcessingResult::Ignored;
}
AZStd::shared_ptr<const SceneDataTypes::ITouchBendingRule> touchBendingRule = context.m_group.GetRuleContainerConst().FindFirstByType<SceneDataTypes::ITouchBendingRule>();
if (!touchBendingRule)
{
return SceneEvents::ProcessingResult::Ignored;
}
AZStd::string rootBoneName = touchBendingRule->GetRootBoneName();
SceneEvents::ProcessingResult result = SceneEvents::ProcessingResult::Ignored;
switch (context.m_phase)
{
case Phase::Filling:
result = SceneEvents::Process<TouchBendableMeshNodeExportContext>(
context, rootBoneName, Phase::Filling);
break;
case Phase::Construction:
{
//Add the Bones to CSkinningInfo only if they have not been added already.
CSkinningInfo* skinningInfo = context.m_container.GetSkinningInfo();
if (skinningInfo->m_arrBonesDesc.size() == 0)
{
result = SceneEvents::Process<AddBonesToSkinningInfoContext>(
*skinningInfo, context.m_scene, rootBoneName);
}
}
break;
default:
break;
}
return result;
}
/*!
The format is based on Cry's PropertyHelpers::SetPropertyValue.
This version doesn't do any nullptr checking or white space trimming,
because those errors are guaranteed not to happen.
*/
static void AddPropertyValue(AZStd::string& inoutPropertiesString, const char* propertyName, float value, const char * propertySeparator)
{
char valueStr[16];
snprintf(valueStr, sizeof(valueStr), "%f", value);
AzStringFunc::Append(inoutPropertiesString, propertyName);
AzStringFunc::Append(inoutPropertiesString, '=');
AzStringFunc::Append(inoutPropertiesString, valueStr);
if (propertySeparator)
{
AzStringFunc::Append(inoutPropertiesString, propertySeparator);
}
}
bool TouchBendingExporter::AddHelperBoneNodes(AZ::RC::ContainerExportContext& context, CContentCGF& content, AZStd::string& rootBoneName,
[[maybe_unused]] bool shouldOverrideDamping, float damping,
[[maybe_unused]] bool shouldOverrideStiffness, float stiffness,
[[maybe_unused]] bool shouldOverrideThickness, float thickness)
{
AZ_TraceContext("AddHelperBoneNodes() rootBoneName:", rootBoneName);
if (rootBoneName.empty())
{
AZ_TracePrintf(TraceWindowName, "Root bone name cannot be empty.");
return false;
}
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
SceneContainers::SceneGraph::NodeIndex nodeIndex = graph.Find(rootBoneName);
if (!nodeIndex.IsValid())
{
AZ_TracePrintf(TraceWindowName, "Unable to find root bone in scene graph.");
return false;
}
auto contentStorage = graph.GetContentStorage();
auto nameStorage = graph.GetNameStorage();
auto pairView = SceneViews::MakePairView(contentStorage, nameStorage);
auto view = SceneViews::MakeSceneGraphDownwardsView<SceneViews::DepthFirst>(graph, nodeIndex, pairView.begin(), true);
int index = 0;
//Once SceneAPI supports Per Node Attributes, the string with properties
//should be built per Node. In the meantime, because all the properties are
//the same for all nodes, the string can be built once.
AZStd::string nodeProperties;
AddPropertyValue(nodeProperties, NODE_PROPERTY_DAMPING, damping, "\r\n");
AddPropertyValue(nodeProperties, NODE_PROPERTY_STIFFNESS, stiffness, "\r\n");
AddPropertyValue(nodeProperties, NODE_PROPERTY_THICKNESS, thickness, nullptr);
for (auto it = view.begin(); it != view.end(); ++it)
{
if (it->first && it->first->RTTI_IsTypeOf(SceneDataTypes::IBoneData::TYPEINFO_Uuid()))
{
//These very dummy nodes, are only used to define the name
//of the spines. It is not necessary to set transform matrices,
//nor it is relevant to set parent pointers, etc.
CNodeCGF* nodeCgf = new CNodeCGF();
SetNodeName(it->second.GetName(), *nodeCgf);
nodeCgf->type = CNodeCGF::NODE_HELPER;
nodeCgf->helperType = HP_POINT;
nodeCgf->properties = nodeProperties.c_str();
content.AddNode(nodeCgf);
}
else
{
// End of bone chain or interruption in the bone chain. In both cases stop looking into this part of hierarchy further.
it.IgnoreNodeDescendants();
}
}
return true;
}
} // namespace RC
} // namespace AZ
@@ -1,60 +0,0 @@
#pragma once
/*
* 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 <AzCore/std/string/string.h>
#include <AzCore/std/containers/vector.h>
#include <AzCore/std/containers/unordered_map.h>
#include <SceneAPI/SceneCore/Components/RCExportingComponent.h>
struct CNodeCGF;
class CContentCGF;
namespace AZ
{
class ReflectContext;
namespace RC
{
struct CgfGroupExportContext;
struct ContainerExportContext;
struct MeshNodeExportContext;
class TouchBendingExporter
: public AZ::SceneAPI::SceneCore::RCExportingComponent
{
public:
AZ_COMPONENT(TouchBendingExporter, "{4C6694B3-F7A8-48D8-A10A-46D57F8CC75E}", AZ::SceneAPI::SceneCore::RCExportingComponent);
TouchBendingExporter();
~TouchBendingExporter() override = default;
static void Reflect(AZ::ReflectContext* context);
SceneAPI::Events::ProcessingResult ConfigureContainer(AZ::RC::ContainerExportContext& context);
SceneAPI::Events::ProcessingResult ProcessSkinnedMesh(AZ::RC::MeshNodeExportContext& context);
static constexpr const char * const TraceWindowName = "TouchBending";
protected:
/*!
StaticObjectCompiler, when building SFoliageInfoCGF, uses the "branch%d_%d" named bones to build the spines.
This methods adds the tree of CNodeCGF helper nodes from Bones with such names.
*/
bool AddHelperBoneNodes(AZ::RC::ContainerExportContext& context, CContentCGF& content, AZStd::string& rootBoneName,
bool shouldOverrideDamping, float damping,
bool shouldOverrideStiffness, float stiffness,
bool shouldOverrideThickness, float thickness);
}; //class TouchBendingCgfExporter
} // namespace RC
} //namespace AZ
@@ -1,199 +0,0 @@
/*
* 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 <Cry_Geo.h> // Needed for CGFContent.h
#include <CGFContent.h>
#include <AzCore/Math/Quaternion.h>
#include <AzCore/std/smart_ptr/shared_ptr.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphUpwardsIterator.h>
#include <SceneAPI/SceneCore/Containers/Views/SceneGraphChildIterator.h>
#include <SceneAPI/SceneCore/Containers/Utilities/Filters.h>
#include <SceneAPI/SceneCore/DataTypes/Rules/IOriginRule.h>
#include <SceneAPI/SceneCore/DataTypes/Groups/IMeshGroup.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/ITransform.h>
#include <SceneAPI/SceneCore/DataTypes/DataTypeUtilities.h>
#include <RC/ResourceCompilerScene/Common/CommonExportContexts.h>
#include <RC/ResourceCompilerScene/Common/WorldMatrixExporter.h>
namespace AZ
{
namespace RC
{
namespace SceneEvents = AZ::SceneAPI::Events;
namespace SceneDataTypes = AZ::SceneAPI::DataTypes;
namespace SceneContainers = AZ::SceneAPI::Containers;
namespace SceneViews = AZ::SceneAPI::Containers::Views;
WorldMatrixExporter::WorldMatrixExporter()
: m_cachedRootMatrix(MatrixType::CreateIdentity())
, m_cachedGroup(nullptr)
, m_cachedRootMatrixIsSet(false)
{
BindToCall(&WorldMatrixExporter::ProcessMeshGroup);
BindToCall(&WorldMatrixExporter::ProcessNode);
}
void WorldMatrixExporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<WorldMatrixExporter, SceneAPI::SceneCore::RCExportingComponent>()->Version(1);
}
}
SceneEvents::ProcessingResult WorldMatrixExporter::ProcessMeshGroup(ContainerExportContext& context)
{
if (context.m_phase != Phase::Construction)
{
return SceneEvents::ProcessingResult::Ignored;
}
m_cachedGroup = &context.m_group;
m_cachedRootMatrix = MatrixType::CreateIdentity();
m_cachedRootMatrixIsSet = false;
AZStd::shared_ptr<const SceneDataTypes::IOriginRule> rule = context.m_group.GetRuleContainerConst().FindFirstByType<SceneDataTypes::IOriginRule>();
if (rule)
{
if (rule->GetTranslation() != Vector3(0.0f, 0.0f, 0.0f) || !rule->GetRotation().IsIdentity())
{
m_cachedRootMatrix = MatrixType::CreateFromQuaternionAndTranslation(rule->GetRotation(), rule->GetTranslation());
m_cachedRootMatrixIsSet = true;
}
if (rule->GetScale() != 1.0f)
{
float scale = rule->GetScale();
m_cachedRootMatrix.MultiplyByScale(Vector3(scale, scale, scale));
m_cachedRootMatrixIsSet = true;
}
if (!rule->GetOriginNodeName().empty() && !rule->UseRootAsOrigin())
{
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
SceneContainers::SceneGraph::NodeIndex index = graph.Find(rule->GetOriginNodeName());
if (index.IsValid())
{
MatrixType worldMatrix = MatrixType::CreateIdentity();
if (ConcatenateMatricesUpwards(worldMatrix, graph.ConvertToHierarchyIterator(index), graph))
{
worldMatrix.InvertFull();
m_cachedRootMatrix *= worldMatrix;
m_cachedRootMatrixIsSet = true;
}
}
}
return m_cachedRootMatrixIsSet ? SceneEvents::ProcessingResult::Success : SceneEvents::ProcessingResult::Ignored;
}
else
{
return SceneEvents::ProcessingResult::Ignored;
}
}
SceneEvents::ProcessingResult WorldMatrixExporter::ProcessNode(NodeExportContext& context)
{
if (context.m_phase != Phase::Filling)
{
return SceneEvents::ProcessingResult::Ignored;
}
MatrixType worldMatrix = MatrixType::CreateIdentity();
const SceneContainers::SceneGraph& graph = context.m_scene.GetGraph();
HierarchyStorageIterator nodeIterator = graph.ConvertToHierarchyIterator(context.m_nodeIndex);
bool translated = ConcatenateMatricesUpwards(worldMatrix, nodeIterator, graph);
AZ_Assert(m_cachedGroup == &context.m_group, "NodeExportContext doesn't belong to chain of previously called MeshGroupExportContext.");
if (m_cachedRootMatrixIsSet)
{
worldMatrix = m_cachedRootMatrix * worldMatrix;
translated = true;
}
//If we aren't merging nodes we need to put the transforms into the localTM
//due to how the CGFSaver works inside the ResourceCompilerPC code.
if (!context.m_container.GetExportInfo()->bMergeAllNodes)
{
SceneAPIMatrixTypeToMatrix34(context.m_node.localTM, worldMatrix);
}
else
{
SceneAPIMatrixTypeToMatrix34(context.m_node.worldTM, worldMatrix);
}
context.m_node.bIdentityMatrix = !translated;
return SceneEvents::ProcessingResult::Success;
}
bool WorldMatrixExporter::ConcatenateMatricesUpwards(MatrixType& transform, const HierarchyStorageIterator& nodeIterator, const SceneContainers::SceneGraph& graph) const
{
bool translated = false;
auto view = SceneViews::MakeSceneGraphUpwardsView(graph, nodeIterator, graph.GetContentStorage().cbegin(), true);
for (auto it = view.begin(); it != view.end(); ++it)
{
if (!(*it))
{
continue;
}
const SceneDataTypes::ITransform* nodeTransform = azrtti_cast<const SceneDataTypes::ITransform*>(it->get());
if (nodeTransform)
{
transform = nodeTransform->GetMatrix() * transform;
translated = true;
}
else
{
bool endPointTransform = MultiplyEndPointTransforms(transform, it.GetHierarchyIterator(), graph);
translated = translated || endPointTransform;
}
}
return translated;
}
bool WorldMatrixExporter::MultiplyEndPointTransforms(MatrixType& transform, const HierarchyStorageIterator& nodeIterator, const SceneContainers::SceneGraph& graph) const
{
// If the translation is not an end point it means it's its own group as opposed to being
// a component of the parent, so only list end point children.
auto view = SceneViews::MakeSceneGraphChildView<SceneViews::AcceptEndPointsOnly>(graph, nodeIterator,
graph.GetContentStorage().begin(), true);
auto result = AZStd::find_if(view.begin(), view.end(), SceneContainers::DerivedTypeFilter<SceneDataTypes::ITransform>());
if (result != view.end())
{
transform = azrtti_cast<const SceneDataTypes::ITransform*>(result->get())->GetMatrix() * transform;
return true;
}
else
{
return false;
}
}
void WorldMatrixExporter::SceneAPIMatrixTypeToMatrix34(Matrix34& out, const MatrixType& in) const
{
// Setting column instead of row because as of writing Matrix34 doesn't support adding
// full rows, as the translation has to be done separately.
for (int column = 0; column < 4; ++column)
{
Vector3 data = in.GetColumn(column);
out.SetColumn(column, Vec3(data.GetX(), data.GetY(), data.GetZ()));
}
}
} // namespace RC
} // namespace AZ
@@ -1,65 +0,0 @@
/*
* 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.
*
*/
#pragma once
#include <Cry_Matrix34.h>
#include <SceneAPI/SceneCore/Components/RCExportingComponent.h>
#include <SceneAPI/SceneCore/Containers/SceneGraph.h>
#include <SceneAPI/SceneCore/DataTypes/MatrixType.h>
namespace AZ
{
class Transform;
namespace SceneAPI
{
namespace DataTypes
{
class IOriginRule;
class IGroup;
}
}
namespace RC
{
struct ContainerExportContext;
struct NodeExportContext;
class WorldMatrixExporter
: public SceneAPI::SceneCore::RCExportingComponent
{
public:
AZ_COMPONENT(WorldMatrixExporter, "{65A0914C-5953-405F-819B-0E6EB96938F1}", SceneAPI::SceneCore::RCExportingComponent);
WorldMatrixExporter();
~WorldMatrixExporter() override = default;
static void Reflect(ReflectContext* context);
SceneAPI::Events::ProcessingResult ProcessMeshGroup(ContainerExportContext& context);
SceneAPI::Events::ProcessingResult ProcessNode(NodeExportContext& context);
protected:
using HierarchyStorageIterator = SceneAPI::Containers::SceneGraph::HierarchyStorageConstIterator;
using MatrixType = SceneAPI::DataTypes::MatrixType;
bool ConcatenateMatricesUpwards(MatrixType& transform, const HierarchyStorageIterator& nodeIterator, const SceneAPI::Containers::SceneGraph& graph) const;
bool MultiplyEndPointTransforms(MatrixType& transform, const HierarchyStorageIterator& nodeIterator, const SceneAPI::Containers::SceneGraph& graph) const;
void SceneAPIMatrixTypeToMatrix34(Matrix34& out, const MatrixType& in) const;
MatrixType m_cachedRootMatrix;
const SceneAPI::DataTypes::IGroup* m_cachedGroup;
bool m_cachedRootMatrixIsSet;
};
} // namespace RC
} // namespace AZ
@@ -12,6 +12,8 @@
*
*/
#include <cstddef>
class IConfig;
namespace AZ
@@ -30,4 +32,4 @@ namespace AZ
inline ISceneConfig::~ISceneConfig() = default;
} // RC
} // AZ
} // AZ
@@ -10,7 +10,7 @@
*
*/
#include "ResourceCompilerScene_precompiled.h"
#include <ISystem.h>
#include <platform.h>
#include <IResCompiler.h>
#include <IRCLog.h>
@@ -1,45 +0,0 @@
#pragma once
/*
* 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.
*
*/
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#include <assert.h>
#define CRY_ASSERT(condition) assert(condition)
#define CRY_ASSERT_TRACE(condition, message) assert(condition)
#define CRY_ASSERT_MESSAGE(condition, message) assert(condition)
// Define this to prevent including CryAssert (there is no proper hook for turning this off, like the above).
#define CRYINCLUDE_CRYCOMMON_CRYASSERT_H
#include <platform.h>
#include <vector>
#include <map>
#include <stdio.h>
#include <Cry_Math.h>
#include <Cry_Geo.h>
#include <CryHeaders.h>
#include <primitives.h>
#include <smartptr.h>
#include <physinterface.h>
#include <CrySizer.h>
#include <RC/ResourceCompiler/IRCLog.h>
@@ -10,7 +10,6 @@
*
*/
#include "ResourceCompilerScene_precompiled.h"
#include <IRCLog.h>
#include <ISceneConfig.h>
#include <ISystem.h>
@@ -43,13 +42,11 @@
#include <RC/ResourceCompilerScene/Common/ContainerSettingsExporter.h>
#include <RC/ResourceCompilerScene/Common/MeshExporter.h>
#include <RC/ResourceCompilerScene/Common/MaterialExporter.h>
#include <RC/ResourceCompilerScene/Common/WorldMatrixExporter.h>
#include <RC/ResourceCompilerScene/Common/ColorStreamExporter.h>
#include <RC/ResourceCompilerScene/Common/UVStreamExporter.h>
#include <RC/ResourceCompilerScene/Common/SkeletonExporter.h>
#include <RC/ResourceCompilerScene/Common/SkinWeightExporter.h>
#include <RC/ResourceCompilerScene/Common/BlendShapeExporter.h>
#include <RC/ResourceCompilerScene/Common/TouchBendingExporter.h>
#include <RC/ResourceCompilerScene/SceneSerializationHandler.h>
#include <SceneAPI/SceneCore/Components/ExportingComponent.h>
@@ -96,8 +93,6 @@ namespace AZ
RegisterComponentDescriptor(SkeletonExporter::CreateDescriptor());
RegisterComponentDescriptor(SkinWeightExporter::CreateDescriptor());
RegisterComponentDescriptor(UVStreamExporter::CreateDescriptor());
RegisterComponentDescriptor(WorldMatrixExporter::CreateDescriptor());
RegisterComponentDescriptor(TouchBendingExporter::CreateDescriptor());
}
AZ::ComponentTypeList RCToolApplication::GetRequiredSystemComponents() const
@@ -375,6 +370,12 @@ namespace AZ
result += SceneEvents::Process<SceneEvents::PreGenerateEventContext>(scene, platformIdentifier);
AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "Generating...\n");
result += SceneEvents::Process<SceneEvents::GenerateEventContext>(scene, platformIdentifier);
AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "Generating LODs...\n");
result += SceneEvents::Process<SceneEvents::GenerateLODEventContext>(scene, platformIdentifier);
AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "Generating additions...\n");
result += SceneEvents::Process<SceneEvents::GenerateAdditionEventContext>(scene, platformIdentifier);
AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "Simplifing scene...\n");
result += SceneEvents::Process<SceneEvents::GenerateSimplificationEventContext>(scene, platformIdentifier);
AZ_TracePrintf(SceneAPI::Utilities::LogWindow, "Finalizing generation process.\n");
result += SceneEvents::Process<SceneEvents::PostGenerateEventContext>(scene, platformIdentifier);
@@ -10,7 +10,6 @@
*
*/
#include "ResourceCompilerScene_precompiled.h"
#include <IConfig.h>
#include <SceneConfig.h>
#include <AzToolsFramework/Debug/TraceContext.h>
@@ -10,7 +10,6 @@
*
*/
#include "ResourceCompilerScene_precompiled.h"
#include <SceneConverter.h>
#include <SceneCompiler.h>
#include <ISceneConfig.h>
@@ -10,7 +10,6 @@
*
*/
#include "ResourceCompilerScene_precompiled.h"
#include <AzCore/IO/SystemFile.h>
#include <AzCore/std/algorithm.h>
#include <AzCore/std/string/conversions.h>
@@ -1,143 +0,0 @@
/*
* 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 <Cry_Geo.h> // Needed for Cry_Matrix34.h
#include <Cry_Matrix34.h>
#include <RC/ResourceCompilerScene/Tests/Cgf/CgfExportContextTestBase.h>
#include <RC/ResourceCompilerScene/Cgf/CgfExportContexts.h>
#include <RC/ResourceCompilerScene/Common/WorldMatrixExporter.h>
#include <SceneAPI/SceneCore/Mocks/DataTypes/GraphData/MockITransform.h>
#include <SceneAPI/SceneCore/Mocks/DataTypes/GraphData/MockIMeshData.h>
#include <SceneAPI/SceneCore/Mocks/DataTypes/ManifestBase/MockISceneNodeSelectionList.h>
namespace AZ
{
namespace RC
{
using ::testing::Const;
using ::testing::Return;
using ::testing::ReturnRef;
class WorldMatrixExporterContextTestBase
: public CgfExporterContextTestBase
{
public:
WorldMatrixExporterContextTestBase()
: m_stubTransformData(new SceneAPI::DataTypes::MockITransform())
, m_stubMeshData(new SceneAPI::DataTypes::MockIMeshData())
, m_stubTransform(AZ::SceneAPI::DataTypes::MatrixType::CreateTranslation(AZ::Vector3(0.f, 0.f, 1.f)))
{
}
~WorldMatrixExporterContextTestBase() override = default;
protected:
void SetUp()
{
CgfExporterContextTestBase::SetUp();
m_outNode.bIdentityMatrix = true;
SceneAPI::Containers::SceneGraph& sceneGraph = m_stubScene.GetGraph();
SceneAPI::Containers::SceneGraph::NodeIndex rootIndex = sceneGraph.GetRoot();
SceneAPI::Containers::SceneGraph::NodeIndex transformIndex = sceneGraph.AddChild(rootIndex, "SampleTransformData", m_stubTransformData);
SceneAPI::Containers::SceneGraph::NodeIndex meshIndex = sceneGraph.AddChild(transformIndex, "SampleMeshData", m_stubMeshData);
UpdateNodeIndex(meshIndex);
EXPECT_CALL(Const(*m_stubTransformData), GetMatrix())
.WillRepeatedly(ReturnRef(m_stubTransform));
ON_CALL(m_stubMeshGroup, GetRuleContainer())
.WillByDefault(ReturnRef(m_ruleContainer));
ON_CALL(Const(m_stubMeshGroup), GetRuleContainerConst())
.WillByDefault(ReturnRef(m_ruleContainer));
}
bool TestChangedData()
{
return !m_outNode.bIdentityMatrix;
}
AZStd::shared_ptr<SceneAPI::DataTypes::MockITransform> m_stubTransformData;
AZStd::shared_ptr<SceneAPI::DataTypes::MockIMeshData> m_stubMeshData;
AZ::SceneAPI::DataTypes::MatrixType m_stubTransform;
WorldMatrixExporter m_testExporter;
SceneAPI::Containers::RuleContainer m_ruleContainer;
};
class WorldMatrixExporterNoOpTestFramework
: public WorldMatrixExporterContextTestBase
{
public:
~WorldMatrixExporterNoOpTestFramework() override = default;
};
TEST_P(WorldMatrixExporterNoOpTestFramework, Process_UnsupportedContext_OutNodeAtIndentity)
{
m_testExporter.Process(m_stubContext);
EXPECT_FALSE(TestChangedData());
}
ContextPhaseTuple g_CgfWorldMatrixExporterTestsUnsupportedContextPhaseTuples[] =
{
{ TestContextMeshGroup, Phase::Filling },
{ TestContextMeshGroup, Phase::Finalizing },
{ TestContextContainer, Phase::Construction },
{ TestContextContainer, Phase::Filling },
{ TestContextContainer, Phase::Finalizing },
{ TestContextNode, Phase::Construction },
{ TestContextNode, Phase::Finalizing },
{ TestContextMeshNode, Phase::Construction },
{ TestContextMeshNode, Phase::Filling },
{ TestContextMeshNode, Phase::Finalizing }
};
INSTANTIATE_TEST_CASE_P(WorldMatrixExporter,
WorldMatrixExporterNoOpTestFramework,
::testing::ValuesIn(g_CgfWorldMatrixExporterTestsUnsupportedContextPhaseTuples));
class WorldMatrixExporterSimpleTests
: public WorldMatrixExporterContextTestBase
{
public:
WorldMatrixExporterSimpleTests()
: m_cacheGenerationContext(m_productList, m_stubScene, m_sampleOutputDirectory, m_stubMeshGroup, Phase::Construction)
{
}
~WorldMatrixExporterSimpleTests() override = default;
protected:
void SetUp() override
{
WorldMatrixExporterContextTestBase::SetUp();
m_testExporter.Process(&m_cacheGenerationContext);
}
CgfGroupExportContext m_cacheGenerationContext;
};
// Disable the test due to an assert that checking consistency of cached mesh group which lacks a way to support currently
//TEST_P(WorldMatrixExporterSimpleTests, Process_SupportedContext_OutNodeNotAtIndentity)
//{
// m_testExporter.Process(m_stubContext);
// EXPECT_TRUE(TestChangedData());
//}
ContextPhaseTuple g_CgfWorldMatrixExporterTestsSupportedContextPhaseTuples[] =
{
{ TestContextNode, Phase::Filling }
};
INSTANTIATE_TEST_CASE_P(WorldMatrixExporter,
WorldMatrixExporterSimpleTests,
::testing::ValuesIn(g_CgfWorldMatrixExporterTestsSupportedContextPhaseTuples));
} // namespace RC
} // namespace AZ
@@ -10,7 +10,6 @@
#
set(FILES
ResourceCompilerScene_precompiled.h
TraceDrillerHook.h
TraceDrillerHook.cpp
ISceneConfig.h
@@ -33,8 +32,6 @@ set(FILES
Common/MeshExporter.cpp
Common/MaterialExporter.h
Common/MaterialExporter.cpp
Common/WorldMatrixExporter.h
Common/WorldMatrixExporter.cpp
Common/ColorStreamExporter.h
Common/ColorStreamExporter.cpp
Common/UVStreamExporter.h
@@ -45,8 +42,6 @@ set(FILES
Common/SkinWeightExporter.cpp
Common/BlendShapeExporter.h
Common/BlendShapeExporter.cpp
Common/TouchBendingExporter.h
Common/TouchBendingExporter.cpp
Cgf/CgfExportContexts.h
Cgf/CgfExportContexts.cpp
Cgf/CgfGroupExporter.h
@@ -18,6 +18,5 @@ set(FILES
Tests/Cgf/CgfMeshExporterTests.cpp
Tests/Cgf/CgfMeshGroupExporterTests.cpp
Tests/Cgf/CgfUVStreamExporterTests.cpp
Tests/Cgf/CgfWorldMatrixExporterTests.cpp
ResourceCompilerScene.cpp
)
@@ -9,9 +9,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
ly_get_list_relative_pal_filename(pal_dir ${CMAKE_CURRENT_LIST_DIR}/Platform/${PAL_PLATFORM_NAME})
set(sdkwrapper_dir ${CMAKE_CURRENT_LIST_DIR}/../SDKWrapper)
set(sdkwrapper_pal_dir ${sdkwrapper_dir}/Platform/${PAL_PLATFORM_NAME})
if (NOT PAL_TRAIT_BUILD_HOST_TOOLS)
return()
@@ -23,9 +21,6 @@ ly_add_target(
FILES_CMAKE
fbxsdkwrapper_files.cmake
${sdkwrapper_dir}/sdkwrapper_files.cmake
${sdkwrapper_pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}_files.cmake
PLATFORM_INCLUDE_FILES
${pal_dir}/platform_${PAL_PLATFORM_NAME_LOWERCASE}.cmake
INCLUDE_DIRECTORIES
PUBLIC
.
@@ -37,4 +32,5 @@ ly_add_target(
AZ::AzToolsFramework
PUBLIC
3rdParty::FbxSdk
3rdParty::assimplib
)
@@ -102,7 +102,7 @@ namespace AZ
return 10.f;
}
uint64_t FbxMaterialWrapper::GetUniqueId() const
AZ::u64 FbxMaterialWrapper::GetUniqueId() const
{
return m_fbxMaterial->GetUniqueID();
}
@@ -38,7 +38,7 @@ namespace AZ
AZ::Vector3 GetEmissiveColor() const override;
float GetOpacity() const override;
float GetShininess() const override;
uint64_t GetUniqueId() const override;
AZ::u64 GetUniqueId() const override;
};
} // namespace FbxSDKWrapper
} // namespace AZ
@@ -1,12 +0,0 @@
#
# 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.
#
@@ -1,12 +0,0 @@
#
# 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.
#
@@ -1,16 +0,0 @@
#
# 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.
#
set(LY_BUILD_DEPENDENCIES
PUBLIC
3rdParty::AssImp
)
set(LY_COMPILE_DEFINITIONS PUBLIC ASSET_IMPORTER_SDK_SUPPORTED_TRAIT)
@@ -19,13 +19,18 @@
#include <SceneAPI/FbxSceneBuilder/FbxImportRequestHandler.h>
#include <SceneAPI/FbxSceneBuilder/FbxImporter.h>
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpBitangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpColorStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMaterialImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMeshImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpTangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpTransformImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpUvMapImporter.h>
#endif
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpSkinImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpBlendShapeImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxAnimationImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxBlendShapeImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxBoneImporter.h>
@@ -39,7 +44,6 @@
#include <SceneAPI/FbxSceneBuilder/Importers/FbxTransformImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxUvMapImporter.h>
namespace AZ
{
namespace SceneAPI
@@ -86,13 +90,19 @@ namespace AZ
g_componentDescriptors.push_back(FbxUvMapImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxTangentStreamImporter::CreateDescriptor());
g_componentDescriptors.push_back(FbxBitangentStreamImporter::CreateDescriptor());
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
g_componentDescriptors.push_back(AssImpBitangentStreamImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpColorStreamImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpMaterialImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpMeshImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpTangentStreamImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpTransformImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpUvMapImporter::CreateDescriptor());
#endif
g_componentDescriptors.push_back(AssImpSkinImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpSkinWeightsImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpBoneImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpAnimationImporter::CreateDescriptor());
g_componentDescriptors.push_back(AssImpBlendShapeImporter::CreateDescriptor());
for (AZ::ComponentDescriptor* descriptor : g_componentDescriptors)
{
AZ::ComponentApplicationBus::Broadcast(&AZ::ComponentApplicationBus::Handler::RegisterComponentDescriptor, descriptor);
@@ -21,10 +21,8 @@
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxImporter.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMaterialImporter.h>
#endif
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSDKWrapper/FbxSceneWrapper.h>
@@ -32,10 +30,8 @@
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/TransformData.h>
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#endif
namespace AZ
{
@@ -59,7 +55,7 @@ namespace AZ
FbxImporter::FbxImporter()
: m_sceneSystem(new FbxSceneSystem())
{
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
if (m_useAssetImporterSDK)
{
m_sceneWrapper = AZStd::make_unique<AssImpSDKWrapper::AssImpSceneWrapper>();
@@ -68,9 +64,7 @@ namespace AZ
{
m_sceneWrapper = AZStd::make_unique<FbxSDKWrapper::FbxSceneWrapper>();
}
#else
m_sceneWrapper = AZStd::make_unique<FbxSDKWrapper::FbxSceneWrapper>();
#endif
BindToCall(&FbxImporter::ImportProcessing);
}
@@ -99,12 +93,10 @@ namespace AZ
{
convertFunc = AZStd::bind(&FbxImporter::ConvertFbxSceneContext, this, AZStd::placeholders::_1);
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
else
{
convertFunc = AZStd::bind(&FbxImporter::ConvertFbxScene, this, AZStd::placeholders::_1);
}
#endif
if (convertFunc(context.GetScene()))
{
@@ -284,7 +276,7 @@ namespace AZ
return true;
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
bool FbxImporter::ConvertFbxScene(Containers::Scene& scene) const
{
std::shared_ptr<SDKNode::NodeWrapper> fbxRoot = m_sceneWrapper->GetRootNode();
@@ -333,6 +325,8 @@ namespace AZ
continue;
}
AZStd::string nodeName = nodeNameMap.GetNodeName(node.m_node);
SanitizeNodeName(nodeName);
AZ_TraceContext("SceneAPI Node Name", nodeName);
Containers::SceneGraph::NodeIndex newNode = scene.GetGraph().AddChild(node.m_parent, nodeName.c_str());
@@ -431,7 +425,13 @@ namespace AZ
return true;
}
#endif
void FbxImporter::SanitizeNodeName(AZStd::string& nodeName) const
{
// Replace % with something else so it is safe for use in printfs.
AZStd::replace(nodeName.begin(), nodeName.end(), '%', '_');
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -46,15 +46,12 @@ namespace AZ
protected:
bool ConvertFbxSceneContext(Containers::Scene& scene) const;
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
bool ConvertFbxScene(Containers::Scene& scene) const;
#endif
void SanitizeNodeName(AZStd::string& nodeName) const;
AZStd::unique_ptr<SDKScene::SceneWrapperBase> m_sceneWrapper;
AZStd::shared_ptr<FbxSceneSystem> m_sceneSystem;
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
bool m_useAssetImporterSDK = false;
#endif
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
@@ -13,12 +13,9 @@
#include <AzCore/Math/Vector3.h>
#include <SceneAPI/FbxSDKWrapper/FbxSceneWrapper.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
#include <assimp/scene.h>
#endif
namespace AZ
@@ -52,7 +49,6 @@ namespace AZ
m_adjustTransformInverse.reset(new DataTypes::MatrixType(m_adjustTransform->GetInverseFull()));
}
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
else if (azrtti_istypeof<AssImpSDKWrapper::AssImpSceneWrapper>(fbxScene))
{
const AssImpSDKWrapper::AssImpSceneWrapper* assImpScene = azrtti_cast<const AssImpSDKWrapper::AssImpSceneWrapper*>(fbxScene);
@@ -135,7 +131,6 @@ namespace AZ
m_adjustTransformInverse.reset(new DataTypes::MatrixType(m_adjustTransform->GetInverseFull()));
}
}
#endif
}
void FbxSceneSystem::SwapVec3ForUpAxis(Vector3& swapVector) const
@@ -0,0 +1,610 @@
/*
* 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 <AssImpTypeConverter.h>
#include <assimp/mesh.h>
#include <assimp/scene.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSDKWrapper/FbxAnimCurveWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxAnimLayerWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxSceneWrapper.h>
#include <SceneAPI/FbxSDKWrapper/FbxTimeSpanWrapper.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneData/GraphData/AnimationData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const char* AssImpAnimationImporter::s_animationNodeName = "animation";
const FbxSDKWrapper::FbxTimeWrapper::TimeMode AssImpAnimationImporter::s_defaultTimeMode =
FbxSDKWrapper::FbxTimeWrapper::frames30;
AssImpAnimationImporter::AssImpAnimationImporter()
{
BindToCall(&AssImpAnimationImporter::ImportAnimation);
}
void AssImpAnimationImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpAnimationImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
AZStd::string GetName(const aiMeshAnim* anim)
{
return anim->mName.C_Str();
}
AZStd::string GetName(const aiNodeAnim* anim)
{
return anim->mNodeName.C_Str();
}
AZStd::string GetName(const aiMeshMorphAnim* anim)
{
return anim->mName.C_Str();
}
struct ConsolidatedNodeAnim
{
ConsolidatedNodeAnim() = default;
ConsolidatedNodeAnim(const ConsolidatedNodeAnim& other) = delete;
ConsolidatedNodeAnim(ConsolidatedNodeAnim&& other) noexcept
: mNumPositionKeys{ other.mNumPositionKeys },
mPositionKeys{ other.mPositionKeys },
mNumRotationKeys{ other.mNumRotationKeys },
mRotationKeys{ other.mRotationKeys },
mNumScalingKeys{ other.mNumScalingKeys },
mScalingKeys{ other.mScalingKeys },
m_ownedPositionKeys{ std::move(other.m_ownedPositionKeys) },
m_ownedScalingKeys{ std::move(other.m_ownedScalingKeys) },
m_ownedRotationKeys{ std::move(other.m_ownedRotationKeys) },
mPreState{ other.mPreState },
mPostState{ other.mPostState }
{
}
ConsolidatedNodeAnim& operator=(const ConsolidatedNodeAnim& other) = delete;
ConsolidatedNodeAnim& operator=(ConsolidatedNodeAnim&& other) noexcept
{
if (this == &other)
{
return *this;
}
mNumPositionKeys = other.mNumPositionKeys;
mPositionKeys = other.mPositionKeys;
mNumRotationKeys = other.mNumRotationKeys;
mRotationKeys = other.mRotationKeys;
mNumScalingKeys = other.mNumScalingKeys;
mScalingKeys = other.mScalingKeys;
m_ownedPositionKeys = std::move(other.m_ownedPositionKeys);
m_ownedScalingKeys = std::move(other.m_ownedScalingKeys);
m_ownedRotationKeys = std::move(other.m_ownedRotationKeys);
mPreState = other.mPreState;
mPostState = other.mPostState;
return *this;
}
// These variables are named using AssImp naming convention for consistency
unsigned int mNumPositionKeys{};
aiVectorKey* mPositionKeys{};
unsigned int mNumRotationKeys{};
aiQuatKey* mRotationKeys{};
unsigned int mNumScalingKeys{};
aiVectorKey* mScalingKeys{};
AZStd::vector<aiVectorKey> m_ownedPositionKeys{};
AZStd::vector<aiVectorKey> m_ownedScalingKeys{};
AZStd::vector<aiQuatKey> m_ownedRotationKeys{};
aiAnimBehaviour mPreState{};
aiAnimBehaviour mPostState{};
};
AZStd::pair<const aiAnimation*, ConsolidatedNodeAnim> MakeMyPair(const aiAnimation* animation, const aiNodeAnim* anim)
{
ConsolidatedNodeAnim consolidatedNodeAnim{};
consolidatedNodeAnim.mNumRotationKeys = anim->mNumRotationKeys;
consolidatedNodeAnim.mNumPositionKeys = anim->mNumPositionKeys;
consolidatedNodeAnim.mNumScalingKeys = anim->mNumScalingKeys;
consolidatedNodeAnim.mRotationKeys = anim->mRotationKeys;
consolidatedNodeAnim.mPositionKeys = anim->mPositionKeys;
consolidatedNodeAnim.mScalingKeys = anim->mScalingKeys;
return {animation, AZStd::move(consolidatedNodeAnim)};
}
auto MakeMyPair(const aiAnimation* animation, const aiMeshAnim* anim)
{
return AZStd::make_pair(animation, anim);
}
auto MakeMyPair(const aiAnimation* animation, const aiMeshMorphAnim* anim)
{
return AZStd::make_pair(animation, anim);
}
Events::ProcessingResult AssImpAnimationImporter::ImportAnimation(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Animation");
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
// Add check for animation layers at the scene level.
if (!scene->HasAnimations() || IsPivotNode(currentNode->mName))
{
return Events::ProcessingResult::Ignored;
}
AZStd::unordered_multimap<AZStd::string, AZStd::pair<const aiAnimation*, ConsolidatedNodeAnim>> boneAnimations;
typedef AZStd::pair<const aiAnimation*, const aiMeshMorphAnim*> AnimAndMorphAnim;
typedef AZStd::unordered_map<AZStd::string, AnimAndMorphAnim> ChannelToMorphAnim;
typedef AZStd::unordered_map<AZStd::string, ChannelToMorphAnim> NodeToChannelToMorphAnim;
NodeToChannelToMorphAnim meshMorphAnimations;
// Goes through all the animation channels of a given type and adds them to a map so we can easily find
// all the animations for a given node
// In the case of bone animations, the data is copied into a ConsolidatedNodeAnim so we can
// do fix-ups later without affecting the original data
auto mapAnimationsFunc = [](unsigned numChannels, auto** channels, const aiAnimation* animation, auto& map)
{
map.reserve(numChannels);
for (unsigned channelIndex = 0; channelIndex < numChannels; ++channelIndex)
{
auto* nodeAnim = channels[channelIndex];
AZStd::string name = GetName(nodeAnim);
map.emplace(name, MakeMyPair(animation, nodeAnim));
}
};
for (unsigned animIndex = 0; animIndex < scene->mNumAnimations; ++animIndex)
{
const aiAnimation* animation = scene->mAnimations[animIndex];
mapAnimationsFunc(animation->mNumChannels, animation->mChannels, animation, boneAnimations);
for (unsigned channelIndex = 0; channelIndex < animation->mNumMorphMeshChannels; ++channelIndex)
{
auto* nodeAnim = animation->mMorphMeshChannels[channelIndex];
AZStd::string name = GetName(nodeAnim);
AZStd::vector<AZStd::string> meshNodeNameAndChannel;
// Morph target animations include the channel in the name,
// so if a mesh is named Mesh01, the morph target for the first channel
// will be named Mesh01*0
AZ::StringFunc::Tokenize(name, meshNodeNameAndChannel, '*');
if (meshNodeNameAndChannel.size() != 2)
{
AZ_Error(
"AnimationImporter", false,
"Morph animation name %s was not in the expected format of: node name, asterisk, node channel. "
"Example: 'NodeName*0'",
name.c_str());
continue;
}
AZStd::string meshNodeName(meshNodeNameAndChannel[0]);
AZStd::string channel(meshNodeNameAndChannel[1]);
meshMorphAnimations[meshNodeName][channel] = AnimAndMorphAnim(animation, nodeAnim);
}
}
// Go through all the bone animations and find any that reference a pivot node
// We'll make a new node anim and store all the combined animation channels there
// with the name set to the base bone name
decltype(boneAnimations) combinedAnimations;
for (auto&& animation : boneAnimations)
{
size_t pos = AZ::StringFunc::Find(animation.first, PivotNodeMarker, 0);
if (pos != animation.first.npos)
{
AZStd::string_view name, part;
SplitPivotNodeName(aiString(animation.first.c_str()), pos, name, part);
auto&& iterator = combinedAnimations.find(name);
if (iterator == combinedAnimations.end())
{
combinedAnimations.emplace(AZStd::string(name), AZStd::move(animation.second));
iterator = combinedAnimations.find(name);
}
if (iterator != combinedAnimations.end())
{
auto& existingNode = iterator->second.second;
auto&& src = animation.second.second;
if (part == "Translation")
{
existingNode.mNumPositionKeys = src.mNumPositionKeys;
existingNode.mPositionKeys = src.mPositionKeys;
}
else if (part == "Rotation")
{
existingNode.mNumRotationKeys = src.mNumRotationKeys;
existingNode.mRotationKeys = src.mRotationKeys;
}
else if (part == "Scaling")
{
existingNode.mNumScalingKeys = src.mNumScalingKeys;
existingNode.mScalingKeys = src.mScalingKeys;
}
}
}
}
if (!combinedAnimations.empty())
{
boneAnimations.swap(combinedAnimations);
}
Events::ProcessingResultCombiner combinedAnimationResult;
for (unsigned meshIndex = 0; meshIndex < currentNode->mNumMeshes; ++meshIndex)
{
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[meshIndex]];
if (NodeToChannelToMorphAnim::iterator channelsForMeshName = meshMorphAnimations.find(mesh->mName.C_Str());
channelsForMeshName != meshMorphAnimations.end())
{
const auto [nodeIterName, channels] = *channelsForMeshName;
for (const auto& [channel, animAndMorphAnim] : channels)
{
const auto& [animation, morphAnimation] = animAndMorphAnim;
combinedAnimationResult += ImportBlendShapeAnimation(
context, animation, morphAnimation, mesh);
}
}
}
AZStd::string nodeName = s_animationNodeName;
RenamedNodesMap::SanitizeNodeName(nodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition);
AZ_TraceContext("Animation node name", nodeName);
// If there are no bone animations, but there are mesh animations,
// then a stub animation needs to be created so the exporter can create the exported morph target animation.
if (boneAnimations.empty() && !meshMorphAnimations.empty())
{
const aiAnimation* animation = scene->mAnimations[0];
// Morph animations need a regular animation on the node, as well.
// If there is no bone animation on the current node, then generate one here.
AZStd::shared_ptr<SceneData::GraphData::AnimationData> createdAnimationData =
AZStd::make_shared<SceneData::GraphData::AnimationData>();
createdAnimationData->ReserveKeyFrames(
animation->mDuration +
1); // +1 because we start at 0 and the last keyframe is at mDuration instead of mDuration-1
createdAnimationData->SetTimeStepBetweenFrames(1.0 / animation->mTicksPerSecond);
// Set every frame of the animation to the start location of the node.
aiMatrix4x4 combinedTransform = GetConcatenatedLocalTransform(currentNode);
DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform);
context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform);
context.m_sourceSceneSystem.ConvertUnit(localTransform);
for (unsigned time = 0; time <= animation->mDuration; ++time)
{
createdAnimationData->AddKeyFrame(localTransform);
}
Containers::SceneGraph::NodeIndex addNode = context.m_scene.GetGraph().AddChild(
context.m_currentGraphPosition, nodeName.c_str(), AZStd::move(createdAnimationData));
context.m_scene.GetGraph().MakeEndPoint(addNode);
return combinedAnimationResult.GetResult();
}
decltype(boneAnimations) parentFillerAnimations;
// Go through all the animations and make sure we create animations for bones who's parents don't have an animation
for (auto&& anim : boneAnimations)
{
aiNode* node = scene->mRootNode->FindNode(anim.first.c_str());
aiNode* parent = node->mParent;
while (parent && parent != scene->mRootNode)
{
if (!IsPivotNode(parent->mName))
{
if (boneAnimations.find(parent->mName.C_Str()) == boneAnimations.end() &&
parentFillerAnimations.find(parent->mName.C_Str()) == parentFillerAnimations.end())
{
// Create 1 key for each type that just copies the current transform
ConsolidatedNodeAnim emptyAnimation;
aiMatrix4x4 globalTransform = GetConcatenatedLocalTransform(parent);
aiVector3D position, scale;
aiQuaternion rotation;
globalTransform.Decompose(scale, rotation, position);
emptyAnimation.mNumRotationKeys = emptyAnimation.mNumPositionKeys = emptyAnimation.mNumScalingKeys = 1;
emptyAnimation.m_ownedPositionKeys.emplace_back(0, position);
emptyAnimation.mPositionKeys = emptyAnimation.m_ownedPositionKeys.data();
emptyAnimation.m_ownedRotationKeys.emplace_back(0, rotation);
emptyAnimation.mRotationKeys = emptyAnimation.m_ownedRotationKeys.data();
emptyAnimation.m_ownedScalingKeys.emplace_back(0, scale);
emptyAnimation.mScalingKeys = emptyAnimation.m_ownedScalingKeys.data();
parentFillerAnimations.insert(
AZStd::make_pair(parent->mName.C_Str(), AZStd::make_pair(anim.second.first, AZStd::move(emptyAnimation))));
}
}
parent = parent->mParent;
}
}
boneAnimations.insert(AZStd::make_move_iterator(parentFillerAnimations.begin()), AZStd::make_move_iterator(parentFillerAnimations.end()));
auto animItr = boneAnimations.equal_range(currentNode->mName.C_Str());
if (animItr.first == animItr.second)
{
return combinedAnimationResult.GetResult();
}
bool onlyOne = false;
for (auto it = animItr.first; it != animItr.second; ++it)
{
if (onlyOne)
{
AZ_Error("AnimationImporter", false, "Bone %s has multiple animations. Only 1 animation per bone is supported", currentNode->mName.C_Str());
break;
}
const aiAnimation* animation = it->second.first;
const ConsolidatedNodeAnim* anim = &it->second.second;
// We don't currently handle having a different number of keys, with 1 exception:
// 1 key is essentially a constant so we do handle that case
if ((anim->mNumPositionKeys != anim->mNumRotationKeys && anim->mNumPositionKeys > 1 && anim->mNumRotationKeys > 1) ||
(anim->mNumPositionKeys != anim->mNumScalingKeys && anim->mNumPositionKeys > 1 && anim->mNumScalingKeys > 1) ||
(anim->mNumRotationKeys != anim->mNumScalingKeys && anim->mNumRotationKeys > 1 && anim->mNumScalingKeys > 1))
{
AZ_Error("AnimationImporter", false, "Bone Animation with different number of position (%d)/rotation (%d)/scaling (%d) keys not supported",
anim->mNumPositionKeys, anim->mNumRotationKeys, anim->mNumScalingKeys);
return Events::ProcessingResult::Failure;
}
unsigned numAnimationKeys = anim->mNumPositionKeys;
if (numAnimationKeys <= 1)
{
numAnimationKeys = AZStd::GetMax(anim->mNumRotationKeys, anim->mNumScalingKeys);
}
auto sampleKeyFrame = [](const auto& keys, unsigned numKeys, double time)
{
AZ_Error("AnimationImporter", numKeys > 0, "Animation key set must have at least 1 key");
if (numKeys == 1)
{
return keys[0].mValue;
}
auto returnValue = keys[0].mValue;
for (unsigned keyIndex = 0; keyIndex < numKeys; ++keyIndex)
{
const auto& key = keys[keyIndex];
// We want to return the key that exactly matches the time if possible, otherwise we'll keep track of the previous time
// If we don't find an exact match and end up going past the desired time (or run out of keyframes) then we return the previous key
if (key.mTime < time)
{
returnValue = key.mValue;
}
else if (key.mTime == time)
{
return key.mValue;
}
else
{
return returnValue;
}
}
return returnValue;
};
AZStd::shared_ptr<SceneData::GraphData::AnimationData> createdAnimationData =
AZStd::make_shared<SceneData::GraphData::AnimationData>();
createdAnimationData->ReserveKeyFrames(animation->mDuration + 1); // +1 because we start at 0 and the last keyframe is at mDuration instead of mDuration-1
createdAnimationData->SetTimeStepBetweenFrames(1.0 / animation->mTicksPerSecond);
for (unsigned time = 0; time <= animation->mDuration; ++time)
{
auto scale = sampleKeyFrame(anim->mScalingKeys, anim->mNumScalingKeys, time);
auto position = sampleKeyFrame(anim->mPositionKeys, anim->mNumPositionKeys, time);
auto rotation = sampleKeyFrame(anim->mRotationKeys, anim->mNumRotationKeys, time);
aiMatrix4x4 transform(scale, rotation, position);
DataTypes::MatrixType animTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(transform);
context.m_sourceSceneSystem.SwapTransformForUpAxis(animTransform);
context.m_sourceSceneSystem.ConvertBoneUnit(animTransform);
createdAnimationData->AddKeyFrame(animTransform);
}
Containers::SceneGraph::NodeIndex addNode = context.m_scene.GetGraph().AddChild(
context.m_currentGraphPosition, nodeName.c_str(), AZStd::move(createdAnimationData));
context.m_scene.GetGraph().MakeEndPoint(addNode);
onlyOne = true;
}
combinedAnimationResult += Events::ProcessingResult::Success;
return combinedAnimationResult.GetResult();
}
Events::ProcessingResult AssImpAnimationImporter::ImportBlendShapeAnimation(
AssImpSceneNodeAppendedContext& context,
const aiAnimation* animation,
const aiMeshMorphAnim* meshMorphAnim,
const aiMesh* mesh)
{
if (meshMorphAnim->mNumKeys == 0)
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedAnimationResult;
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
// In:
// Key index
// Time
// Values in AssImp, Channel in FBX SDK
// Weights in AssImp, Values in FBX SDK
// Num values & weights
// Out:
// One BlendShapeAnimationData per value (Channel in FBX SDK) index
// SetTimeStepBetweenFrames set on the animation data
// Keyframes. Weights (Values in FBX SDK) per key time.
// Keyframes generated for every single frame of the animation.
// Helper class to store key data, when translating from AssImp layout to the engine's scene format.
struct KeyData
{
KeyData(float weight, float time) :
m_weight(weight),
m_time(time)
{
}
bool operator<(const KeyData& other) const
{
return m_time < other.m_time;
}
// Naming in the previous SDK (FBX SDK) and in the engine's scene format
// doesn't match AssImp's naming convention.
// weight here is the AssImp's name for the data, it was named value in FBX SDK.
float m_weight = 0;
float m_time = 0;
};
typedef AZStd::map<int, AZStd::vector<KeyData>> ValueToKeyDataMap;
ValueToKeyDataMap valueToKeyDataMap;
for (int keyIdx = 0; keyIdx < meshMorphAnim->mNumKeys; keyIdx++)
{
aiMeshMorphKey& key = meshMorphAnim->mKeys[keyIdx];
for (int valIdx = 0; valIdx < key.mNumValuesAndWeights; ++valIdx)
{
int currentValue = key.mValues[valIdx];
KeyData thisKey(key.mWeights[valIdx], key.mTime);
valueToKeyDataMap[currentValue].insert(
AZStd::upper_bound(valueToKeyDataMap[currentValue].begin(), valueToKeyDataMap[currentValue].end(),thisKey),
thisKey);
}
}
for (const auto& [meshIdx, keys] : valueToKeyDataMap)
{
AZStd::shared_ptr<SceneData::GraphData::BlendShapeAnimationData> morphAnimNode =
AZStd::make_shared<SceneData::GraphData::BlendShapeAnimationData>();
morphAnimNode->ReserveKeyFrames(animation->mDuration + 1);
morphAnimNode->SetTimeStepBetweenFrames(1.0 / animation->mTicksPerSecond);
aiAnimMesh* aiAnimMesh = mesh->mAnimMeshes[meshIdx];
AZStd::string_view nodeName(aiAnimMesh->mName.C_Str());
const unsigned maxKeys = keys.size();
unsigned keyIdx = 0;
for (unsigned time = 0; time <= animation->mDuration; ++time)
{
if (keyIdx < maxKeys - 1 && time >= keys[keyIdx+1].m_time)
{
++keyIdx;
}
float weight_value = keys[keyIdx].m_weight;
if (keyIdx < maxKeys - 1)
{
float nextWeight = keys[keyIdx+1].m_weight;
float normalizedTimeBetweenFrames = 0;
if (keys[keyIdx + 1].m_time != keys[keyIdx].m_time)
{
normalizedTimeBetweenFrames =
(time - keys[keyIdx].m_time) / (keys[keyIdx + 1].m_time - keys[keyIdx].m_time);
}
else
{
AZ_Warning("AnimationImporter", false,
"Morph target mesh %s has keys with duplicate time, at indices %d and %d. The second will be ignored.",
nodeName.data(),
keyIdx,
keyIdx+1);
}
// AssImp and FBX both only support linear interpolation for blend shapes.
weight_value = AZ::Lerp(weight_value, nextWeight, normalizedTimeBetweenFrames);
}
morphAnimNode->AddKeyFrame(weight_value);
}
const size_t dotIndex = nodeName.find_last_of('.');
nodeName = nodeName.substr(dotIndex + 1);
morphAnimNode->SetBlendShapeName(nodeName.data());
AZStd::string animNodeName(AZStd::string::format("%s_%s", s_animationNodeName, nodeName.data()));
Containers::SceneGraph::NodeIndex addNode = context.m_scene.GetGraph().AddChild(
context.m_currentGraphPosition, animNodeName.c_str(), AZStd::move(morphAnimNode));
context.m_scene.GetGraph().MakeEndPoint(addNode);
}
return Events::ProcessingResult::Success;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,54 @@
/*
* 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.
*
*/
#pragma once
#include <SceneAPI/FbxSceneBuilder/ImportContexts/FbxImportContexts.h>
#include <SceneAPI/FbxSDKWrapper/FbxTimeWrapper.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
struct aiAnimation;
struct aiMesh;
struct aiMeshMorphAnim;
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpAnimationImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpAnimationImporter, "{93b3f4e3-6fcd-42b9-a74e-5923f76d25c7}", SceneCore::LoadingComponent);
AssImpAnimationImporter();
~AssImpAnimationImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportAnimation(AssImpSceneNodeAppendedContext& context);
Events::ProcessingResult ImportBlendShapeAnimation(
AssImpSceneNodeAppendedContext& context,
const aiAnimation* animation,
const aiMeshMorphAnim* meshMorphAnim,
const aiMesh* mesh);
protected:
static const char* s_animationNodeName;
static const FbxSDKWrapper::FbxTimeWrapper::TimeMode s_defaultTimeMode;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,119 @@
/*
* 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 <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpBitangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexBitangentData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <assimp/scene.h>
#include <assimp/mesh.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const char* AssImpBitangentStreamImporter::m_defaultNodeName = "Bitangent";
AssImpBitangentStreamImporter::AssImpBitangentStreamImporter()
{
BindToCall(&AssImpBitangentStreamImporter::ImportBitangentStreams);
}
void AssImpBitangentStreamImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpBitangentStreamImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpBitangentStreamImporter::ImportBitangentStreams(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", m_defaultNodeName);
if (!context.m_sourceNode.ContainsMesh())
{
return Events::ProcessingResult::Ignored;
}
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
AZStd::shared_ptr<DataTypes::IGraphObject> parentData =
context.m_scene.GetGraph().GetNodeContent(context.m_currentGraphPosition);
if (!parentData || !parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct bitangent stream attribute for invalid or non-mesh parent data");
return Events::ProcessingResult::Failure;
}
const SceneData::GraphData::MeshData* const parentMeshData = azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
size_t vertexCount = parentMeshData->GetVertexCount();
int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
if (sdkMeshIndex < 0 || sdkMeshIndex >= currentNode->mNumMeshes)
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct bitangent stream attribute for invalid or non-mesh parent data, mesh index is invalid");
return Events::ProcessingResult::Failure;
}
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
if (!mesh->HasTangentsAndBitangents())
{
return Events::ProcessingResult::Ignored;
}
AZStd::shared_ptr<SceneData::GraphData::MeshVertexBitangentData> bitangentStream =
AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexBitangentData>();
// AssImp only has one bitangentStream per mesh.
bitangentStream->SetBitangentSetIndex(0);
bitangentStream->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromFbx);
bitangentStream->ReserveContainerSpace(vertexCount);
for (int v = 0; v < mesh->mNumVertices; ++v)
{
const Vector3 bitangent(
AssImpSDKWrapper::AssImpTypeConverter::ToVector3(mesh->mBitangents[v]));
bitangentStream->AppendBitangent(bitangent);
}
AZStd::string nodeName(AZStd::string::format("%s",m_defaultNodeName));
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
Events::ProcessingResult bitangentResults;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, bitangentStream, newIndex, nodeName.c_str());
bitangentResults = Events::Process(dataPopulated);
if (bitangentResults != Events::ProcessingResult::Failure)
{
bitangentResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
return bitangentResults;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,40 @@
/*
* 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 <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpBitangentStreamImporter : public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpBitangentStreamImporter, "{49FC818A-956F-43DA-BBAC-73198E0C5A1F}", SceneCore::LoadingComponent);
AssImpBitangentStreamImporter();
~AssImpBitangentStreamImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportBitangentStreams(AssImpSceneNodeAppendedContext& context);
protected:
static const char* m_defaultNodeName;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,172 @@
/*
* 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 <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/string/conversions.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpBlendShapeImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <SceneAPI/SceneData/GraphData/SkinMeshData.h>
#include <SceneAPI/SceneData/GraphData/BlendShapeData.h>
#include <assimp/scene.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
AssImpBlendShapeImporter::AssImpBlendShapeImporter()
{
BindToCall(&AssImpBlendShapeImporter::ImportBlendShapes);
}
void AssImpBlendShapeImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpBlendShapeImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpBlendShapeImporter::ImportBlendShapes(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Blend Shapes");
int numMesh = context.m_sourceNode.GetAssImpNode()->mNumMeshes;
bool animMeshExists = false;
for (int idx = 0; idx < numMesh; idx++)
{
int meshId = context.m_sourceNode.GetAssImpNode()->mMeshes[idx];
aiMesh* aiMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[meshId];
if (aiMesh->mNumAnimMeshes)
{
animMeshExists = true;
break;
}
}
if (!animMeshExists)
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedBlendShapeResult;
for (int meshIdx = 0; meshIdx < numMesh; meshIdx++)
{
int meshId = context.m_sourceNode.GetAssImpNode()->mMeshes[meshIdx];
aiMesh* aiMesh = context.m_sourceScene.GetAssImpScene()->mMeshes[meshId];
if (!aiMesh->mNumAnimMeshes)
{
continue;
}
for (int animIdx = 0; animIdx < aiMesh->mNumAnimMeshes; animIdx++)
{
AZStd::shared_ptr<SceneData::GraphData::BlendShapeData> blendShapeData =
AZStd::make_shared<SceneData::GraphData::BlendShapeData>();
aiAnimMesh* aiAnimMesh = aiMesh->mAnimMeshes[animIdx];
AZStd::string nodeName(aiAnimMesh->mName.C_Str());
size_t dotIndex = nodeName.rfind('.');
if (dotIndex != AZStd::string::npos)
{
nodeName.erase(0, dotIndex + 1);
}
RenamedNodesMap::SanitizeNodeName(nodeName, context.m_scene.GetGraph(), context.m_currentGraphPosition, "BlendShape");
AZ_TraceContext("Blend shape name", nodeName);
int firstMeshVertexIndex = -1;
int previousMeshVertexIndex = -1;
int verticesInMeshFace = 0;
for (int vertIdx = 0; vertIdx < aiAnimMesh->mNumVertices; ++vertIdx)
{
AZ::Vector3 vertex(AssImpSDKWrapper::AssImpTypeConverter::ToVector3(aiAnimMesh->mVertices[vertIdx]));
context.m_sourceSceneSystem.SwapVec3ForUpAxis(vertex);
context.m_sourceSceneSystem.ConvertUnit(vertex);
AZ::Vector3 normal;
if (aiAnimMesh->HasNormals())
{
normal = AssImpSDKWrapper::AssImpTypeConverter::ToVector3(aiAnimMesh->mNormals[vertIdx]);
context.m_sourceSceneSystem.SwapVec3ForUpAxis(normal);
normal.NormalizeSafe();
}
blendShapeData->AddVertex(vertex, normal);
blendShapeData->SetVertexIndexToControlPointIndexMap(vertIdx, vertIdx);
}
// aiAnimMesh just has a list of positions for vertices. The face indices are on the original mesh.
for (int faceIdx = 0; faceIdx < aiMesh->mNumFaces; ++faceIdx)
{
aiFace face = aiMesh->mFaces[faceIdx];
DataTypes::IBlendShapeData::Face blendFace;
if (face.mNumIndices != 3)
{
// AssImp should have triangulated everything, so if this happens then someone has
// probably changed AssImp's import settings. The engine only supports triangles.
AZ_Error(
Utilities::ErrorWindow, false,
"Mesh for node %s has a face with %d vertices, only 3 vertices are supported per face.",
nodeName.c_str(),
face.mNumIndices);
continue;
}
for (int idx = 0; idx < face.mNumIndices; ++idx)
{
blendFace.vertexIndex[idx] = face.mIndices[idx];
}
blendShapeData->AddFace(blendFace);
}
// Report problem if no vertex or face converted to MeshData
if (blendShapeData->GetVertexCount() <= 0 || blendShapeData->GetFaceCount() <= 0)
{
AZ_Error(Utilities::ErrorWindow, false, "Missing geometry data in blendshape node %s.", nodeName.c_str());
return Events::ProcessingResult::Failure;
}
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
Events::ProcessingResult blendShapeResult;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, blendShapeData, newIndex, nodeName);
blendShapeResult = Events::Process(dataPopulated);
if (blendShapeResult != Events::ProcessingResult::Failure)
{
blendShapeResult = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedBlendShapeResult += blendShapeResult;
}
}
return combinedBlendShapeResult.GetResult();
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,39 @@
/*
* 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.
*
*/
#pragma once
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpBlendShapeImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpBlendShapeImporter, "{B0F7174B-9863-4C03-BFB2-83BF29B1A2DD}", SceneCore::LoadingComponent);
AssImpBlendShapeImporter();
~AssImpBlendShapeImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportBlendShapes(AssImpSceneNodeAppendedContext& context);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -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.
*
*/
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpBoneImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSDKWrapper/FbxNodeWrapper.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneData/GraphData/BoneData.h>
#include <SceneAPI/SceneData/GraphData/RootBoneData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
AssImpBoneImporter::AssImpBoneImporter()
{
BindToCall(&AssImpBoneImporter::ImportBone);
}
void AssImpBoneImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpBoneImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
void EnumBonesInNode(
const aiScene* scene, const aiNode* node, AZStd::unordered_map<AZStd::string, aiNode*>& mainBoneList,
AZStd::unordered_map<AZStd::string, aiBone*>& boneLookup)
{
/* From AssImp Documentation
a) Create a map or a similar container to store which nodes are necessary for the skeleton. Pre-initialise it for all nodes with a "no".
b) For each bone in the mesh:
b1) Find the corresponding node in the scene's hierarchy by comparing their names.
b2) Mark this node as "yes" in the necessityMap.
b3) Mark all of its parents the same way until you 1) find the mesh's node or 2) the parent of the mesh's node.
c) Recursively iterate over the node hierarchy
c1) If the node is marked as necessary, copy it into the skeleton and check its children
c2) If the node is marked as not necessary, skip it and do not iterate over its children.
*/
for (unsigned meshIndex = 0; meshIndex < node->mNumMeshes; ++meshIndex)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[meshIndex]];
for (unsigned boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex)
{
aiBone* bone = mesh->mBones[boneIndex];
aiNode* boneNode = scene->mRootNode->FindNode(bone->mName);
aiNode* boneParent = boneNode->mParent;
mainBoneList[bone->mName.C_Str()] = boneNode;
boneLookup[bone->mName.C_Str()] = bone;
while (boneParent && boneParent != node && boneParent != node->mParent && boneParent != scene->mRootNode)
{
mainBoneList[boneParent->mName.C_Str()] = boneParent;
boneParent = boneParent->mParent;
}
}
}
}
void EnumChildren(
const aiScene* scene, const aiNode* node, AZStd::unordered_map<AZStd::string, aiNode*>& mainBoneList,
AZStd::unordered_map<AZStd::string, aiBone*>& boneLookup)
{
EnumBonesInNode(scene, node, mainBoneList, boneLookup);
for (unsigned childIndex = 0; childIndex < node->mNumChildren; ++childIndex)
{
const aiNode* child = node->mChildren[childIndex];
EnumChildren(scene, child, mainBoneList, boneLookup);
}
}
Events::ProcessingResult AssImpBoneImporter::ImportBone(AssImpNodeEncounteredContext& context)
{
AZ_TraceContext("Importer", "Bone");
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if (IsPivotNode(currentNode->mName))
{
return Events::ProcessingResult::Ignored;
}
bool isBone = false;
if (NodeParentIsOfType(context.m_scene.GetGraph(), context.m_currentGraphPosition, DataTypes::IBoneData::TYPEINFO_Uuid()))
{
isBone = true;
}
else
{
AZStd::unordered_map<AZStd::string, aiNode*> mainBoneList;
AZStd::unordered_map<AZStd::string, aiBone*> boneLookup;
EnumChildren(scene, scene->mRootNode, mainBoneList, boneLookup);
if (mainBoneList.find(currentNode->mName.C_Str()) != mainBoneList.end())
{
isBone = true;
}
// If we have an animation, the bones will be listed in there
if (!isBone)
{
for(unsigned animIndex = 0; animIndex < scene->mNumAnimations; ++animIndex)
{
aiAnimation* animation = scene->mAnimations[animIndex];
for (unsigned channelIndex = 0; channelIndex < animation->mNumChannels; ++channelIndex)
{
aiNodeAnim* nodeAnim = animation->mChannels[channelIndex];
if (nodeAnim->mNodeName == currentNode->mName)
{
isBone = true;
break;
}
}
if (isBone)
{
break;
}
}
}
}
if(!isBone)
{
return Events::ProcessingResult::Ignored;
}
// If the current scene node (our eventual parent) contains bone data, we are not a root bone
AZStd::shared_ptr<SceneData::GraphData::BoneData> createdBoneData;
if (NodeHasAncestorOfType(
context.m_scene.GetGraph(), context.m_currentGraphPosition, DataTypes::IBoneData::TYPEINFO_Uuid()))
{
createdBoneData = AZStd::make_shared<SceneData::GraphData::BoneData>();
}
else
{
createdBoneData = AZStd::make_shared<SceneData::GraphData::RootBoneData>();
}
aiMatrix4x4 transform = currentNode->mTransformation;
aiNode* parent = currentNode->mParent;
while (parent)
{
transform = parent->mTransformation * transform;
parent = parent->mParent;
}
SceneAPI::DataTypes::MatrixType globalTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(transform);
context.m_sourceSceneSystem.SwapTransformForUpAxis(globalTransform);
context.m_sourceSceneSystem.ConvertBoneUnit(globalTransform);
createdBoneData->SetWorldTransform(globalTransform);
context.m_createdData.push_back(AZStd::move(createdBoneData));
return Events::ProcessingResult::Success;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,39 @@
/*
* 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.
*
*/
#pragma once
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpBoneImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpBoneImporter, "{E7A62DE7-B660-4920-BF91-32738175D5A7}", SceneCore::LoadingComponent);
AssImpBoneImporter();
~AssImpBoneImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportBone(AssImpNodeEncounteredContext& context);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -58,11 +58,10 @@ namespace AZ
AZStd::shared_ptr<DataTypes::IGraphObject> parentData =
context.m_scene.GetGraph().GetNodeContent(context.m_currentGraphPosition);
AZ_Assert(
parentData && parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()),
"Tried to construct color stream attribute for invalid or non-mesh parent data");
if (!parentData || !parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct color stream attribute for invalid or non-mesh parent data");
return Events::ProcessingResult::Failure;
}
const SceneData::GraphData::MeshData* const parentMeshData = azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
@@ -71,9 +70,7 @@ namespace AZ
int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
if (sdkMeshIndex < 0)
{
AZ_Error(
Utilities::ErrorWindow,
false,
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct color stream attribute for invalid or non-mesh parent data, mesh index is missing");
return Events::ProcessingResult::Failure;
}
@@ -0,0 +1,94 @@
/*
* 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 <SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.h>
#include <AzCore/Debug/Trace.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <assimp/scene.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
bool IsSkinnedMesh(const aiNode& node, const aiScene& scene)
{
unsigned boneCount = 0;
for (unsigned mesh = 0; mesh < node.mNumMeshes; ++mesh)
{
if (scene.mMeshes[node.mMeshes[mesh]]->HasBones())
{
++boneCount;
}
}
if (boneCount > 1 && boneCount != node.mNumMeshes)
{
AZ_Error("AssImpImporterUtilities", false, "Node has %d meshes but only %d are skinned. "
"This is unexpected and may result in errors", node.mNumMeshes, boneCount);
}
return boneCount > 0;
}
bool IsPivotNode(const aiString& nodeName, size_t* pos)
{
AZStd::string_view name(nodeName.C_Str(), nodeName.length);
size_t myPos;
if (!pos)
{
pos = &myPos;
}
*pos = AZ::StringFunc::Find(name, PivotNodeMarker);
return *pos != name.npos;
}
void SplitPivotNodeName(const aiString& nodeName, size_t pivotPos, AZStd::string_view& baseNodeName, AZStd::string_view& pivotType)
{
AZStd::string_view nodeNameView(nodeName.data, nodeName.length);
baseNodeName = AZStd::string_view(nodeNameView.substr(0, pivotPos));
pivotType = AZStd::string_view(nodeNameView.substr(pivotPos + sizeof PivotNodeMarker - 1));
}
aiMatrix4x4 GetConcatenatedLocalTransform(const aiNode* currentNode)
{
aiNode* parent = currentNode->mParent;
aiMatrix4x4 combinedTransform = currentNode->mTransformation;
while (parent)
{
size_t pos;
if (IsPivotNode(parent->mName, &pos))
{
combinedTransform = parent->mTransformation * combinedTransform;
parent = parent->mParent;
}
else
{
break;
}
}
return combinedTransform;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,38 @@
/*
* 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.
*
*/
#pragma once
#include <assimp/matrix4x4.h>
#include <AzCore/std/string/string.h>
struct aiNode;
struct aiScene;
struct aiString;
namespace AZ::SceneAPI::FbxSceneBuilder
{
inline constexpr char PivotNodeMarker[] = "_$AssimpFbx$_";
bool IsSkinnedMesh(const aiNode& node, const aiScene& scene);
// Checks if a node name is a pivot node and optionally returns the position in the name of the pivot marker (for splitting out the parts later)
bool IsPivotNode(const aiString& nodeName, size_t* pos = nullptr);
// Returns the bone name and type of a pivot node
void SplitPivotNodeName(const aiString& nodeName, size_t pivotPos, AZStd::string_view& baseNodeName, AZStd::string_view& pivotType);
// Gets the entire, combined local transform for a node taking pivot nodes into account. When pivot nodes are not used, this just returns the node's transform
aiMatrix4x4 GetConcatenatedLocalTransform(const aiNode* currentNode);
} // namespace AZ
@@ -11,9 +11,11 @@
*/
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMaterialImporter.h>
#include <AzCore/IO/FileIO.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/containers/unordered_map.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
@@ -54,6 +56,8 @@ namespace AZ
}
Events::ProcessingResultCombiner combinedMaterialImportResults;
AZStd::unordered_map<int, AZStd::shared_ptr<SceneData::GraphData::MaterialData>> materialMap;
for (int idx = 0; idx < context.m_sourceNode.m_assImpNode->mNumMeshes; ++idx)
{
int meshIndex = context.m_sourceNode.m_assImpNode->mMeshes[idx];
@@ -62,8 +66,6 @@ namespace AZ
int materialIndex = assImpMesh->mMaterialIndex;
AZ_TraceContext("Material Index", materialIndex);
AZStd::unordered_map<int, AZStd::shared_ptr<SceneData::GraphData::MaterialData>> materialMap;
auto matFound = materialMap.find(materialIndex);
AZStd::shared_ptr<SceneData::GraphData::MaterialData> material;
@@ -82,19 +84,58 @@ namespace AZ
material->SetMaterialName(assImpMaterial->GetName());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Diffuse,
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Diffuse).c_str());
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Diffuse)).c_str());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Specular,
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Specular).c_str());
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Specular)).c_str());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Bump,
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Bump).c_str());
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Bump)).c_str());
material->SetTexture(DataTypes::IMaterialData::TextureMapType::Normal,
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Normal).c_str());
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Normal)).c_str());
material->SetUniqueId(assImpMaterial->GetUniqueId());
material->SetDiffuseColor(assImpMaterial->GetDiffuseColor());
material->SetSpecularColor(assImpMaterial->GetSpecularColor());
material->SetEmissiveColor(assImpMaterial->GetEmissiveColor());
material->SetShininess(assImpMaterial->GetShininess());
material->SetUseColorMap(assImpMaterial->GetUseColorMap());
material->SetBaseColor(assImpMaterial->GetBaseColor());
material->SetUseMetallicMap(assImpMaterial->GetUseMetallicMap());
material->SetMetallicFactor(assImpMaterial->GetMetallicFactor());
material->SetTexture(
DataTypes::IMaterialData::TextureMapType::Metallic,
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Metallic).c_str()));
material->SetUseRoughnessMap(assImpMaterial->GetUseRoughnessMap());
material->SetRoughnessFactor(assImpMaterial->GetRoughnessFactor());
material->SetTexture(
DataTypes::IMaterialData::TextureMapType::Roughness,
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Roughness).c_str()));
material->SetUseEmissiveMap(assImpMaterial->GetUseEmissiveMap());
material->SetEmissiveIntensity(assImpMaterial->GetEmissiveIntensity());
material->SetUseAOMap(assImpMaterial->GetUseAOMap());
material->SetTexture(
DataTypes::IMaterialData::TextureMapType::AmbientOcclusion,
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::AmbientOcclusion).c_str()));
material->SetTexture(
DataTypes::IMaterialData::TextureMapType::Emissive,
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::Emissive).c_str()));
material->SetTexture(
DataTypes::IMaterialData::TextureMapType::BaseColor,
ResolveTexturePath(context.m_sourceScene.GetSceneFileName(),
assImpMaterial->GetTextureFileName(SDKMaterial::MaterialWrapper::MaterialMapType::BaseColor).c_str()));
AZ_Assert(material, "Failed to allocate scene material data.");
if (!material)
@@ -135,6 +176,39 @@ namespace AZ
return combinedMaterialImportResults.GetResult();
}
AZStd::string AssImpMaterialImporter::ResolveTexturePath(const AZStd::string& sceneFilePath, const AZStd::string& textureFilePath) const
{
if (textureFilePath.empty())
{
return textureFilePath;
}
AZStd::string texturePathRelativeToScene;
AZStd::string cleanedUpSceneFilePath(sceneFilePath);
AZ::StringFunc::Path::StripFullName(cleanedUpSceneFilePath);
AZ::StringFunc::Path::Join(cleanedUpSceneFilePath.c_str(), textureFilePath.c_str(), texturePathRelativeToScene);
// If the texture did start with marker to change directories upward, then it's relative to the FBX file,
// and that path needs to be resolved. It can't be resolved later. This was handled internally by FBX SDK,
// but is not handled by AssImp.
if (textureFilePath.starts_with(".."))
{
// Not checking for the file existing because it may not be there yet.
return texturePathRelativeToScene;
}
// The engine only supports relative paths to scan folders.
// FBX files may have paths to textures, relative to the FBX file. Check for those, first.
if (AZ::IO::FileIOBase::GetInstance()->Exists(texturePathRelativeToScene.c_str()))
{
return texturePathRelativeToScene;
}
return textureFilePath;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -33,6 +33,9 @@ namespace AZ
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportMaterials(AssImpSceneNodeAppendedContext& context);
private:
AZStd::string ResolveTexturePath(const AZStd::string& sceneFilePath, const AZStd::string& textureFilePath) const;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
@@ -9,19 +9,17 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMeshImporter.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <assimp/scene.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/SceneCore/Containers/Scene.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpMeshImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <assimp/scene.h>
#include <assimp/mesh.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
namespace AZ
{
@@ -46,80 +44,23 @@ namespace AZ
Events::ProcessingResult AssImpMeshImporter::ImportMesh(AssImpNodeEncounteredContext& context)
{
AZ_TraceContext("Importer", "Mesh");
if (!context.m_sourceNode.ContainsMesh())
{
return Events::ProcessingResult::Ignored;
}
AZStd::unordered_map<int, int> assImpMatIndexToLYIndex;
int lyMeshIndex = 0;
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
for (int m = 0; m < currentNode->mNumMeshes; ++m)
if (!context.m_sourceNode.ContainsMesh() || IsSkinnedMesh(*currentNode, *scene))
{
AZStd::shared_ptr<SceneData::GraphData::MeshData> newMesh =
AZStd::make_shared<SceneData::GraphData::MeshData>();
newMesh->SetUnitSizeInMeters(context.m_sourceSceneSystem.GetUnitSizeInMeters());
newMesh->SetOriginalUnitSizeInMeters(context.m_sourceSceneSystem.GetOriginalUnitSizeInMeters());
newMesh->SetSdkMeshIndex(m);
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[m]];
// Lumberyard materials are created in order based on mesh references in the scene
if (assImpMatIndexToLYIndex.find(mesh->mMaterialIndex) == assImpMatIndexToLYIndex.end())
{
assImpMatIndexToLYIndex.insert(AZStd::pair<int, int>(mesh->mMaterialIndex, lyMeshIndex++));
}
for (int vertIdx = 0; vertIdx < mesh->mNumVertices; ++vertIdx)
{
AZ::Vector3 vertex(
mesh->mVertices[vertIdx].x,
mesh->mVertices[vertIdx].y,
mesh->mVertices[vertIdx].z);
context.m_sourceSceneSystem.SwapVec3ForUpAxis(vertex);
context.m_sourceSceneSystem.ConvertUnit(vertex);
newMesh->AddPosition(vertex);
if (mesh->HasNormals())
{
AZ::Vector3 normal(
mesh->mNormals[vertIdx].x,
mesh->mNormals[vertIdx].y,
mesh->mNormals[vertIdx].z);
context.m_sourceSceneSystem.SwapVec3ForUpAxis(normal);
normal.NormalizeSafe();
newMesh->AddNormal(normal);
}
}
for (int faceIdx = 0; faceIdx < mesh->mNumFaces; ++faceIdx)
{
aiFace face = mesh->mFaces[faceIdx];
AZ::SceneAPI::DataTypes::IMeshData::Face meshFace;
if (face.mNumIndices != 3)
{
// AssImp should have triangulated everything, so if this happens then someone has
// probably changed AssImp's import settings. The engine only supports triangles.
AZ_Error(Utilities::ErrorWindow, false, "Mesh has a face with %d vertices, only 3 vertices are supported per face.");
continue;
}
for (int idx = 0; idx < face.mNumIndices; ++idx)
{
meshFace.vertexIndex[idx] = face.mIndices[idx];
}
newMesh->AddFace(meshFace, assImpMatIndexToLYIndex[mesh->mMaterialIndex]);
}
context.m_createdData.push_back(std::move(newMesh));
return Events::ProcessingResult::Ignored;
}
return Events::ProcessingResult::Success;
if (BuildSceneMeshFromAssImpMesh(currentNode, scene, context.m_sourceSceneSystem, context.m_createdData, [] {
return AZStd::make_shared<SceneData::GraphData::MeshData>();
}))
{
return Events::ProcessingResult::Success;
}
return Events::ProcessingResult::Failure;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
@@ -0,0 +1,67 @@
/*
* 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 <assimp/scene.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpSkinImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/SceneData/GraphData/SkinMeshData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
AssImpSkinImporter::AssImpSkinImporter()
{
BindToCall(&AssImpSkinImporter::ImportSkin);
}
void AssImpSkinImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpSkinImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpSkinImporter::ImportSkin(AssImpNodeEncounteredContext& context)
{
AZ_TraceContext("Importer", "Skin");
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if (!context.m_sourceNode.ContainsMesh() || !IsSkinnedMesh(*currentNode, *scene))
{
return Events::ProcessingResult::Ignored;
}
if (BuildSceneMeshFromAssImpMesh(currentNode, scene, context.m_sourceSceneSystem, context.m_createdData, [] {
return AZStd::make_shared<SceneData::GraphData::SkinMeshData>();
}))
{
return Events::ProcessingResult::Success;
}
return Events::ProcessingResult::Failure;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,39 @@
/*
* 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.
*
*/
#pragma once
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpSkinImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpSkinImporter, "{8FBCA725-C04E-42B7-9669-82DB3BB0901F}", SceneCore::LoadingComponent);
AssImpSkinImporter();
~AssImpSkinImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportSkin(AssImpNodeEncounteredContext& context);
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -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.
*
*/
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/std/string/conversions.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpSkinWeightsImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/RenamedNodesMap.h>
#include <SceneAPI/SceneCore/Events/ImportEventContext.h>
#include <SceneAPI/SceneData/GraphData/SkinWeightData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const AZStd::string AssImpSkinWeightsImporter::s_skinWeightName = "SkinWeight_";
AssImpSkinWeightsImporter::AssImpSkinWeightsImporter()
{
BindToCall(&AssImpSkinWeightsImporter::ImportSkinWeights);
BindToCall(&AssImpSkinWeightsImporter::SetupNamedBoneLinks);
}
void AssImpSkinWeightsImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpSkinWeightsImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpSkinWeightsImporter::ImportSkinWeights(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "Skin Weights");
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if(currentNode->mNumMeshes <= 0)
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedSkinWeightsResult;
for(unsigned m = 0; m < currentNode->mNumMeshes; ++m)
{
auto mesh = scene->mMeshes[currentNode->mMeshes[m]];
for(unsigned b = 0; b < mesh->mNumBones; ++b)
{
auto bone = mesh->mBones[b];
if(bone->mNumWeights <= 0)
{
continue;
}
AZStd::string skinWeightName = s_skinWeightName;
skinWeightName += AZStd::to_string(b);
RenamedNodesMap::SanitizeNodeName(skinWeightName, context.m_scene.GetGraph(), context.m_currentGraphPosition);
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> skinDeformer = BuildSkinWeightData(bone, mesh->mNumVertices);
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, skinWeightName.c_str());
AZ_Error("SkinWeightsImporter", newIndex.IsValid(), "Failed to create SceneGraph node for attribute.");
if (!newIndex.IsValid())
{
combinedSkinWeightsResult += Events::ProcessingResult::Failure;
continue;
}
Events::ProcessingResult skinWeightsResult;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, skinDeformer, newIndex, skinWeightName);
skinWeightsResult = Events::Process(dataPopulated);
if (skinWeightsResult != Events::ProcessingResult::Failure)
{
skinWeightsResult = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedSkinWeightsResult += skinWeightsResult;
}
}
return combinedSkinWeightsResult.GetResult();
}
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> AssImpSkinWeightsImporter::BuildSkinWeightData(aiBone* bone, unsigned numVertices)
{
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> skinWeightData =
AZStd::make_shared<SceneData::GraphData::SkinWeightData>();
// Cache the new object and the link info for now so it can be resolved at a later point when all
// names have been updated.
Pending pending;
pending.m_bone = bone;
pending.m_numVertices = numVertices;
pending.m_skinWeightData = skinWeightData;
m_pendingSkinWeights.push_back(pending);
return skinWeightData;
}
Events::ProcessingResult AssImpSkinWeightsImporter::SetupNamedBoneLinks(AssImpFinalizeSceneContext& /*context*/)
{
AZ_TraceContext("Importer", "Skin Weights");
for (auto& it : m_pendingSkinWeights)
{
it.m_skinWeightData->ResizeContainerSpace(it.m_numVertices);
AZStd::string boneName = it.m_bone->mName.C_Str();
int boneId = it.m_skinWeightData->GetBoneId(boneName);
for(unsigned weight = 0; weight < it.m_bone->mNumWeights; ++weight)
{
DataTypes::ISkinWeightData::Link link;
link.boneId = boneId;
link.weight = it.m_bone->mWeights[weight].mWeight;
it.m_skinWeightData->AppendLink(it.m_bone->mWeights[weight].mVertexId, link);
}
}
const auto result = m_pendingSkinWeights.empty() ? Events::ProcessingResult::Ignored : Events::ProcessingResult::Success;
m_pendingSkinWeights.clear();
return result;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -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.
*
*/
#pragma once
#include <assimp/scene.h>
#include <AzCore/std/containers/vector.h>
#include <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
#include <SceneAPI/SceneCore/DataTypes/GraphData/ISkinWeightData.h>
namespace AZ
{
namespace FbxSDKWrapper
{
class FbxMeshWrapper;
}
namespace SceneData
{
namespace GraphData
{
class SkinWeightData;
}
}
namespace SceneAPI
{
namespace Events
{
class PostImportEventContext;
}
namespace FbxSceneBuilder
{
class AssImpSkinWeightsImporter
: public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpSkinWeightsImporter, "{79B5E863-C155-473A-BC0D-B85F8D8303EB}", SceneCore::LoadingComponent);
AssImpSkinWeightsImporter();
~AssImpSkinWeightsImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportSkinWeights(AssImpSceneNodeAppendedContext& context);
Events::ProcessingResult SetupNamedBoneLinks(AssImpFinalizeSceneContext& context);
protected:
struct Pending
{
aiBone* m_bone = nullptr;
unsigned m_numVertices = 0;
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> m_skinWeightData;
};
AZStd::shared_ptr<SceneData::GraphData::SkinWeightData> BuildSkinWeightData(aiBone* bone, unsigned numVertices);
//! List of skin weights that still need to be filled in. Setting the data for skin weights is
//! delayed until after the tree has been fully constructed as bones are linked by name, but until
//! the graph has been fully filled in, those names can change which would break the names recorded
//! for the skin.
AZStd::vector<Pending> m_pendingSkinWeights;
static const AZStd::string s_skinWeightName;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,119 @@
/*
* 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 <AzCore/Serialization/SerializeContext.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <AzToolsFramework/Debug/TraceContext.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpTangentStreamImporter.h>
#include <SceneAPI/FbxSceneBuilder/Importers/FbxImporterUtilities.h>
#include <SceneAPI/SceneData/GraphData/MeshVertexTangentData.h>
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpTypeConverter.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
#include <assimp/scene.h>
#include <assimp/mesh.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
const char* AssImpTangentStreamImporter::m_defaultNodeName = "Tangent";
AssImpTangentStreamImporter::AssImpTangentStreamImporter()
{
BindToCall(&AssImpTangentStreamImporter::ImportTangentStreams);
}
void AssImpTangentStreamImporter::Reflect(ReflectContext* context)
{
SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<AssImpTangentStreamImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpTangentStreamImporter::ImportTangentStreams(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", m_defaultNodeName);
if (!context.m_sourceNode.ContainsMesh())
{
return Events::ProcessingResult::Ignored;
}
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
AZStd::shared_ptr<DataTypes::IGraphObject> parentData =
context.m_scene.GetGraph().GetNodeContent(context.m_currentGraphPosition);
if (!parentData || !parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct tangent stream attribute for invalid or non-mesh parent data");
return Events::ProcessingResult::Failure;
}
const SceneData::GraphData::MeshData* const parentMeshData = azrtti_cast<SceneData::GraphData::MeshData*>(parentData.get());
size_t vertexCount = parentMeshData->GetVertexCount();
int sdkMeshIndex = parentMeshData->GetSdkMeshIndex();
if (sdkMeshIndex < 0 || sdkMeshIndex >= currentNode->mNumMeshes)
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct tangent stream attribute for invalid or non-mesh parent data, mesh index is invalid");
return Events::ProcessingResult::Failure;
}
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
if (!mesh->HasTangentsAndBitangents())
{
return Events::ProcessingResult::Ignored;
}
AZStd::shared_ptr<SceneData::GraphData::MeshVertexTangentData> tangentStream =
AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexTangentData>();
// AssImp only has one tangentStream per mesh.
tangentStream->SetTangentSetIndex(0);
tangentStream->SetTangentSpace(AZ::SceneAPI::DataTypes::TangentSpace::FromFbx);
tangentStream->ReserveContainerSpace(vertexCount);
for (int v = 0; v < mesh->mNumVertices; ++v)
{
// Vector4's constructor that takes in a vector3 sets w to 1.0f automatically.
const Vector4 tangent(AssImpSDKWrapper::AssImpTypeConverter::ToVector3(mesh->mTangents[v]));
tangentStream->AppendTangent(tangent);
}
AZStd::string nodeName(AZStd::string::format("%s", m_defaultNodeName));
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, nodeName.c_str());
Events::ProcessingResult tangentResults;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, tangentStream, newIndex, nodeName.c_str());
tangentResults = Events::Process(dataPopulated);
if (tangentResults != Events::ProcessingResult::Failure)
{
tangentResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
return tangentResults;
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -0,0 +1,40 @@
/*
* 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 <SceneAPI/FbxSceneBuilder/ImportContexts/AssImpImportContexts.h>
#include <SceneAPI/SceneCore/Components/LoadingComponent.h>
namespace AZ
{
namespace SceneAPI
{
namespace FbxSceneBuilder
{
class AssImpTangentStreamImporter : public SceneCore::LoadingComponent
{
public:
AZ_COMPONENT(AssImpTangentStreamImporter, "{AB2D1D1E-5A19-40AF-B4F4-C652DD578F43}", SceneCore::LoadingComponent);
AssImpTangentStreamImporter();
~AssImpTangentStreamImporter() override = default;
static void Reflect(ReflectContext* context);
Events::ProcessingResult ImportTangentStreams(AssImpSceneNodeAppendedContext& context);
protected:
static const char* m_defaultNodeName;
};
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
@@ -23,6 +23,7 @@
#include <SceneAPI/SDKWrapper/AssImpNodeWrapper.h>
#include <SceneAPI/SDKWrapper/AssImpSceneWrapper.h>
#include <assimp/scene.h>
#include <SceneAPI/FbxSceneBuilder/Importers/AssImpImporterUtilities.h>
namespace AZ
{
@@ -45,16 +46,25 @@ namespace AZ
serializeContext->Class<AssImpTransformImporter, SceneCore::LoadingComponent>()->Version(1);
}
}
Events::ProcessingResult AssImpTransformImporter::ImportTransform(AssImpSceneNodeAppendedContext& context)
{
AZ_TraceContext("Importer", "transform");
aiNode* currentNode = context.m_sourceNode.GetAssImpNode();
const aiScene* scene = context.m_sourceScene.GetAssImpScene();
if (currentNode == scene->mRootNode || IsPivotNode(currentNode->mName))
{
return Events::ProcessingResult::Ignored;
}
DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(context.m_sourceNode.GetAssImpNode()->mTransformation);
aiMatrix4x4 combinedTransform = GetConcatenatedLocalTransform(currentNode);
DataTypes::MatrixType localTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(combinedTransform);
context.m_sourceSceneSystem.SwapTransformForUpAxis(localTransform);
context.m_sourceSceneSystem.ConvertUnit(localTransform);
AZStd::shared_ptr<SceneData::GraphData::TransformData> transformData =
AZStd::make_shared<SceneData::GraphData::TransformData>(localTransform);
AZ_Error(SceneAPI::Utilities::ErrorWindow, transformData, "Failed to allocate transform data.");
@@ -63,7 +73,6 @@ namespace AZ
return Events::ProcessingResult::Failure;
}
// If it is non-endpoint data populated node, add a transform attribute
if (context.m_scene.GetGraph().HasNodeContent(context.m_currentGraphPosition))
{
@@ -59,10 +59,10 @@ namespace AZ
AZStd::shared_ptr<DataTypes::IGraphObject> parentData =
context.m_scene.GetGraph().GetNodeContent(context.m_currentGraphPosition);
AZ_Assert(parentData && parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()),
"Tried to construct uv stream attribute for invalid or non-mesh parent data");
if (!parentData || !parentData->RTTI_IsTypeOf(SceneData::GraphData::MeshData::TYPEINFO_Uuid()))
{
AZ_Error(Utilities::ErrorWindow, false,
"Tried to construct uv stream attribute for invalid or non-mesh parent data");
return Events::ProcessingResult::Failure;
}
const SceneData::GraphData::MeshData* const parentMeshData =
@@ -75,40 +75,44 @@ namespace AZ
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[sdkMeshIndex]];
if (!mesh->mTextureCoords[0])
{
return Events::ProcessingResult::Ignored;
}
Events::ProcessingResultCombiner combinedUvMapResults;
AZStd::shared_ptr<SceneData::GraphData::MeshVertexUVData> uvMap =
AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexUVData>();
uvMap->ReserveContainerSpace(vertexCount);
uvMap->SetCustomName(m_defaultNodeName);
for (int v = 0; v < mesh->mNumVertices; ++v)
for (int texCoordIndex = 0; texCoordIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++texCoordIndex)
{
AZ::Vector2 vertexUV(
mesh->mTextureCoords[0][v].x,
mesh->mTextureCoords[0][v].y);
uvMap->AppendUV(vertexUV);
if (!mesh->mTextureCoords[texCoordIndex])
{
continue;
}
AZStd::shared_ptr<SceneData::GraphData::MeshVertexUVData> uvMap =
AZStd::make_shared<AZ::SceneData::GraphData::MeshVertexUVData>();
uvMap->ReserveContainerSpace(vertexCount);
AZStd::string name(AZStd::string::format("%s%d", m_defaultNodeName, texCoordIndex));
uvMap->SetCustomName(name.c_str());
for (int v = 0; v < mesh->mNumVertices; ++v)
{
AZ::Vector2 vertexUV(
mesh->mTextureCoords[texCoordIndex][v].x,
// The engine's V coordinate is reverse of how it's stored in the FBX file.
1.0f - mesh->mTextureCoords[texCoordIndex][v].y);
uvMap->AppendUV(vertexUV);
}
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, name.c_str());
Events::ProcessingResult uvMapResults;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, uvMap, newIndex, name);
uvMapResults = Events::Process(dataPopulated);
if (uvMapResults != Events::ProcessingResult::Failure)
{
uvMapResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedUvMapResults += uvMapResults;
}
Containers::SceneGraph::NodeIndex newIndex =
context.m_scene.GetGraph().AddChild(context.m_currentGraphPosition, m_defaultNodeName);
Events::ProcessingResult uvMapResults;
AssImpSceneAttributeDataPopulatedContext dataPopulated(context, uvMap, newIndex, m_defaultNodeName);
uvMapResults = Events::Process(dataPopulated);
if (uvMapResults != Events::ProcessingResult::Failure)
{
uvMapResults = AddAttributeDataNodeWithContexts(dataPopulated);
}
combinedUvMapResults += uvMapResults;
return combinedUvMapResults.GetResult();
}
@@ -62,7 +62,6 @@ namespace AZ
SceneNodeFinalizeContext finalizeNode(addedAttributes);
nodeResults += Events::Process(finalizeNode);
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
else
{
AssImpSceneDataPopulatedContext* dataPopulatedContext = azrtti_cast<AssImpSceneDataPopulatedContext*>(&dataPopulated);
@@ -75,7 +74,6 @@ namespace AZ
AssImpSceneNodeFinalizeContext finalizeNode(addedAttributes);
nodeResults += Events::Process(finalizeNode);
}
#endif
return nodeResults.GetResult();
}
@@ -99,14 +97,12 @@ namespace AZ
SceneAttributeNodeAppendedContext nodeAppended(*dataPopulatedContext, dataPopulated.m_currentGraphPosition);
nodeResults += Events::Process(nodeAppended);
}
#ifdef ASSET_IMPORTER_SDK_SUPPORTED_TRAIT
else
{
AssImpSceneAttributeDataPopulatedContext* dataPopulatedContext = azrtti_cast<AssImpSceneAttributeDataPopulatedContext*>(&dataPopulated);
AssImpSceneAttributeNodeAppendedContext nodeAppended(*dataPopulatedContext, dataPopulated.m_currentGraphPosition);
nodeResults += Events::Process(nodeAppended);
}
#endif
return nodeResults.GetResult();
}
@@ -16,7 +16,6 @@
#include <SceneAPI/SceneCore/DataTypes/MatrixType.h>
#include <SceneAPI/SceneCore/Events/CallProcessorBus.h>
namespace AZ
{
struct Uuid;
@@ -79,4 +79,4 @@ namespace AZ
}
} // namespace FbxSceneBuilder
} // namespace SceneAPI
} // namespace AZ
} // namespace AZ
@@ -0,0 +1,98 @@
/*
* 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 <assimp/mesh.h>
#include <assimp/scene.h>
#include <AzCore/Casting/numeric_cast.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <SceneAPI/FbxSceneBuilder/FbxSceneSystem.h>
#include <SceneAPI/FbxSceneBuilder/Importers/Utilities/AssImpMeshImporterUtilities.h>
#include <SceneAPI/SceneCore/Utilities/Reporting.h>
#include <SceneAPI/SceneData/GraphData/BlendShapeData.h>
#include <SceneAPI/SceneData/GraphData/MeshData.h>
namespace AZ::SceneAPI::FbxSceneBuilder
{
bool BuildSceneMeshFromAssImpMesh(aiNode* currentNode, const aiScene* scene, const FbxSceneSystem& sceneSystem, AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>>& meshes,
const AZStd::function<AZStd::shared_ptr<SceneData::GraphData::MeshData>()>& makeMeshFunc)
{
AZStd::unordered_map<int, int> assImpMatIndexToLYIndex;
int lyMeshIndex = 0;
if(!currentNode || !scene)
{
return false;
}
for (int m = 0; m < currentNode->mNumMeshes; ++m)
{
auto newMesh = makeMeshFunc();
newMesh->SetUnitSizeInMeters(sceneSystem.GetUnitSizeInMeters());
newMesh->SetOriginalUnitSizeInMeters(sceneSystem.GetOriginalUnitSizeInMeters());
newMesh->SetSdkMeshIndex(m);
aiMesh* mesh = scene->mMeshes[currentNode->mMeshes[m]];
// Lumberyard materials are created in order based on mesh references in the scene
if (assImpMatIndexToLYIndex.find(mesh->mMaterialIndex) == assImpMatIndexToLYIndex.end())
{
assImpMatIndexToLYIndex.insert(AZStd::pair<int, int>(mesh->mMaterialIndex, lyMeshIndex++));
}
for (int vertIdx = 0; vertIdx < mesh->mNumVertices; ++vertIdx)
{
AZ::Vector3 vertex(mesh->mVertices[vertIdx].x, mesh->mVertices[vertIdx].y, mesh->mVertices[vertIdx].z);
sceneSystem.SwapVec3ForUpAxis(vertex);
sceneSystem.ConvertUnit(vertex);
newMesh->AddPosition(vertex);
newMesh->SetVertexIndexToControlPointIndexMap(vertIdx, vertIdx);
if (mesh->HasNormals())
{
AZ::Vector3 normal(mesh->mNormals[vertIdx].x, mesh->mNormals[vertIdx].y, mesh->mNormals[vertIdx].z);
sceneSystem.SwapVec3ForUpAxis(normal);
normal.NormalizeSafe();
newMesh->AddNormal(normal);
}
}
for (int faceIdx = 0; faceIdx < mesh->mNumFaces; ++faceIdx)
{
aiFace face = mesh->mFaces[faceIdx];
AZ::SceneAPI::DataTypes::IMeshData::Face meshFace;
if (face.mNumIndices != 3)
{
// AssImp should have triangulated everything, so if this happens then someone has
// probably changed AssImp's import settings. The engine only supports triangles.
AZ_Error(Utilities::ErrorWindow, false,
"Mesh on node %s has a face with %d vertices, only 3 vertices are supported per face.",
currentNode->mName.C_Str(),
face.mNumIndices);
continue;
}
for (int idx = 0; idx < face.mNumIndices; ++idx)
{
meshFace.vertexIndex[idx] = face.mIndices[idx];
}
newMesh->AddFace(meshFace, assImpMatIndexToLYIndex[mesh->mMaterialIndex]);
}
meshes.push_back(newMesh);
}
return true;
}
}
@@ -0,0 +1,48 @@
/*
* 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.
*
*/
#pragma once
struct aiNode;
struct aiScene;
namespace AZ
{
namespace FbxSDKWrapper
{
class FbxMeshWrapper;
}
namespace SceneData
{
namespace GraphData
{
class MeshData;
class BlendShapeData;
}
}
namespace SceneAPI
{
namespace DataTypes
{
class IGraphObject;
}
class FbxSceneSystem;
namespace FbxSceneBuilder
{
bool BuildSceneMeshFromAssImpMesh(aiNode* currentNode, const aiScene* scene, const FbxSceneSystem& sceneSystem, AZStd::vector<AZStd::shared_ptr<DataTypes::IGraphObject>>& meshes,
const AZStd::function<AZStd::shared_ptr<SceneData::GraphData::MeshData>()>& makeMeshFunc);
}
}
}
@@ -10,16 +10,4 @@
#
set(FILES
../../ImportContexts/AssImpImportContexts.h
../../ImportContexts/AssImpImportContexts.cpp
../../Importers/AssImpColorStreamImporter.h
../../Importers/AssImpColorStreamImporter.cpp
../../Importers/AssImpMaterialImporter.h
../../Importers/AssImpMaterialImporter.cpp
../../Importers/AssImpMeshImporter.h
../../Importers/AssImpMeshImporter.cpp
../../Importers/AssImpUvMapImporter.h
../../Importers/AssImpUvMapImporter.cpp
../../Importers/AssImpTransformImporter.h
../../Importers/AssImpTransformImporter.cpp
)
@@ -21,6 +21,8 @@ set(FILES
ImportContexts/ImportContexts.cpp
ImportContexts/FbxImportContexts.h
ImportContexts/FbxImportContexts.cpp
ImportContexts/AssImpImportContexts.h
ImportContexts/AssImpImportContexts.cpp
Importers/FbxAnimationImporter.h
Importers/FbxAnimationImporter.cpp
Importers/FbxBoneImporter.h
@@ -50,6 +52,36 @@ set(FILES
Importers/FbxUvMapImporter.cpp
Importers/Utilities/FbxMeshImporterUtilities.h
Importers/Utilities/FbxMeshImporterUtilities.cpp
Importers/Utilities/AssImpMeshImporterUtilities.h
Importers/Utilities/AssImpMeshImporterUtilities.cpp
Importers/Utilities/RenamedNodesMap.h
Importers/Utilities/RenamedNodesMap.cpp
Importers/AssImpAnimationImporter.h
Importers/AssImpAnimationImporter.cpp
Importers/AssImpBitangentStreamImporter.h
Importers/AssImpBitangentStreamImporter.cpp
Importers/AssImpBlendShapeImporter.h
Importers/AssImpBlendShapeImporter.cpp
Importers/AssImpBoneImporter.h
Importers/AssImpBoneImporter.cpp
Importers/AssImpColorStreamImporter.h
Importers/AssImpColorStreamImporter.cpp
Importers/AssImpImporterUtilities.h
Importers/AssImpImporterUtilities.cpp
Importers/AssImpMaterialImporter.h
Importers/AssImpMaterialImporter.cpp
Importers/AssImpMeshImporter.h
Importers/AssImpMeshImporter.cpp
Importers/AssImpSkinImporter.h
Importers/AssImpSkinImporter.cpp
Importers/AssImpSkinWeightsImporter.h
Importers/AssImpSkinWeightsImporter.cpp
Importers/AssImpTangentStreamImporter.h
Importers/AssImpTangentStreamImporter.cpp
Importers/AssImpTransformImporter.h
Importers/AssImpTransformImporter.cpp
Importers/AssImpUvMapImporter.h
Importers/AssImpUvMapImporter.cpp
Importers/AssImpAnimationImporter.h
Importers/AssImpAnimationImporter.cpp
)

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