diff --git a/Source/Engine/CSG/CSGData.cpp b/Source/Engine/CSG/CSGData.cpp index 219ea4b73..a5da3fce1 100644 --- a/Source/Engine/CSG/CSGData.cpp +++ b/Source/Engine/CSG/CSGData.cpp @@ -17,8 +17,8 @@ namespace CSG struct Node : RectPackNode { - Node(float x, float y, float width, float height) - : RectPackNode(x, y, width, height) + Node(Size x, Size y, Size width, Size height) + : RectPackNode(x, y, width, height) { } @@ -50,7 +50,7 @@ namespace CSG Node* Insert(ChartType chart) { - return _root.Insert(chart->Size.X, chart->Size.Y, _chartsPadding, chart, _atlasSize); + return _root.Insert(chart->Size.X, chart->Size.Y, chart, _atlasSize); } }; } diff --git a/Source/Engine/ContentImporters/ImportModel.cpp b/Source/Engine/ContentImporters/ImportModel.cpp index 568abfbeb..d057bae0c 100644 --- a/Source/Engine/ContentImporters/ImportModel.cpp +++ b/Source/Engine/ContentImporters/ImportModel.cpp @@ -72,8 +72,8 @@ void RepackMeshLightmapUVs(ModelData& data) // Build list of meshes with their area struct LightmapUVsPack : RectPackNode { - LightmapUVsPack(float x, float y, float width, float height) - : RectPackNode(x, y, width, height) + LightmapUVsPack(Size x, Size y, Size width, Size height) + : RectPackNode(x, y, width, height) { } @@ -110,10 +110,10 @@ void RepackMeshLightmapUVs(ModelData& data) bool failed = false; const float chartsPadding = (4.0f / 256.0f) * atlasSize; RectPackAtlas atlas; - atlas.Init(chartsPadding, chartsPadding); + atlas.Init(atlasSize, atlasSize, chartsPadding); for (auto& entry : entries) { - entry.Slot = atlas.Insert(entry.Size, entry.Size, chartsPadding); + entry.Slot = atlas.Insert(entry.Size, entry.Size); if (entry.Slot == nullptr) { // Failed to insert surface, increase atlas size and try again diff --git a/Source/Engine/Render2D/FontTextureAtlas.cpp b/Source/Engine/Render2D/FontTextureAtlas.cpp index b1c8e6c3f..01112305c 100644 --- a/Source/Engine/Render2D/FontTextureAtlas.cpp +++ b/Source/Engine/Render2D/FontTextureAtlas.cpp @@ -36,7 +36,8 @@ void FontTextureAtlas::Init(uint32 width, uint32 height) // Setup _width = width; _height = height; - _atlas.Init(_width, _height, GetPaddingAmount()); + const uint32 padding = GetPaddingAmount() * 2; // Double the padding so each slot has own border around it + _atlas.Init(_width, _height, padding); _isDirty = false; // Reserve upload data memory @@ -44,9 +45,9 @@ void FontTextureAtlas::Init(uint32 width, uint32 height) Platform::MemoryClear(_data.Get(), _data.Capacity()); } -FontTextureAtlasSlot* FontTextureAtlas::AddEntry(uint32 targetWidth, uint32 targetHeight, const Array& data) +FontTextureAtlasSlot* FontTextureAtlas::AddEntry(uint32 width, uint32 height, const Array& data) { - if (targetWidth == 0 || targetHeight == 0) + if (width == 0 || height == 0) return nullptr; // Try to find slot for the texture @@ -54,7 +55,7 @@ FontTextureAtlasSlot* FontTextureAtlas::AddEntry(uint32 targetWidth, uint32 targ for (int32 i = 0; i < _freeSlots.Count(); i++) { FontTextureAtlasSlot* e = _freeSlots[i]; - if (e->Width == targetWidth && e->Height == targetHeight) + if (e->Width == width && e->Height == height) { slot = e; _freeSlots.RemoveAt(i); @@ -63,7 +64,7 @@ FontTextureAtlasSlot* FontTextureAtlas::AddEntry(uint32 targetWidth, uint32 targ } if (!slot) { - slot = _atlas.Insert(targetWidth, targetHeight, GetPaddingAmount()); + slot = _atlas.Insert(width, height); } if (slot) @@ -100,11 +101,10 @@ bool FontTextureAtlas::Invalidate(uint32 x, uint32 y, uint32 width, uint32 heigh void FontTextureAtlas::CopyDataIntoSlot(const FontTextureAtlasSlot* slot, const Array& data) { RowData rowData; - rowData.DstData = &_data[slot->Y * _width * _bytesPerPixel + slot->X * _bytesPerPixel]; + rowData.DstData = _data.Get() + (slot->Y * _width + slot->X) * _bytesPerPixel; rowData.SrcData = data.Get(); - rowData.DstTextureWidth = _width; - rowData.SrcTextureWidth = slot->Width; - rowData.RowWidth = slot->Width; + rowData.DstWidth = _width; + rowData.SrcWidth = slot->Width; rowData.Padding = GetPaddingAmount(); // Start with padding @@ -148,20 +148,20 @@ byte* FontTextureAtlas::GetSlotData(const FontTextureAtlasSlot* slot, uint32& wi void FontTextureAtlas::copyRow(const RowData& copyRowData) const { - const byte* srcData = (const byte*)((intptr)copyRowData.SrcData + (intptr)copyRowData.SrcRow * copyRowData.SrcTextureWidth * _bytesPerPixel); - byte* dstData = (byte*)((intptr)copyRowData.DstData + (intptr)copyRowData.DstRow * copyRowData.DstTextureWidth * _bytesPerPixel); - Platform::MemoryCopy(dstData, srcData, copyRowData.SrcTextureWidth * _bytesPerPixel); + const byte* srcData = (const byte*)((intptr)copyRowData.SrcData + (intptr)copyRowData.SrcRow * copyRowData.SrcWidth * _bytesPerPixel); + byte* dstData = (byte*)((intptr)copyRowData.DstData + (intptr)copyRowData.DstRow * copyRowData.DstWidth * _bytesPerPixel); + Platform::MemoryCopy(dstData, srcData, copyRowData.SrcWidth * _bytesPerPixel); if (copyRowData.Padding > 0) { const uint32 padSize = copyRowData.Padding * _bytesPerPixel; - byte* dstPaddingPixelLeft = (byte*)((intptr)copyRowData.DstData + (intptr)copyRowData.DstRow * copyRowData.DstTextureWidth * _bytesPerPixel - padSize); - byte* dstPaddingPixelRight = dstPaddingPixelLeft + copyRowData.RowWidth * _bytesPerPixel + padSize; + byte* dstPaddingPixelLeft = (byte*)((intptr)copyRowData.DstData + (intptr)copyRowData.DstRow * copyRowData.DstWidth * _bytesPerPixel - padSize); + byte* dstPaddingPixelRight = dstPaddingPixelLeft + copyRowData.SrcWidth * _bytesPerPixel + padSize; if (_paddingStyle == DilateBorder) { // Dilate left and right sides of the padded row const byte* firstPixel = srcData; - const byte* lastPixel = srcData + (copyRowData.SrcTextureWidth - 1) * _bytesPerPixel; + const byte* lastPixel = srcData + (copyRowData.SrcWidth - 1) * _bytesPerPixel; Platform::MemoryCopy(dstPaddingPixelLeft, firstPixel, padSize); Platform::MemoryCopy(dstPaddingPixelRight, lastPixel, padSize); } @@ -176,8 +176,8 @@ void FontTextureAtlas::copyRow(const RowData& copyRowData) const void FontTextureAtlas::zeroRow(const RowData& copyRowData) const { - byte* dstData = (byte*)((intptr)copyRowData.DstData + (intptr)copyRowData.DstRow * copyRowData.DstTextureWidth * _bytesPerPixel); - uint32 dstSize = copyRowData.RowWidth * _bytesPerPixel; + byte* dstData = (byte*)((intptr)copyRowData.DstData + (intptr)copyRowData.DstRow * copyRowData.DstWidth * _bytesPerPixel); + uint32 dstSize = copyRowData.SrcWidth * _bytesPerPixel; if (copyRowData.Padding > 0) { // Extend clear by left and right borders of the padded row diff --git a/Source/Engine/Render2D/FontTextureAtlas.h b/Source/Engine/Render2D/FontTextureAtlas.h index b63c7b705..adb46652a 100644 --- a/Source/Engine/Render2D/FontTextureAtlas.h +++ b/Source/Engine/Render2D/FontTextureAtlas.h @@ -13,8 +13,8 @@ /// struct FontTextureAtlasSlot : RectPackNode<> { - FontTextureAtlasSlot(uint32 x, uint32 y, uint32 width, uint32 height) - : RectPackNode<>(x, y, width, height) + FontTextureAtlasSlot(Size x, Size y, Size width, Size height) + : RectPackNode(x, y, width, height) { } @@ -37,9 +37,8 @@ private: uint8* DstData; int32 SrcRow; int32 DstRow; - int32 RowWidth; - int32 SrcTextureWidth; - int32 DstTextureWidth; + int32 SrcWidth; + int32 DstWidth; uint32 Padding; }; @@ -154,11 +153,11 @@ public: /// /// Adds the new entry to the atlas /// - /// Width of the entry. - /// Height of the entry. + /// Width of the entry. + /// Height of the entry. /// The data. /// The atlas slot occupied by the new entry. - FontTextureAtlasSlot* AddEntry(uint32 targetWidth, uint32 targetHeight, const Array& data); + FontTextureAtlasSlot* AddEntry(uint32 width, uint32 height, const Array& data); /// /// Invalidates the cached dynamic entry from the atlas. diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index 20288cfe0..6dbe014f9 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -73,8 +73,8 @@ struct GlobalSurfaceAtlasTile : RectPackNode uint32 Address; uint32 ObjectAddressOffset; - GlobalSurfaceAtlasTile(uint16 x, uint16 y, uint16 width, uint16 height) - : RectPackNode(x, y, width, height) + GlobalSurfaceAtlasTile(Size x, Size y, Size width, Size height) + : RectPackNode(x, y, width, height) { } @@ -1236,7 +1236,7 @@ void GlobalSurfaceAtlasPass::RasterizeActor(Actor* actor, void* actorObject, con uint16 tilePixels = tileResolution * tileResolution; GlobalSurfaceAtlasTile* tile = nullptr; if (tilePixels <= surfaceAtlasData.AtlasPixelsTotal - surfaceAtlasData.AtlasPixelsUsed) - tile = surfaceAtlasData.Atlas.Insert(tileResolution, tileResolution, 0, &surfaceAtlasData, actorObject, tileIndex); + tile = surfaceAtlasData.Atlas.Insert(tileResolution, tileResolution, &surfaceAtlasData, actorObject, tileIndex); if (tile) { if (!object) diff --git a/Source/Engine/Renderer/ShadowsPass.cpp b/Source/Engine/Renderer/ShadowsPass.cpp index dbd9c7fdd..15ac7a097 100644 --- a/Source/Engine/Renderer/ShadowsPass.cpp +++ b/Source/Engine/Renderer/ShadowsPass.cpp @@ -43,8 +43,8 @@ struct ShadowsAtlasRectTile : RectPackNode { bool IsStatic; - ShadowsAtlasRectTile(uint16 x, uint16 y, uint16 width, uint16 height) - : RectPackNode(x, y, width, height) + ShadowsAtlasRectTile(Size x, Size y, Size width, Size height) + : RectPackNode(x, y, width, height) { } @@ -682,7 +682,7 @@ bool ShadowsPass::SetupLight(ShadowsCustomBuffer& shadows, RenderContext& render auto& tile = atlasLight.Tiles[tileIndex]; if (tile.StaticRectTile == nullptr) { - tile.StaticRectTile = shadows.StaticAtlas.Insert(atlasLight.StaticResolution, atlasLight.StaticResolution, 0, &shadows, true); + tile.StaticRectTile = shadows.StaticAtlas.Insert(atlasLight.StaticResolution, atlasLight.StaticResolution, &shadows, true); if (!tile.StaticRectTile) { // Failed to insert tile to switch back to the default rendering @@ -1225,7 +1225,7 @@ RETRY_ATLAS_SETUP: bool failedToInsert = false; for (int32 tileIndex = 0; tileIndex < atlasLight.TilesNeeded; tileIndex++) { - auto rectTile = shadows.Atlas.Insert(atlasLight.Resolution, atlasLight.Resolution, 0, &shadows, false); + auto rectTile = shadows.Atlas.Insert(atlasLight.Resolution, atlasLight.Resolution, &shadows, false); if (!rectTile) { // Free any previous tiles that were added diff --git a/Source/Engine/ShadowsOfMordor/AtlasChartsPacker.h b/Source/Engine/ShadowsOfMordor/AtlasChartsPacker.h index e28a53f0a..f94e7b5c1 100644 --- a/Source/Engine/ShadowsOfMordor/AtlasChartsPacker.h +++ b/Source/Engine/ShadowsOfMordor/AtlasChartsPacker.h @@ -17,8 +17,8 @@ namespace ShadowsOfMordor { Builder::LightmapUVsChart* Chart = nullptr; - Node(int32 x, int32 y, int32 width, int32 height) - : RectPackNode(x, y, width, height) + Node(Size x, Size y, Size width, Size height) + : RectPackNode(x, y, width, height) { } @@ -63,7 +63,7 @@ namespace ShadowsOfMordor /// Node* Insert(Builder::LightmapUVsChart* chart) { - return _root.Insert(chart->Width, chart->Height, _settings->ChartsPadding, chart, _settings); + return _root.Insert(chart->Width, chart->Height, chart, _settings); } }; }; diff --git a/Source/Engine/Utilities/RectPack.h b/Source/Engine/Utilities/RectPack.h index 6e51ac35a..a187e4c3b 100644 --- a/Source/Engine/Utilities/RectPack.h +++ b/Source/Engine/Utilities/RectPack.h @@ -31,12 +31,6 @@ struct RectPackNode , Height(height) { } - - bool operator<(const RectPackNode& other) const - { - // Sort largest to smallest - return Width * Height > other.Width * other.Height; - } }; /// @@ -118,7 +112,7 @@ public: /// /// The atlas width (in pixels). /// The atlas height (in pixels). - /// The atlas borders padding (in pixels). + /// The nodes padding (in pixels). Distance from node contents to atlas borders or other nodes. void Init(Size atlasWidth, Size atlasHeight, Size bordersPadding = 0) { Width = atlasWidth; @@ -126,7 +120,7 @@ public: BordersPadding = bordersPadding; Nodes.Clear(); FreeNodes.Clear(); - Nodes.Add(NodeType(bordersPadding, bordersPadding, atlasWidth - bordersPadding * 2, atlasHeight - bordersPadding * 2)); + Nodes.Add(NodeType(bordersPadding, bordersPadding, atlasWidth - bordersPadding, atlasHeight - bordersPadding)); FreeNodes.Add(&Nodes[0]); } @@ -145,62 +139,61 @@ public: /// /// The node width (in pixels). /// The node height (in pixels). - /// The node padding margin (in pixels) around its contents. /// The additional arguments. /// The node that contains inserted an item or null if failed to find a free space. template - NodeType* Insert(Size width, Size height, Size padding, Args&&... args) + NodeType* Insert(Size width, Size height, Args&&... args) { NodeType* result = nullptr; - const Size paddedWidth = width + padding; - const Size paddedHeight = height + padding; + const Size paddedWidth = width + BordersPadding; + const Size paddedHeight = height + BordersPadding; // Search free nodes from back to front and find the one that fits requested item size // TODO: FreeNodes are sorted so use Binary Search to quickly find the first tile that might have enough space for insert for (int32 i = FreeNodes.Count() - 1; i >= 0; i--) { - NodeType& freeNode = *FreeNodes.Get()[i]; - if (paddedWidth > freeNode.Width || paddedHeight > freeNode.Height) + NodeType* freeNode = FreeNodes.Get()[i]; + if (paddedWidth > freeNode->Width || paddedHeight > freeNode->Height) { // Not enough space continue; } // Check if there will be some remaining space left in this node - if (freeNode.Width != paddedWidth || freeNode.Height != paddedHeight) + if (freeNode->Width != width || freeNode->Height != height) { // Subdivide this node into up to 2 additional nodes - const Size remainingWidth = freeNode.Width - paddedWidth; - const Size remainingHeight = freeNode.Height - paddedHeight; + const Size remainingWidth = freeNode->Width - paddedWidth; + const Size remainingHeight = freeNode->Height - paddedHeight; // Split the remaining area around this node into two children SizeRect bigger, smaller; if (remainingHeight <= remainingWidth) { // Split vertically - smaller = SizeRect(freeNode.X, freeNode.Y + paddedHeight, width, remainingHeight); - bigger = SizeRect(freeNode.X + paddedWidth, freeNode.Y, remainingWidth, freeNode.Height); + smaller = SizeRect(freeNode->X, freeNode->Y + paddedHeight, width, remainingHeight); + bigger = SizeRect(freeNode->X + paddedWidth, freeNode->Y, remainingWidth, freeNode->Height); } else { // Split horizontally - smaller = SizeRect(freeNode.X + paddedWidth, freeNode.Y, remainingWidth, height); - bigger = SizeRect(freeNode.X, freeNode.Y + paddedHeight, freeNode.Width, remainingHeight); + smaller = SizeRect(freeNode->X + paddedWidth, freeNode->Y, remainingWidth, height); + bigger = SizeRect(freeNode->X, freeNode->Y + paddedHeight, freeNode->Width, remainingHeight); } if (smaller.W * smaller.H > bigger.W * bigger.H) Swap(bigger, smaller); - if (bigger.W * bigger.H > padding) + if (bigger.W * bigger.H > BordersPadding) AddFreeNode(Nodes.Add(NodeType(bigger.X, bigger.Y, bigger.W, bigger.H))); - if (smaller.W * smaller.H > padding) + if (smaller.W * smaller.H > BordersPadding) AddFreeNode(Nodes.Add(NodeType(smaller.X, smaller.Y, smaller.W, smaller.H))); // Shrink to the actual area - freeNode.Width = width; - freeNode.Height = height; + freeNode->Width = width; + freeNode->Height = height; } // Insert into this node - result = &freeNode; + result = freeNode; FreeNodes.RemoveAtKeepOrder(i); result->OnInsert(Forward(args)...); break;