AtlasBuilderWorker.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #pragma once
  9. #include <AzCore/RTTI/RTTI.h>
  10. #include <AzCore/Math/Color.h>
  11. #include <AssetBuilderSDK/AssetBuilderSDK.h>
  12. #include <AssetBuilderSDK/AssetBuilderBusses.h>
  13. #include <qimage.h>
  14. #include <TextureAtlas/TextureAtlasBus.h>
  15. namespace TextureAtlasBuilder
  16. {
  17. //! Struct that is used to communicate input commands
  18. struct AtlasBuilderInput
  19. {
  20. AZ_CLASS_ALLOCATOR(AtlasBuilderInput, AZ::SystemAllocator);
  21. AZ_TYPE_INFO(AtlasBuilderInput, "{F54477F9-1BDE-4274-8CC0-8320A3EF4A42}");
  22. bool m_forceSquare;
  23. bool m_forcePowerOf2;
  24. // Includes a white default texture for the UI to use under certain circumstances
  25. bool m_includeWhiteTexture;
  26. int m_maxDimension;
  27. // At least this much padding will surround each texture except on the edges of the atlas
  28. int m_padding;
  29. // Color used in wasted space
  30. AZ::Color m_unusedColor;
  31. // A preset to use for the texture atlas image processing
  32. AZStd::string m_presetName;
  33. AZStd::vector<AZStd::string> m_filePaths;
  34. AtlasBuilderInput():
  35. m_forceSquare(false),
  36. m_forcePowerOf2(false),
  37. m_includeWhiteTexture(true),
  38. m_maxDimension(4096),
  39. m_padding(1),
  40. // Default color should be a non-transparent color that isn't used often in uis
  41. m_unusedColor(.235f, .702f, .443f, 1)
  42. {
  43. }
  44. static void Reflect(AZ::ReflectContext* context);
  45. //! Attempts to read the input from a .texatlas file. "valid" is for reporting exceptions and telling the asset
  46. //! proccesor to fail the job. Supports parsing through a human readable custom parser.
  47. static AtlasBuilderInput ReadFromFile(const AZStd::string& path, const AZStd::string& directory, bool& valid);
  48. //! Resolves any wild cards in paths
  49. static void AddFilesUsingWildCard(AZStd::vector<AZStd::string>& paths, const AZStd::string& insert);
  50. //! Removes anything that matches the wildcard
  51. static void RemoveFilesUsingWildCard(AZStd::vector<AZStd::string>& paths, const AZStd::string& remove);
  52. //! Compare considering wildcards
  53. static bool DoesPathnameMatchWildCard(const AZStd::string& rule, const AZStd::string& path);
  54. //! As FollowsRule but allows extra items after the last '/'
  55. static bool DoesWildCardDirectoryIncludePathname(const AZStd::string& rule, const AZStd::string& path);
  56. //! Helper function for DoesPathnameMatchWildCard
  57. static bool TokenMatchesWildcard(const AZStd::string& rule, const AZStd::string& token);
  58. //! Resolves any folder paths into image file paths
  59. static void AddFolderContents(AZStd::vector<AZStd::string>& paths, const AZStd::string& insert, bool& valid);
  60. //! Resolves remove commands for folders
  61. static void RemoveFolderContents(AZStd::vector<AZStd::string>& paths, const AZStd::string& remove);
  62. };
  63. //! Struct that is used to represent an object with a width and height in pixels
  64. struct ImageDimension
  65. {
  66. int m_width;
  67. int m_height;
  68. ImageDimension(int width, int height)
  69. {
  70. m_width = width;
  71. m_height = height;
  72. }
  73. };
  74. //! Typedef for an ImageDimension paired with an integer
  75. using IndexImageDimension = AZStd::pair<int, ImageDimension>;
  76. //! Typedef for a list of ImageDimensions paired with integers
  77. using ImageDimensionData = AZStd::vector<IndexImageDimension>;
  78. //! Typedef to simplify references to TextureAtlas::AtlasCoordinates
  79. using AtlasCoordinates = TextureAtlasNamespace::AtlasCoordinates;
  80. //! Number of bytes in a pixel
  81. const int bytesPerPixel = 4;
  82. //! The size of the padded sorting units (important for compression)
  83. const int cellSize = 4;
  84. //! Indexes of the products
  85. enum class Product
  86. {
  87. TexatlasidxProduct = 0,
  88. StreamingImageProduct = 1
  89. };
  90. //! An asset builder for texture atlases
  91. class AtlasBuilderWorker : public AssetBuilderSDK::AssetBuilderCommandBus::Handler
  92. {
  93. public:
  94. AZ_RTTI(AtlasBuilderWorker, "{79036188-E017-4575-9EC0-8D39CB560EA6}");
  95. AtlasBuilderWorker() = default;
  96. ~AtlasBuilderWorker() = default;
  97. //! Asset Builder Callback Functions
  98. //! Called by asset processor to gather information on a job for a ".texatlas" file
  99. void CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request,
  100. AssetBuilderSDK::CreateJobsResponse& response);
  101. //! Called by asset proccessor when it wants us to execute a job
  102. void ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request,
  103. AssetBuilderSDK::ProcessJobResponse& response);
  104. //! Returns the job related information used by the builder
  105. static AssetBuilderSDK::JobDescriptor GetJobDescriptor(const AZStd::string& sourceFile, const AtlasBuilderInput& input);
  106. //////////////////////////////////////////////////////////////////////////
  107. //! AssetBuilderSDK::AssetBuilderCommandBus interface
  108. void ShutDown() override; // if you get this you must fail all existing jobs and return.
  109. //////////////////////////////////////////////////////////////////////////
  110. private:
  111. bool m_isShuttingDown = false;
  112. //! This is the main function that takes a set of inputs and attempts to pack them into an atlas of a given
  113. //! size. Returns true if succesful, does not update out on failure.
  114. static bool TryPack(const ImageDimensionData& images,
  115. int targetWidth,
  116. int targetHeight,
  117. int padding,
  118. size_t& amountFit,
  119. AZStd::vector<AtlasCoordinates>& out);
  120. //! Removes any overlap between slotList and the given item
  121. static void TrimOverlap(AZStd::vector<AtlasCoordinates>& slotList, AtlasCoordinates item);
  122. //! Uses the proper tightening method based on the input and returns the maximum number of items that were able to be fit
  123. bool TryTightening(AtlasBuilderInput input,
  124. const ImageDimensionData& images,
  125. int smallestWidth,
  126. int smallestHeight,
  127. int targetArea,
  128. int padding,
  129. int& resultWidth,
  130. int& resultHeight,
  131. size_t& amountFit,
  132. AZStd::vector<AtlasCoordinates>& out);
  133. //! Finds the tightest square fit achievable by expanding a square area until a valid fit is found
  134. bool TryTighteningSquare(const ImageDimensionData& images,
  135. int lowerBound,
  136. int maxDimension,
  137. int targetArea,
  138. bool powerOfTwo,
  139. int padding,
  140. int& resultWidth,
  141. int& resultHeight,
  142. size_t& amountFit,
  143. AZStd::vector<AtlasCoordinates>& out);
  144. //! Finds the tightest fit achievable by starting with the optimal thin solution and attempting to resize to be
  145. //! a better shape
  146. bool TryTighteningOptimal(const ImageDimensionData& images,
  147. int smallestWidth,
  148. int smallestHeight,
  149. int maxDimension,
  150. int targetArea,
  151. bool powerOfTwo,
  152. int padding,
  153. int& resultWidth,
  154. int& resultHeight,
  155. size_t& amountFit,
  156. AZStd::vector<AtlasCoordinates>& out);
  157. //! Sorting logic for adding a slot to a sorted list in order to maintain increasing order
  158. static void InsertInOrder(AZStd::vector<AtlasCoordinates>& slotList, AtlasCoordinates item);
  159. //! Misc Logic For Estimating Target Shape
  160. //! Returns the width of the widest element
  161. static int GetWidest(const ImageDimensionData& imageList);
  162. //! Returns the height of the tallest area
  163. static int GetTallest(const ImageDimensionData& imageList);
  164. };
  165. }