aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client/Stitcher.cpp
diff options
context:
space:
mode:
authordaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
committerdaoge_cmd <3523206925@qq.com>2026-03-01 12:16:08 +0800
commitb691c43c44ff180d10e7d4a9afc83b98551ff586 (patch)
tree3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.Client/Stitcher.cpp
parentdef8cb415354ac390b7e89052a50605285f1aca9 (diff)
Initial commit
Diffstat (limited to 'Minecraft.Client/Stitcher.cpp')
-rw-r--r--Minecraft.Client/Stitcher.cpp261
1 files changed, 261 insertions, 0 deletions
diff --git a/Minecraft.Client/Stitcher.cpp b/Minecraft.Client/Stitcher.cpp
new file mode 100644
index 00000000..5888d4f8
--- /dev/null
+++ b/Minecraft.Client/Stitcher.cpp
@@ -0,0 +1,261 @@
+#include "stdafx.h"
+#include "StitchSlot.h"
+#include "Texture.h"
+#include "TextureHolder.h"
+#include "TextureManager.h"
+#include "StitchedTexture.h"
+#include "Stitcher.h"
+
+void Stitcher::_init(const wstring &name, int maxWidth, int maxHeight, bool forcePowerOfTwo, int forcedScale)
+{
+ this->name = name;
+ this->maxWidth = maxWidth;
+ this->maxHeight = maxHeight;
+ this->forcePowerOfTwo = forcePowerOfTwo;
+ this->forcedScale = forcedScale;
+
+ // 4J init
+ storageX = 0;
+ storageY = 0;
+ stitchedTexture = NULL;
+}
+
+Stitcher::Stitcher(const wstring &name, int maxWidth, int maxHeight, bool forcePowerOfTwo)
+{
+ _init(name, maxWidth, maxHeight, forcePowerOfTwo, 0);
+}
+
+Stitcher::Stitcher(const wstring &name, int maxWidth, int maxHeight, bool forcePowerOfTwo, int forcedScale)
+{
+ _init(name, maxWidth, maxHeight, forcePowerOfTwo, forcedScale);
+}
+
+int Stitcher::getWidth()
+{
+ return storageX;
+}
+
+int Stitcher::getHeight()
+{
+ return storageY;
+}
+
+void Stitcher::addTexture(TextureHolder *textureHolder)
+{
+ if (forcedScale > 0)
+ {
+ textureHolder->setForcedScale(forcedScale);
+ }
+ texturesToBeStitched.insert(textureHolder);
+}
+
+Texture *Stitcher::constructTexture(bool mipmap)
+{
+ if (forcePowerOfTwo)
+ {
+ storageX = smallestEncompassingPowerOfTwo(storageX);
+ storageY = smallestEncompassingPowerOfTwo(storageY);
+ }
+
+ stitchedTexture = TextureManager::getInstance()->createTexture(name, Texture::TM_DYNAMIC, storageX, storageY, Texture::TFMT_RGBA, mipmap);
+ stitchedTexture->fill(stitchedTexture->getRect(), 0xffff0000);
+
+ vector<StitchSlot *> *slots = gatherAreas();
+ for (int index = 0; index < slots->size(); index++)
+ {
+ StitchSlot *slot = slots->at(index);
+ TextureHolder *textureHolder = slot->getHolder();
+ stitchedTexture->blit(slot->getX(), slot->getY(), textureHolder->getTexture(), textureHolder->isRotated());
+ }
+ delete slots;
+ TextureManager::getInstance()->registerName(name, stitchedTexture);
+
+ return stitchedTexture;
+}
+
+void Stitcher::stitch()
+{
+ //TextureHolder[] textureHolders = texturesToBeStitched.toArray(new TextureHolder[texturesToBeStitched.size()]);
+ //Arrays.sort(textureHolders);
+
+ stitchedTexture = NULL;
+
+ //for (int i = 0; i < textureHolders.length; i++)
+ for(AUTO_VAR(it, texturesToBeStitched.begin()); it != texturesToBeStitched.end(); ++it)
+ {
+ TextureHolder *textureHolder = *it; //textureHolders[i];
+
+ if (!addToStorage(textureHolder))
+ {
+ app.DebugPrintf("Stitcher exception!\n");
+#ifndef _CONTENT_PACKAGE
+ __debugbreak();
+#endif
+ //throw new StitcherException(textureHolder);
+ }
+ }
+}
+
+vector<StitchSlot *> *Stitcher::gatherAreas()
+{
+ vector<StitchSlot *> *result = new vector<StitchSlot *>();
+
+ //for (StitchSlot slot : storage)
+ for(AUTO_VAR(it, storage.begin()); it != storage.end(); ++it)
+ {
+ StitchSlot *slot = *it;
+ slot->collectAssignments(result);
+ }
+
+ return result;
+}
+
+// Based on: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
+int Stitcher::smallestEncompassingPowerOfTwo(int input)
+{
+ int result = input - 1;
+ result |= result >> 1;
+ result |= result >> 2;
+ result |= result >> 4;
+ result |= result >> 8;
+ result |= result >> 16;
+ return result + 1;
+}
+
+bool Stitcher::addToStorage(TextureHolder *textureHolder)
+{
+ for (int i = 0; i < storage.size(); i++)
+ {
+ if (storage.at(i)->add(textureHolder))
+ {
+ return true;
+ }
+
+ // Try rotated
+ textureHolder->rotate();
+ if (storage.at(i)->add(textureHolder))
+ {
+ return true;
+ }
+
+ // Undo rotation
+ textureHolder->rotate();
+ }
+
+ return expand(textureHolder);
+}
+
+/**
+* Expand the current storage to take in account the new texture.
+* This should only be called if it didn't fit anywhere.
+*
+* @param textureHolder
+* @return Boolean indicating if it could accommodate for the growth
+*/
+bool Stitcher::expand(TextureHolder *textureHolder)
+{
+ int minDistance = min(textureHolder->getHeight(), textureHolder->getWidth());
+ bool firstAddition = storageX == 0 && storageY == 0;
+
+ // It couldn't fit, decide which direction to grow to
+ bool growOnX;
+ if (forcePowerOfTwo)
+ {
+ int xCurrentSize = smallestEncompassingPowerOfTwo(storageX);
+ int yCurrentSize = smallestEncompassingPowerOfTwo(storageY);
+ int xNewSize = smallestEncompassingPowerOfTwo(storageX + minDistance);
+ int yNewSize = smallestEncompassingPowerOfTwo(storageY + minDistance);
+
+ bool xCanGrow = xNewSize <= maxWidth;
+ bool yCanGrow = yNewSize <= maxHeight;
+
+ if (!xCanGrow && !yCanGrow)
+ {
+ return false;
+ }
+
+ // Even if the smallest side fits the larger might not >.>
+ int maxDistance = max(textureHolder->getHeight(), textureHolder->getWidth());
+ // TODO: This seems wrong ...
+ if (firstAddition && !xCanGrow && !(smallestEncompassingPowerOfTwo(storageY + maxDistance) <= maxHeight))
+ {
+ return false;
+ }
+
+ bool xWillGrow = xCurrentSize != xNewSize;
+ bool yWillGrow = yCurrentSize != yNewSize;
+
+ if (xWillGrow ^ yWillGrow)
+ {
+ // Either grows
+ //only pick X if it can grow AND it wanted to grow
+ // if !xCanGrow then yCanGrow
+
+
+ growOnX = xWillGrow && xCanGrow;
+ }
+ else
+ {
+ // Both or Neither grow -- smallest side wins
+ growOnX = xCanGrow && xCurrentSize <= yCurrentSize;
+ }
+ }
+ else
+ {
+ // We need to figure out to either expand
+ bool xCanGrow = (storageX + minDistance) <= maxWidth;
+ bool yCanGrow = (storageY + minDistance) <= maxHeight;
+
+ if (!xCanGrow && !yCanGrow)
+ {
+ return false;
+ }
+
+ // Prefer growing on X when its: first addition *or* its the smaller of the two sides
+ growOnX = (firstAddition || storageX <= storageY) && xCanGrow;
+ }
+
+ StitchSlot *slot;
+ if (growOnX)
+ {
+ if (textureHolder->getWidth() > textureHolder->getHeight())
+ {
+ textureHolder->rotate();
+ }
+
+ // Grow the 'Y' when it has no size yet
+ if (storageY == 0)
+ {
+ storageY = textureHolder->getHeight();
+ }
+
+ int newSlotWidth = textureHolder->getWidth();
+ // 4J Stu - If we are expanding the texture, then allocate the full powerOfTwo size that we are going to eventually create
+ if (forcePowerOfTwo)
+ {
+ newSlotWidth = smallestEncompassingPowerOfTwo(storageX + newSlotWidth) - storageX;
+ }
+ slot = new StitchSlot(storageX, 0, newSlotWidth, storageY);
+ //storageX += textureHolder->getWidth();
+ storageX += newSlotWidth;
+ }
+ else
+ {
+ int newSlotHeight = textureHolder->getHeight();
+ // 4J Stu - If we are expanding the texture, then allocate the full powerOfTwo size that we are going to eventually create
+ if (forcePowerOfTwo)
+ {
+ newSlotHeight = smallestEncompassingPowerOfTwo(storageY + newSlotHeight) - storageY;
+ }
+
+ // grow on Y
+ slot = new StitchSlot(0, storageY, storageX, newSlotHeight);
+ //storageY += textureHolder->getHeight();
+ storageY += newSlotHeight;
+ }
+
+ slot->add(textureHolder);
+ storage.push_back(slot);
+
+ return true;
+} \ No newline at end of file