the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "StitchSlot.h"
3#include "Texture.h"
4#include "TextureHolder.h"
5#include "TextureManager.h"
6#include "StitchedTexture.h"
7#include "Stitcher.h"
8
9void Stitcher::_init(const wstring &name, int maxWidth, int maxHeight, bool forcePowerOfTwo, int forcedScale)
10{
11 this->name = name;
12 this->maxWidth = maxWidth;
13 this->maxHeight = maxHeight;
14 this->forcePowerOfTwo = forcePowerOfTwo;
15 this->forcedScale = forcedScale;
16
17 // 4J init
18 storageX = 0;
19 storageY = 0;
20 stitchedTexture = NULL;
21}
22
23Stitcher::Stitcher(const wstring &name, int maxWidth, int maxHeight, bool forcePowerOfTwo)
24{
25 _init(name, maxWidth, maxHeight, forcePowerOfTwo, 0);
26}
27
28Stitcher::Stitcher(const wstring &name, int maxWidth, int maxHeight, bool forcePowerOfTwo, int forcedScale)
29{
30 _init(name, maxWidth, maxHeight, forcePowerOfTwo, forcedScale);
31}
32
33int Stitcher::getWidth()
34{
35 return storageX;
36}
37
38int Stitcher::getHeight()
39{
40 return storageY;
41}
42
43void Stitcher::addTexture(TextureHolder *textureHolder)
44{
45 if (forcedScale > 0)
46 {
47 textureHolder->setForcedScale(forcedScale);
48 }
49 texturesToBeStitched.insert(textureHolder);
50}
51
52Texture *Stitcher::constructTexture(bool mipmap)
53{
54 if (forcePowerOfTwo)
55 {
56 storageX = smallestEncompassingPowerOfTwo(storageX);
57 storageY = smallestEncompassingPowerOfTwo(storageY);
58 }
59
60 stitchedTexture = TextureManager::getInstance()->createTexture(name, Texture::TM_DYNAMIC, storageX, storageY, Texture::TFMT_RGBA, mipmap);
61 stitchedTexture->fill(stitchedTexture->getRect(), 0xffff0000);
62
63 vector<StitchSlot *> *slots = gatherAreas();
64 for (int index = 0; index < slots->size(); index++)
65 {
66 StitchSlot *slot = slots->at(index);
67 TextureHolder *textureHolder = slot->getHolder();
68 stitchedTexture->blit(slot->getX(), slot->getY(), textureHolder->getTexture(), textureHolder->isRotated());
69 }
70 delete slots;
71 TextureManager::getInstance()->registerName(name, stitchedTexture);
72
73 return stitchedTexture;
74}
75
76void Stitcher::stitch()
77{
78 //TextureHolder[] textureHolders = texturesToBeStitched.toArray(new TextureHolder[texturesToBeStitched.size()]);
79 //Arrays.sort(textureHolders);
80
81 stitchedTexture = NULL;
82
83 //for (int i = 0; i < textureHolders.length; i++)
84 for(AUTO_VAR(it, texturesToBeStitched.begin()); it != texturesToBeStitched.end(); ++it)
85 {
86 TextureHolder *textureHolder = *it; //textureHolders[i];
87
88 if (!addToStorage(textureHolder))
89 {
90 app.DebugPrintf("Stitcher exception!\n");
91#ifndef _CONTENT_PACKAGE
92 __debugbreak();
93#endif
94 //throw new StitcherException(textureHolder);
95 }
96 }
97}
98
99vector<StitchSlot *> *Stitcher::gatherAreas()
100{
101 vector<StitchSlot *> *result = new vector<StitchSlot *>();
102
103 //for (StitchSlot slot : storage)
104 for(AUTO_VAR(it, storage.begin()); it != storage.end(); ++it)
105 {
106 StitchSlot *slot = *it;
107 slot->collectAssignments(result);
108 }
109
110 return result;
111}
112
113// Based on: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
114int Stitcher::smallestEncompassingPowerOfTwo(int input)
115{
116 int result = input - 1;
117 result |= result >> 1;
118 result |= result >> 2;
119 result |= result >> 4;
120 result |= result >> 8;
121 result |= result >> 16;
122 return result + 1;
123}
124
125bool Stitcher::addToStorage(TextureHolder *textureHolder)
126{
127 for (int i = 0; i < storage.size(); i++)
128 {
129 if (storage.at(i)->add(textureHolder))
130 {
131 return true;
132 }
133
134 // Try rotated
135 textureHolder->rotate();
136 if (storage.at(i)->add(textureHolder))
137 {
138 return true;
139 }
140
141 // Undo rotation
142 textureHolder->rotate();
143 }
144
145 return expand(textureHolder);
146}
147
148/**
149* Expand the current storage to take in account the new texture.
150* This should only be called if it didn't fit anywhere.
151*
152* @param textureHolder
153* @return Boolean indicating if it could accommodate for the growth
154*/
155bool Stitcher::expand(TextureHolder *textureHolder)
156{
157 int minDistance = min(textureHolder->getHeight(), textureHolder->getWidth());
158 bool firstAddition = storageX == 0 && storageY == 0;
159
160 // It couldn't fit, decide which direction to grow to
161 bool growOnX;
162 if (forcePowerOfTwo)
163 {
164 int xCurrentSize = smallestEncompassingPowerOfTwo(storageX);
165 int yCurrentSize = smallestEncompassingPowerOfTwo(storageY);
166 int xNewSize = smallestEncompassingPowerOfTwo(storageX + minDistance);
167 int yNewSize = smallestEncompassingPowerOfTwo(storageY + minDistance);
168
169 bool xCanGrow = xNewSize <= maxWidth;
170 bool yCanGrow = yNewSize <= maxHeight;
171
172 if (!xCanGrow && !yCanGrow)
173 {
174 return false;
175 }
176
177 // Even if the smallest side fits the larger might not >.>
178 int maxDistance = max(textureHolder->getHeight(), textureHolder->getWidth());
179 // TODO: This seems wrong ...
180 if (firstAddition && !xCanGrow && !(smallestEncompassingPowerOfTwo(storageY + maxDistance) <= maxHeight))
181 {
182 return false;
183 }
184
185 bool xWillGrow = xCurrentSize != xNewSize;
186 bool yWillGrow = yCurrentSize != yNewSize;
187
188 if (xWillGrow ^ yWillGrow)
189 {
190 // Either grows
191 //only pick X if it can grow AND it wanted to grow
192 // if !xCanGrow then yCanGrow
193
194
195 growOnX = xWillGrow && xCanGrow;
196 }
197 else
198 {
199 // Both or Neither grow -- smallest side wins
200 growOnX = xCanGrow && xCurrentSize <= yCurrentSize;
201 }
202 }
203 else
204 {
205 // We need to figure out to either expand
206 bool xCanGrow = (storageX + minDistance) <= maxWidth;
207 bool yCanGrow = (storageY + minDistance) <= maxHeight;
208
209 if (!xCanGrow && !yCanGrow)
210 {
211 return false;
212 }
213
214 // Prefer growing on X when its: first addition *or* its the smaller of the two sides
215 growOnX = (firstAddition || storageX <= storageY) && xCanGrow;
216 }
217
218 StitchSlot *slot;
219 if (growOnX)
220 {
221 if (textureHolder->getWidth() > textureHolder->getHeight())
222 {
223 textureHolder->rotate();
224 }
225
226 // Grow the 'Y' when it has no size yet
227 if (storageY == 0)
228 {
229 storageY = textureHolder->getHeight();
230 }
231
232 int newSlotWidth = textureHolder->getWidth();
233 // 4J Stu - If we are expanding the texture, then allocate the full powerOfTwo size that we are going to eventually create
234 if (forcePowerOfTwo)
235 {
236 newSlotWidth = smallestEncompassingPowerOfTwo(storageX + newSlotWidth) - storageX;
237 }
238 slot = new StitchSlot(storageX, 0, newSlotWidth, storageY);
239 //storageX += textureHolder->getWidth();
240 storageX += newSlotWidth;
241 }
242 else
243 {
244 int newSlotHeight = textureHolder->getHeight();
245 // 4J Stu - If we are expanding the texture, then allocate the full powerOfTwo size that we are going to eventually create
246 if (forcePowerOfTwo)
247 {
248 newSlotHeight = smallestEncompassingPowerOfTwo(storageY + newSlotHeight) - storageY;
249 }
250
251 // grow on Y
252 slot = new StitchSlot(0, storageY, storageX, newSlotHeight);
253 //storageY += textureHolder->getHeight();
254 storageY += newSlotHeight;
255 }
256
257 slot->add(textureHolder);
258 storage.push_back(slot);
259
260 return true;
261}