Cogs.Core
CADAttributeMap.h
1#pragma once
2
3#include <glm/vec2.hpp>
4#include <glm/vec3.hpp>
5
6#include <algorithm>
7#include <span>
8#include <vector>
9
10namespace Cogs::Editor
11{
16 enum class AttributeMapPixelState : uint8_t {
17 Default = 0,
18 Selected = 1,
19 Highlighted = 2,
20 Hidden = 3,
21 SelectedAndHighlighted = 4,
22 Unused00 = 5,
23 Unused01 = 6,
24 Unused02 = 7,
25 Unused03 = 8,
26 Unused04 = 9,
27 Unused05 = 10,
28 Unused06 = 11,
29 Unused07 = 12,
30 Unused08 = 13,
31 Unused09 = 14,
32 Unused10 = 15,
33 Unused11 = 16,
34 Unused12 = 17,
35 Unused13 = 18,
36 Unused14 = 19,
37 Unused15 = 20,
38 Unused16 = 21,
39 Unused17 = 22,
40 Unused18 = 23,
41 Unused19 = 24,
42 Unused20 = 25,
43 Unused21 = 26,
44 Unused22 = 27,
45 Unused23 = 28,
46 Unused24 = 29,
47 Unused25 = 30,
48 Unused26 = 31,
49 Unused27 = 32,
50 Unused28 = 33,
51 Unused29 = 34,
52 Unused30 = 35,
53 Unused31 = 36,
54 Unused32 = 37,
55 Unused33 = 38,
56 Unused34 = 39,
57 Unused35 = 40,
58 Unused36 = 41,
59 Unused37 = 42,
60 Unused38 = 43,
61 Unused39 = 44,
62 Unused40 = 45,
63 Unused41 = 46,
64 Unused42 = 47,
65 Unused43 = 48,
66 Unused44 = 49,
67 Unused45 = 50,
68 Unused46 = 51,
69 Unused47 = 52,
70 Unused48 = 53,
71 Unused49 = 54,
72 Unused50 = 55,
73 Unused51 = 56,
74 Unused52 = 57,
75 Unused53 = 58,
76 Unused54 = 59,
77 Unused55 = 60,
78 Unused56 = 61,
79 Unused57 = 62,
80 Unused58 = 63,
81 };
82
87 enum class AttributeMapPixelTransparency : uint8_t {
88 Off = 0,
89 Low = 1,
90 Medium = 2,
91 High = 3,
92 };
93
96 AttributeMapPixelTransparency transparency;
97 AttributeMapPixelState state;
98 };
99
100
112 class CADAttributeMap final {
113 public:
118 explicit CADAttributeMap(bool powerOfTwoTextures = true)
119 : powerOfTwoTextures(powerOfTwoTextures)
120 {
121 }
122 CADAttributeMap(const CADAttributeMap&) = delete;
123 CADAttributeMap& operator=(const CADAttributeMap&) = delete;
124
128 std::span<const uint8_t> getAttributeMap() const { return this->_attributeMap; }
129
133 glm::uvec2 getAttrSize() const { return this->_attrSize; }
134
140 void init(glm::uvec3 color, AttributeMapAlpha alpha)
141 {
142 uint32_t size = this->_attrSize.x * this->_attrSize.y;
143 for (uint32_t i = 0; i < size; i++) {
144 this->setColor(i, color);
145 this->setAlpha(i, alpha);
146 }
147 }
148
155 bool growToContainIndex(size_t index)
156 {
157 if (this->isValidIndex(index)) {
158 return false;
159 }
160
161 const glm::uvec2 newSize = CADAttributeMap::getAttributeSize(index + 1, powerOfTwoTextures);
162 this->resize(newSize);
163 return true;
164 }
165
171 void setColor(size_t index, glm::uvec3 color)
172 {
173 const size_t offset = index * 4;
174 this->_attributeMap[offset + 0] = uint8_t(color[0]);
175 this->_attributeMap[offset + 1] = uint8_t(color[1]);
176 this->_attributeMap[offset + 2] = uint8_t(color[2]);
177 }
178
184 glm::vec3 getColor(size_t index) const {
185 const size_t offset = index * 4;
186 return glm::vec3(this->_attributeMap[offset + 0], this->_attributeMap[offset + 1], this->_attributeMap[offset + 2]);
187 }
188
194 void setAlpha(size_t index, AttributeMapAlpha alpha)
195 {
196 this->_attributeMap[index * 4 + 3] = CADAttributeMap::encodeAlpha(alpha);
197 }
198
205 {
206 return CADAttributeMap::decodeAlpha(this->_attributeMap[index * 4 + 3]);
207 }
208
209
215 bool isValidIndex(size_t index) const
216 {
217 return index * 4U < this->_attributeMap.size();
218 }
219
227 uint8_t getAttribute(size_t index, size_t attrOffset)
228 {
229 return this->_attributeMap[index * 4 + attrOffset];
230 }
231
239 void setAttribute(size_t index, size_t attrOffset, uint8_t attribute)
240 {
241 this->_attributeMap[index * 4 + attrOffset] = attribute;
242 }
243
248 void resize(glm::uvec2 attrSize)
249 {
250 // Data stored in texture. Avoid empty texture.
251 attrSize.x = std::max(2U, attrSize.x);
252 attrSize.y = std::max(2U, attrSize.y);
253
254 if (attrSize != this->_attrSize) {
255 glm::uvec2 oldSize = this->_attrSize;
256 this->_attrSize = attrSize;
257 this->_attributeMap.resize(this->_attrSize.x * this->_attrSize.y * 4);
258
259 if (attrSize.x > oldSize.x || attrSize.y > oldSize.y) {
260 // Fill rest with defaults:
261 uint32_t oldMaxIndex = oldSize.x * oldSize.y;
262 uint32_t newMaxSize = attrSize.x * attrSize.y;
263 for (uint32_t i = oldMaxIndex; i < newMaxSize; ++i) {
264 this->setColor(i, defaultColor);
265 this->setAlpha(i, defaultAlpha);
266 }
267 }
268 }
269 }
270
277 static glm::uvec2 getAttributeSize(size_t tagCount, bool powerOfTwo)
278 {
279 static constexpr uint32_t MinTexSize = 8;
280 uint32_t sizeX = MinTexSize;
281 while (sizeX * sizeX < tagCount) {
282 sizeX = sizeX * 2;
283 }
284
285 if (powerOfTwo) {
286 return { sizeX, sizeX };
287 }
288 else {
289 uint32_t sizeY = MinTexSize;
290 while (sizeX * sizeY < tagCount) {
291 sizeY = sizeY * 2;
292 }
293 return { sizeX, sizeY };
294 }
295 }
296
302 {
303 return defaultAlpha;
304 }
305
308 {
309 defaultAlpha = alpha;
310 }
311
313 glm::uvec3 getDefaultColor() const { return defaultColor; }
314
316 void setDefaultColor(glm::uvec3 color)
317 {
318 defaultColor = color;
319 }
320
325 static constexpr uint8_t encodeAlpha(AttributeMapAlpha data) noexcept
326 {
327 // Bits 0-1 cover transparency
328 // Bits 2-7 cover state
329 // This works by first adding the 6 bits for the state, then shifting these bits to the left by 2.
330 // Secondly, it adds the two bits for transparency again with a bitwise OR '|' operator.
331 // This means that if the state has a value higher than 31 (00111111), it will fail, as the two rightmost bits will be discarded.
332 // It also means that if transparency has a value higher than 3 (00000011), it will affect the state.
333 const uint8_t bits = (uint8_t(data.state) << 2) | uint8_t(data.transparency);
334 return bits;
335 }
336
341 static constexpr AttributeMapAlpha decodeAlpha(uint8_t alpha)
342 {
343 // Bits 0-1 cover transparency
344 // Bits 2-7 cover state
345 AttributeMapPixelTransparency transparency = AttributeMapPixelTransparency(alpha & 3U); // bitwise AND with 00000011 to only retain bits 0-1
346 AttributeMapPixelState state = AttributeMapPixelState(alpha >> 2U); // shift 2 to the right to extract the value of bits 2-7
347 return { transparency, state };
348 }
349
350 private:
351 bool powerOfTwoTextures = true;
352 glm::uvec2 _attrSize = {};
353 std::vector<uint8_t> _attributeMap;
354 glm::uvec3 defaultColor = { 0,0,0 };
355 AttributeMapAlpha defaultAlpha = { AttributeMapPixelTransparency::Off, AttributeMapPixelState::Default, };
356 };
357}
void init(glm::uvec3 color, AttributeMapAlpha alpha)
static constexpr uint8_t encodeAlpha(AttributeMapAlpha data) noexcept
AttributeMapAlpha getAlpha(size_t index)
CADAttributeMap(bool powerOfTwoTextures=true)
void setAttribute(size_t index, size_t attrOffset, uint8_t attribute)
bool isValidIndex(size_t index) const
glm::uvec2 getAttrSize() const
void setDefaultColor(glm::uvec3 color)
Set default color value.
static glm::uvec2 getAttributeSize(size_t tagCount, bool powerOfTwo)
static constexpr AttributeMapAlpha decodeAlpha(uint8_t alpha)
uint8_t getAttribute(size_t index, size_t attrOffset)
void setDefaultAlpha(AttributeMapAlpha alpha)
Get default Alpha entry.
glm::uvec3 getDefaultColor() const
Get default color value.
void resize(glm::uvec2 attrSize)
bool growToContainIndex(size_t index)
std::span< const uint8_t > getAttributeMap() const
void setAlpha(size_t index, AttributeMapAlpha alpha)
AttributeMapAlpha getDefaultAlpha() const
glm::vec3 getColor(size_t index) const
void setColor(size_t index, glm::uvec3 color)
@ Off
Disable capture and camera, consume no rendering resources.