Integrating latest from github/staging
Integrating up through commit 5e1bdae
This commit is contained in:
@@ -79,9 +79,9 @@ ly_add_source_properties(
|
||||
)
|
||||
|
||||
ly_add_target(
|
||||
NAME ImageProcessing.Editor MODULE
|
||||
NAME ImageProcessing.Editor GEM_MODULE
|
||||
|
||||
NAMESPACE Gem
|
||||
OUTPUT_NAME Gem.ImageProcessing.Editor.eeffbd9211cf4ce0b5cc73696b427cbe.v0.1.0
|
||||
AUTOMOC
|
||||
AUTORCC
|
||||
FILES_CMAKE
|
||||
@@ -108,6 +108,7 @@ ly_add_target(
|
||||
Gem::TextureAtlas
|
||||
RUNTIME_DEPENDENCIES
|
||||
3rdParty::ASTCEncoder
|
||||
Gem::TextureAtlas
|
||||
)
|
||||
|
||||
if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <AzCore/Serialization/SerializeContext.h>
|
||||
#include <AzCore/std/sort.h>
|
||||
#include <AzCore/IO/FileIO.h>
|
||||
#include <AzCore/IO/Path/Path.h>
|
||||
#include <AzCore/std/string/regex.h>
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
#include <AzFramework/API/ApplicationAPI.h>
|
||||
@@ -67,61 +68,18 @@ namespace TextureAtlasBuilder
|
||||
return (pathLength > 0 && (path.at(pathLength - 1) == '/' || path.at(pathLength - 1) == '\\'));
|
||||
}
|
||||
|
||||
bool GetCanonicalPathFromFullPath(const AZStd::string& fullPath, AZStd::string& canonicalPathOut)
|
||||
{
|
||||
AZStd::string curPath = fullPath;
|
||||
|
||||
// We avoid using LocalFileIO::ConvertToAbsolutePath for this because it does not behave consistently across platforms.
|
||||
// On non-Windows platforms, LocalFileIO::ConvertToAbsolutePath requires that the path exist, otherwise the path
|
||||
// remains unchanged. This won't work for paths that include wildcards.
|
||||
// Also, on non-Windows platforms, if the path is already a full path, it will remain unchanged even if it contains
|
||||
// "./" or "../" somewhere other than the beginning of the path
|
||||
|
||||
// Normalize path
|
||||
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePathKeepCase, curPath);
|
||||
|
||||
const AZStd::string slash("/");
|
||||
|
||||
// Replace "/./" occurrances with "/"
|
||||
const AZStd::string slashDotSlash("/./");
|
||||
bool replaced = false;
|
||||
do
|
||||
{
|
||||
// Replace first occurrance
|
||||
replaced = AzFramework::StringFunc::Replace(curPath, slashDotSlash.c_str(), slash.c_str(), false, true, false);
|
||||
} while (replaced);
|
||||
|
||||
// Replace "/xxx/../" with "/"
|
||||
const AZStd::regex slashDotDotSlash("\\/[^/.]*\\/\\.\\.\\/");
|
||||
AZStd::string prevPath;
|
||||
while (prevPath != curPath)
|
||||
{
|
||||
prevPath = curPath;
|
||||
curPath = AZStd::regex_replace(prevPath, slashDotDotSlash, slash, AZStd::regex_constants::match_flag_type::format_first_only);
|
||||
}
|
||||
|
||||
if ((curPath.find("..") != AZStd::string::npos) || (curPath.find("./") != AZStd::string::npos) || (curPath.find("/.") != AZStd::string::npos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
canonicalPathOut = curPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ResolveRelativePath(const AZStd::string& relativePath, const AZStd::string& watchDirectory, AZStd::string& resolvedFullPathOut)
|
||||
{
|
||||
bool resolved = false;
|
||||
|
||||
// Get full path by appending the relative path to the watch directory
|
||||
AZStd::string fullPath = watchDirectory;
|
||||
fullPath.append("/");
|
||||
fullPath.append(relativePath);
|
||||
AZ::IO::FixedMaxPath resolvedPath;
|
||||
AZ::IO::FileIOBase::GetInstance()->ReplaceAlias(resolvedPath, AZ::IO::PathView{relativePath});
|
||||
|
||||
// Resolve to canonical path (remove "./" and "../")
|
||||
resolved = GetCanonicalPathFromFullPath(fullPath, resolvedFullPathOut);
|
||||
resolvedPath = (AZ::IO::FixedMaxPath{watchDirectory} / resolvedPath).LexicallyNormal();
|
||||
resolvedFullPathOut = resolvedPath.String();
|
||||
|
||||
return resolved;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetAbsoluteSourcePathFromRelativePath(const AZStd::string& relativeSourcePath, AZStd::string& absoluteSourcePathOut)
|
||||
@@ -434,33 +392,38 @@ namespace TextureAtlasBuilder
|
||||
|
||||
void AtlasBuilderInput::AddFilesUsingWildCard(AZStd::vector<AZStd::string>& paths, const AZStd::string& insert)
|
||||
{
|
||||
const AZStd::string& fullPath = insert;
|
||||
AZ::IO::PathView fullPathView(insert);
|
||||
|
||||
AZStd::vector<AZStd::string> candidates;
|
||||
AZStd::string fixedPath = fullPath.substr(0, fullPath.find('*'));
|
||||
fixedPath = fixedPath.substr(0, fixedPath.find_last_of('/'));
|
||||
candidates.push_back(fixedPath);
|
||||
|
||||
AZStd::vector<AZStd::string> wildPath;
|
||||
AzFramework::StringFunc::Tokenize(fullPath.substr(fixedPath.length()).c_str(), wildPath, "/");
|
||||
|
||||
for (size_t i = 0; i < wildPath.size() && candidates.size() > 0; ++i)
|
||||
// Find first path element with a wild card in it
|
||||
AZ::IO::Path staticPath;
|
||||
auto wildCardPathElementIter = fullPathView.begin();
|
||||
for (; wildCardPathElementIter != fullPathView.end(); ++wildCardPathElementIter)
|
||||
{
|
||||
AZStd::vector<AZStd::string> nextCandidates;
|
||||
for (size_t j = 0; j < candidates.size(); ++j)
|
||||
if (wildCardPathElementIter->Native().contains('*'))
|
||||
{
|
||||
AZStd::string compare = AZStd::string::format("%s/%s", candidates[j].c_str(), wildPath[i].c_str());
|
||||
QDir inputFolder(candidates[j].c_str());
|
||||
if (inputFolder.exists())
|
||||
break;
|
||||
}
|
||||
staticPath /= *wildCardPathElementIter;
|
||||
}
|
||||
|
||||
// The remaining path segments are part of the wild card path
|
||||
|
||||
AZStd::vector<AZ::IO::Path> candidates{ AZStd::move(staticPath) };
|
||||
for(; wildCardPathElementIter != fullPathView.end() && !candidates.empty(); ++wildCardPathElementIter)
|
||||
{
|
||||
AZStd::vector<AZ::IO::Path> nextCandidates;
|
||||
for (const AZ::IO::Path& candidate : candidates)
|
||||
{
|
||||
if (QDir inputFolder(QString::fromUtf8(candidate.c_str(), aznumeric_cast<int>(candidate.Native().size())));
|
||||
inputFolder.exists())
|
||||
{
|
||||
QFileInfoList entries = inputFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files);
|
||||
for (const QFileInfo& entry : entries)
|
||||
{
|
||||
AZStd::string child = (entry.filePath().toStdString()).c_str();
|
||||
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePathKeepCase, child);
|
||||
if (DoesPathnameMatchWildCard(compare, child))
|
||||
AZ::IO::Path filenameEntry(entry.fileName().toUtf8().data());
|
||||
if (filenameEntry.Match(wildCardPathElementIter->Native()))
|
||||
{
|
||||
nextCandidates.push_back(child);
|
||||
nextCandidates.push_back(entry.filePath().toUtf8().data());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -468,138 +431,70 @@ namespace TextureAtlasBuilder
|
||||
candidates = nextCandidates;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < candidates.size(); ++i)
|
||||
for (const AZ::IO::Path& candidate : candidates)
|
||||
{
|
||||
if (!IsFolderPath(candidates[i]) && !HasTrailingSlash(fullPath))
|
||||
QFileInfo fileInfo(QString::fromUtf8(candidate.c_str(), aznumeric_cast<int>(candidate.Native().size())));
|
||||
if (fileInfo.isFile())
|
||||
{
|
||||
AZStd::string ext;
|
||||
AzFramework::StringFunc::Path::GetExtension(candidates[i].c_str(), ext, false);
|
||||
AZStd::string ext = fileInfo.suffix().toUtf8().data();
|
||||
if (ImageProcessing::IsExtensionSupported(ext.c_str()) && ext != "dds")
|
||||
{
|
||||
bool duplicate = false;
|
||||
for (size_t j = 0; j < paths.size() && !duplicate; ++j)
|
||||
auto FindExistingPath = [&candidate](const AZStd::string& path)
|
||||
{
|
||||
duplicate = paths[j] == candidates[i];
|
||||
}
|
||||
if (!duplicate)
|
||||
return candidate == AZ::IO::PathView(path);
|
||||
};
|
||||
if (auto foundIt = AZStd::find_if(paths.begin(), paths.end(), FindExistingPath);
|
||||
foundIt == paths.end())
|
||||
{
|
||||
paths.push_back(candidates[i]);
|
||||
AZStd::string normalizedPath = AZ::IO::Path(candidate.Native(), AZ::IO::PosixPathSeparator).LexicallyNormal().Native();
|
||||
paths.push_back(AZStd::move(normalizedPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsFolderPath(candidates[i]) && HasTrailingSlash(fullPath))
|
||||
else if (fileInfo.isDir())
|
||||
{
|
||||
bool waste = true;
|
||||
AddFolderContents(paths, candidates[i], waste);
|
||||
AddFolderContents(paths, candidate.Native(), waste);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AtlasBuilderInput::RemoveFilesUsingWildCard(AZStd::vector<AZStd::string>& paths, const AZStd::string& remove)
|
||||
{
|
||||
bool isDir = (remove.at(remove.length() - 1) == '/');
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
auto RemoveWildCardPath = [&remove](const AZStd::string& subPath)
|
||||
{
|
||||
if (isDir ? DoesWildCardDirectoryIncludePathname(remove, paths[i]) : DoesPathnameMatchWildCard(remove, paths[i]))
|
||||
{
|
||||
paths.erase(paths.begin() + i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tells us if the child follows the rule
|
||||
bool AtlasBuilderInput::DoesPathnameMatchWildCard(const AZStd::string& rule, const AZStd::string& child)
|
||||
{
|
||||
AZStd::vector<AZStd::string> rulePathTokens;
|
||||
AzFramework::StringFunc::Tokenize(rule.c_str(), rulePathTokens, "/");
|
||||
AZStd::vector<AZStd::string> pathTokens;
|
||||
AzFramework::StringFunc::Tokenize(child.c_str(), pathTokens, "/");
|
||||
if (rulePathTokens.size() != pathTokens.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < rulePathTokens.size(); ++i)
|
||||
{
|
||||
if (!TokenMatchesWildcard(rulePathTokens[i], pathTokens[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AtlasBuilderInput::DoesWildCardDirectoryIncludePathname(const AZStd::string& rule, const AZStd::string& child)
|
||||
{
|
||||
AZStd::vector<AZStd::string> rulePathTokens;
|
||||
AzFramework::StringFunc::Tokenize(rule.c_str(), rulePathTokens, "/");
|
||||
AZStd::vector<AZStd::string> pathTokens;
|
||||
AzFramework::StringFunc::Tokenize(child.c_str(), pathTokens, "/");
|
||||
if (rulePathTokens.size() >= pathTokens.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < rulePathTokens.size(); ++i)
|
||||
{
|
||||
if (!TokenMatchesWildcard(rulePathTokens[i], pathTokens[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AtlasBuilderInput::TokenMatchesWildcard(const AZStd::string& rule, const AZStd::string& child)
|
||||
{
|
||||
AZStd::vector<AZStd::string> ruleTokens;
|
||||
AzFramework::StringFunc::Tokenize(rule.c_str(), ruleTokens, "*");
|
||||
size_t pos = 0;
|
||||
int token = 0;
|
||||
if (rule.at(0) != '*' && child.find(ruleTokens[0]) != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (pos != AZStd::string::npos && token < ruleTokens.size())
|
||||
{
|
||||
pos = child.find(ruleTokens[token], pos);
|
||||
if (pos != AZStd::string::npos)
|
||||
{
|
||||
pos += ruleTokens[token].size();
|
||||
}
|
||||
++token;
|
||||
}
|
||||
return pos == child.size() || (pos != AZStd::string::npos && rule.at(rule.length() - 1) == '*');
|
||||
return AZ::IO::PathView(subPath).Match(remove);
|
||||
};
|
||||
AZStd::erase_if(paths, RemoveWildCardPath);
|
||||
}
|
||||
|
||||
// Replaces all folder paths with the files they contain
|
||||
void AtlasBuilderInput::AddFolderContents(AZStd::vector<AZStd::string>& paths, const AZStd::string& insert, bool& valid)
|
||||
{
|
||||
QDir inputFolder(insert.c_str());
|
||||
|
||||
if (inputFolder.exists())
|
||||
if (QDir inputFolder(insert.c_str()); inputFolder.exists())
|
||||
{
|
||||
QFileInfoList entries = inputFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Files);
|
||||
for (const QFileInfo& entry : entries)
|
||||
{
|
||||
AZStd::string child = (entry.filePath().toStdString()).c_str();
|
||||
AZStd::string ext;
|
||||
bool isDir = !AzFramework::StringFunc::Path::GetExtension(child.c_str(), ext, false);
|
||||
AZ::IO::Path child = entry.filePath().toUtf8().data();
|
||||
AZStd::string ext = entry.suffix().toUtf8().data();
|
||||
const bool isDir = entry.isDir();
|
||||
if (isDir)
|
||||
{
|
||||
AddFolderContents(paths, child, valid);
|
||||
AddFolderContents(paths, child.Native(), valid);
|
||||
}
|
||||
else if (ImageProcessing::IsExtensionSupported(ext.c_str()) && ext != "dds")
|
||||
{
|
||||
AzFramework::ApplicationRequests::Bus::Broadcast(&AzFramework::ApplicationRequests::NormalizePathKeepCase, child);
|
||||
bool duplicate = false;
|
||||
for (size_t i = 0; i < paths.size() && !duplicate; ++i)
|
||||
auto FindExistingPath = [&child](const AZStd::string& path)
|
||||
{
|
||||
duplicate = paths[i] == child;
|
||||
}
|
||||
if (!duplicate)
|
||||
return child == AZ::IO::PathView(path);
|
||||
};
|
||||
if (auto foundIter = AZStd::find_if(paths.begin(), paths.end(), FindExistingPath);
|
||||
foundIter == paths.end())
|
||||
{
|
||||
paths.push_back(child);
|
||||
// Normalize the path to have posix slashes
|
||||
AZStd::string normalizedPath = AZ::IO::Path(child.Native(), AZ::IO::PosixPathSeparator).LexicallyNormal().Native();
|
||||
paths.push_back(AZStd::move(normalizedPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -614,17 +509,11 @@ namespace TextureAtlasBuilder
|
||||
// Removes all of the contents of a folder
|
||||
void AtlasBuilderInput::RemoveFolderContents(AZStd::vector<AZStd::string>& paths, const AZStd::string& remove)
|
||||
{
|
||||
AZStd::string folder = remove;
|
||||
AzFramework::StringFunc::Strip(folder, "/", false, false, true);
|
||||
folder.append("/");
|
||||
for (size_t i = 0; i < paths.size(); ++i)
|
||||
auto RemoveSubPath = [folder = AZ::IO::PathView(remove)](const AZStd::string& subPath)
|
||||
{
|
||||
if (paths[i].find(folder) == 0)
|
||||
{
|
||||
paths.erase(paths.begin() + i);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
return AZ::IO::PathView(subPath).IsRelativeTo(folder);
|
||||
};
|
||||
AZStd::erase_if(paths, RemoveSubPath);
|
||||
}
|
||||
|
||||
// Note - Shutdown will be called on a different thread than your process job thread
|
||||
|
||||
@@ -62,15 +62,6 @@ namespace TextureAtlasBuilder
|
||||
//! Removes anything that matches the wildcard
|
||||
static void RemoveFilesUsingWildCard(AZStd::vector<AZStd::string>& paths, const AZStd::string& remove);
|
||||
|
||||
//! Compare considering wildcards
|
||||
static bool DoesPathnameMatchWildCard(const AZStd::string& rule, const AZStd::string& path);
|
||||
|
||||
//! As FollowsRule but allows extra items after the last '/'
|
||||
static bool DoesWildCardDirectoryIncludePathname(const AZStd::string& rule, const AZStd::string& path);
|
||||
|
||||
//! Helper function for DoesPathnameMatchWildCard
|
||||
static bool TokenMatchesWildcard(const AZStd::string& rule, const AZStd::string& token);
|
||||
|
||||
//! Resolves any folder paths into image file paths
|
||||
static void AddFolderContents(AZStd::vector<AZStd::string>& paths, const AZStd::string& insert, bool& valid);
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include <AzFramework/StringFunc/StringFunc.h>
|
||||
|
||||
#include <ImageLoader/ImageLoaders.h>
|
||||
#include <Processing/ImageConvert.h>
|
||||
#include <Processing/ImageToProcess.h>
|
||||
|
||||
namespace ImageProcessing
|
||||
{
|
||||
@@ -71,11 +73,13 @@ namespace ImageProcessing
|
||||
builderDescriptor.m_createJobFunction = AZStd::bind(&ImageBuilderWorker::CreateJobs, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
|
||||
builderDescriptor.m_processJobFunction = AZStd::bind(&ImageBuilderWorker::ProcessJob, &m_imageBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
|
||||
m_imageBuilder.BusConnect(builderDescriptor.m_busId);
|
||||
ImageProcessingRequestBus::Handler::BusConnect();
|
||||
AssetBuilderSDK::AssetBuilderBus::Broadcast(&AssetBuilderSDK::AssetBuilderBusTraits::RegisterBuilderInformation, builderDescriptor);
|
||||
}
|
||||
|
||||
void BuilderPluginComponent::Deactivate()
|
||||
{
|
||||
ImageProcessingRequestBus::Handler::BusDisconnect();
|
||||
m_imageBuilder.BusDisconnect();
|
||||
BuilderSettingManager::DestroyInstance();
|
||||
CPixelFormats::DestroyInstance();
|
||||
@@ -111,6 +115,23 @@ namespace ImageProcessing
|
||||
incompatible.push_back(AZ_CRC("ImagerBuilderPluginService", 0x6dc0db6e));
|
||||
}
|
||||
|
||||
IImageObjectPtr BuilderPluginComponent::LoadImage(const AZStd::string& filePath)
|
||||
{
|
||||
return IImageObjectPtr(LoadImageFromFile(filePath));
|
||||
}
|
||||
|
||||
IImageObjectPtr BuilderPluginComponent::LoadImagePreview(const AZStd::string& filePath)
|
||||
{
|
||||
IImageObjectPtr image(LoadImageFromFile(filePath));
|
||||
if (image)
|
||||
{
|
||||
ImageToProcess imageToProcess(image);
|
||||
imageToProcess.ConvertFormat(ePixelFormat_R8G8B8A8);
|
||||
return imageToProcess.Get();
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
void ImageBuilderWorker::ShutDown()
|
||||
{
|
||||
// it is important to note that this will be called on a different thread than your process job thread
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <AssetBuilderSDK/AssetBuilderBusses.h>
|
||||
#include <AssetBuilderSDK/AssetBuilderSDK.h>
|
||||
#include <AzCore/Outcome/Outcome.h>
|
||||
#include <ImageProcessing/ImageProcessingBus.h>
|
||||
|
||||
namespace ImageProcessing
|
||||
{
|
||||
@@ -48,6 +49,7 @@ namespace ImageProcessing
|
||||
//! BuilderPluginComponent is to handle the lifecycle of ImageBuilder module.
|
||||
class BuilderPluginComponent
|
||||
: public AZ::Component
|
||||
, protected ImageProcessingRequestBus::Handler
|
||||
{
|
||||
public:
|
||||
AZ_COMPONENT(BuilderPluginComponent, "{2F12E1BE-D8F6-47A4-AC3E-6C5527C55840}")
|
||||
@@ -66,6 +68,12 @@ namespace ImageProcessing
|
||||
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// ImageProcessingRequestBus interface implementation
|
||||
IImageObjectPtr LoadImage(const AZStd::string& filePath) override;
|
||||
IImageObjectPtr LoadImagePreview(const AZStd::string& filePath) override;
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private:
|
||||
ImageBuilderWorker m_imageBuilder;
|
||||
};
|
||||
|
||||
@@ -127,8 +127,9 @@ protected:
|
||||
AZ::Entity* FindEntity(const AZ::EntityId&) override { return nullptr; }
|
||||
AZ::BehaviorContext* GetBehaviorContext() override { return nullptr; }
|
||||
AZ::JsonRegistrationContext* GetJsonRegistrationContext() override { return nullptr; }
|
||||
const char* GetExecutableFolder() const override { return nullptr; }
|
||||
const char* GetAppRoot() const override { return nullptr; }
|
||||
const char* GetEngineRoot() const override { return nullptr; }
|
||||
const char* GetExecutableFolder() const override { return nullptr; }
|
||||
AZ::Debug::DrillerManager* GetDrillerManager() override { return nullptr; }
|
||||
void EnumerateEntities(const EntityCallback& /*callback*/) override {}
|
||||
void QueryApplicationType(AZ::ApplicationTypeQuery& /*appType*/) const override {}
|
||||
|
||||
Reference in New Issue
Block a user