TDME2  1.9.200
SimpleTextureAtlas.cpp
Go to the documentation of this file.
2 
3 #include <array>
4 #include <string>
5 #include <unordered_map>
6 #include <vector>
7 
8 #include <tdme/tdme.h>
9 #include <tdme/engine/Texture.h>
10 #include <tdme/math/Math.h>
12 #include <tdme/utilities/Console.h>
13 
15 
16 using std::array;
17 using std::string;
18 using std::unordered_map;
19 using std::vector;
20 
22 using tdme::math::Math;
25 
26 SimpleTextureAtlas::SimpleTextureAtlas(const string& id): atlasTextureId(id) {
27 }
28 
30  for (const auto& [atlasTextureEntityIdx, atlasTextureEntity]: atlasTextureIdxToTextureMapping) {
31  atlasTextureEntity->releaseReference();
32  }
33  if (atlasTexture != nullptr) {
35  }
36 }
37 
39  Console::println("SimpleTextureAtlas::addTexture(): texture added to atlas: " + texture->getId() + ", atlas with id: " + atlasTextureId);
40  // check if texture had been added
41  {
42  auto textureIdx = getTextureIdx(texture);
43  if (textureIdx != TEXTURE_IDX_NONE) {
44  textureReferenceCounter[texture]++;
45  return textureIdx;
46  }
47  }
48  // nope, add it
49  auto textureIdx = -1;
50  if (freeTextureIds.empty() == false) {
51  textureIdx = freeTextureIds[0];
52  freeTextureIds.erase(freeTextureIds.begin() + 0);
53  } else {
54  textureIdx = textureToAtlasTextureIdxMapping.size();
55  if (textureIdx > 255) {
56  Console::println("SimpleTextureAtlas::addTexture(): texture added to atlas: " + texture->getId() + ", atlas with id: " + atlasTextureId + ", too many textures!");
57  return TEXTURE_IDX_NONE;
58  }
59  }
60  //
61  texture->acquireReference();
62  textureToAtlasTextureIdxMapping[texture] = textureIdx;
63  atlasTextureIdxToTextureMapping[textureIdx] = texture;
64  textureReferenceCounter[texture]++;
65  //
66  requiresUpdate = true;
67  //
68  return textureIdx;
69 }
70 
72  Console::println("SimpleTextureAtlas::removeTexture(): texture removed from atlas: " + texture->getId() + ", atlas with id: " + atlasTextureId);
73  auto textureIdx = getTextureIdx(texture);
74  if (textureIdx == TEXTURE_IDX_NONE) {
75  Console::println("SimpleTextureAtlas::removeTexture(): texture was not yet added to atlas: " + texture->getId() + ", atlas with id: " + atlasTextureId);
76  return;
77  }
78  textureReferenceCounter[texture]--;
79  if (textureReferenceCounter[texture] == 0) {
80  Console::println("SimpleTextureAtlas::removeTexture(): reference counter = 0, texture removed from atlas: " + texture->getId() + ", atlas with id: " + atlasTextureId);
81  textureReferenceCounter.erase(texture);
82  textureToAtlasTextureIdxMapping.erase(texture);
83  atlasTextureIdxToTextureMapping.erase(textureIdx);
84  texture->releaseReference();
85  }
86  //
87  requiresUpdate = true;
88 }
89 
91  Console::println("SimpleTextureAtlas::update(): " + atlasTextureId);
92  // release last atlas if we have any
93  if (atlasTexture != nullptr) {
95  atlasTexture = nullptr;
96  }
97 
98  //
99  if (atlasTextureIdxToTextureMapping.empty() == true) {
100  Console::println("SimpleTextureAtlas::update(): " + atlasTextureId + ": nothing to do");
101  //
102  requiresUpdate = false;
103  //
104  return;
105  }
106 
107  //
108  auto textureAtlasSize = static_cast<int>(Math::ceil(Math::sqrt(atlasTextureIdxToTextureMapping.size())));
109  auto atlasTextureWidth = textureAtlasSize * ATLAS_TEXTURE_SIZE;
110  auto atlasTextureHeight = textureAtlasSize * ATLAS_TEXTURE_SIZE;
111  auto atlasTextureByteBuffer = ByteBuffer(atlasTextureWidth * atlasTextureHeight * 4);
112  array<Texture*, 256> atlasTextureIdxToTextureMappingVector { nullptr };
113  array<ByteBuffer, 256> atlasTextureIdxToTextureTextureDataVector;
114  for (const auto& [atlasTextureIdx, atlasTextureEntity]: atlasTextureIdxToTextureMapping) {
115  atlasTextureIdxToTextureMappingVector[atlasTextureIdx] = atlasTextureEntity;
116  atlasTextureIdxToTextureTextureDataVector[atlasTextureIdx] = atlasTextureEntity->getRGBTextureData();
117  }
118  vector<ByteBuffer> atlasTextureByteBufferMapping;
119  for (auto y = 0; y < atlasTextureHeight; y++)
120  for (auto x = 0; x < atlasTextureWidth; x++) {
121  auto atlasTextureIdxX = x / ATLAS_TEXTURE_SIZE;
122  auto atlasTextureIdxY = y / ATLAS_TEXTURE_SIZE;
123  auto textureX = x - (atlasTextureIdxX * ATLAS_TEXTURE_SIZE);
124  auto textureY = y - (atlasTextureIdxY * ATLAS_TEXTURE_SIZE);
125  auto textureXFloat = static_cast<float>(textureX) / static_cast<float>(ATLAS_TEXTURE_SIZE);
126  auto textureYFloat = static_cast<float>(textureY) / static_cast<float>(ATLAS_TEXTURE_SIZE);
127  auto atlasTextureIdx = atlasTextureIdxY * textureAtlasSize + atlasTextureIdxX;
128  auto texture = atlasTextureIdxToTextureMappingVector[atlasTextureIdx];
129  if (texture != nullptr) {
130  auto textureTextureData = &atlasTextureIdxToTextureTextureDataVector[atlasTextureIdx];
131  auto textureWidth = texture->getTextureWidth();
132  auto textureHeight = texture->getTextureHeight();
133  auto textureBytesPerPixel = texture->getRGBDepthBitsPerPixel() / 8;
134  auto textureXInt = static_cast<int>(textureXFloat * static_cast<float>(textureWidth));
135  auto textureYInt = static_cast<int>(textureYFloat * static_cast<float>(textureHeight));
136  if (textureXInt < ATLAS_TEXTURE_BORDER) textureXInt = 0; else
137  if (textureXInt > textureWidth - ATLAS_TEXTURE_BORDER) textureXInt = textureWidth - 1; else
138  textureXInt = static_cast<int>((static_cast<float>(textureXInt) - static_cast<float>(ATLAS_TEXTURE_BORDER)) * (static_cast<float>(textureWidth) + static_cast<float>(ATLAS_TEXTURE_BORDER) * 2.0f) / static_cast<float>(textureWidth));
139  if (textureYInt < ATLAS_TEXTURE_BORDER) textureYInt = 0; else
140  if (textureYInt > textureHeight - ATLAS_TEXTURE_BORDER) textureYInt = textureHeight - 1; else
141  textureYInt = static_cast<int>((static_cast<float>(textureYInt) - static_cast<float>(ATLAS_TEXTURE_BORDER)) * (static_cast<float>(textureHeight) + static_cast<float>(ATLAS_TEXTURE_BORDER) * 2.0f) / static_cast<float>(textureHeight));
142  auto texturePixelOffset =
143  textureYInt * textureWidth * textureBytesPerPixel +
144  textureXInt * textureBytesPerPixel;
145  auto r = textureTextureData->get(texturePixelOffset + 0);
146  auto g = textureTextureData->get(texturePixelOffset + 1);
147  auto b = textureTextureData->get(texturePixelOffset + 2);
148  auto a = textureBytesPerPixel == 4?textureTextureData->get(texturePixelOffset + 3):0xff;
149  atlasTextureByteBuffer.put(r);
150  atlasTextureByteBuffer.put(g);
151  atlasTextureByteBuffer.put(b);
152  atlasTextureByteBuffer.put(a);
153  } else {
154  auto r = 0xff;
155  auto g = 0x00;
156  auto b = 0x00;
157  auto a = 0xff;
158  atlasTextureByteBuffer.put(r);
159  atlasTextureByteBuffer.put(g);
160  atlasTextureByteBuffer.put(b);
161  atlasTextureByteBuffer.put(a);
162  }
163  }
164  atlasTexture = new Texture(
166  Texture::TEXTUREDEPTH_RGBA,
167  Texture::TEXTUREFORMAT_RGBA,
168  atlasTextureWidth, atlasTextureHeight,
169  atlasTextureWidth, atlasTextureHeight,
170  Texture::TEXTUREFORMAT_RGBA,
171  atlasTextureByteBuffer
172  );
173  atlasTexture->setAtlasSize(textureAtlasSize);
174  atlasTexture->setUseMipMap(false);
176 
177  //
178  requiresUpdate = false;
179 }
180 
Texture entity.
Definition: Texture.h:24
const string & getId() const
Definition: Texture.h:172
void setUseMipMap(bool useMipMap)
Set if to use mip map.
Definition: Texture.h:302
void setAtlasSize(uint16_t atlasSize)
Set atlas size.
Definition: Texture.h:377
Standard math functions.
Definition: Math.h:19
Byte buffer class.
Definition: ByteBuffer.h:27
Console class.
Definition: Console.h:29
static void println()
Print new line to console.
Definition: Console.cpp:92
virtual void releaseReference()
Releases a reference, thus decrementing the counter and delete it if reference counter is zero.
Definition: Reference.h:38
virtual void acquireReference()
Acquires a reference, incrementing the counter.
Definition: Reference.h:31
void removeTexture(Texture *texture)
Remove texture.
unordered_map< Texture *, int > textureReferenceCounter
unordered_map< Texture *, int > textureToAtlasTextureIdxMapping
int addTexture(Texture *texture)
Add texture.
int getTextureIdx(Texture *texture)
Returns specific atlas texture index within atlas.
void update()
Update texture atlas.
unordered_map< int, Texture * > atlasTextureIdxToTextureMapping