atlas.cpp

main 175 lines · 4.8 KB Raw
Alex Alex Commit Client Upload Part 2 19/10/2026 00:06
1#include "atlas.h"
2#include "framebuffermanager.h"
3#include "painter.h"
4#include "graphics.h"
5#include <framework/core/clock.h>
6#include <framework/platform/platform.h>
7
8Atlas g_atlas;
9
10void Atlas::init()
11{
12 // If you don't care about players with old computers (~5% of players) you can change 4096 to 6144 or8192
13 m_size = std::min<size_t>(8192, g_graphics.getMaxTextureSize());
14 g_logger.info(stdext::format("[Atlas] Texture size is: %ix%i (max: %ix%i)", m_size, m_size, g_graphics.getMaxTextureSize(), g_graphics.getMaxTextureSize()));
15
16 for(size_t i = 0; i < 2; ++i) {
17 m_atlas[i] = g_framebuffers.createFrameBuffer();
18 if (i == 0) {
19 m_atlas[i]->resize(Size(m_size, m_size));
20 } else { // text atlas
21 m_atlas[i]->setSmooth(false);
22#ifdef BIG_FONTS
23 m_atlas[i]->resize(Size(m_size, m_size));
24#else
25 m_atlas[i]->resize(Size(2048, 2048));
26#endif
27 }
28
29 glActiveTexture(GL_TEXTURE6 + i);
30 glBindTexture(GL_TEXTURE_2D, m_atlas[i]->getTexture()->getId());
31 glActiveTexture(GL_TEXTURE0);
32 }
33 reset();
34 resetAtlas(1);
35}
36
37void Atlas::reset()
38{
39 m_doReset = false;
40 resetAtlas(0);
41 m_cache.clear();
42}
43
44void Atlas::reload()
45{
46 reset();
47 resetAtlas(1);
48}
49
50void Atlas::resetAtlas(int location) {
51 if (!m_atlas[location])
52 return;
53 for (auto& location : m_locations[location])
54 location.clear();
55
56 size_t size = m_atlas[location]->getSize().width();
57 for (size_t i = 0; i < size; i += 2048) {
58 m_locations[location][6].push_back(Point(i, i));
59 for (size_t x = 0; x < i; x += 2048) {
60 m_locations[location][6].push_back(Point(i, x));
61 m_locations[location][6].push_back(Point(x, i));
62 }
63 }
64
65 m_atlas[location]->bind();
66 g_painter->clear(Color::alpha);
67 m_atlas[location]->release();
68}
69
70
71void Atlas::terminate() {
72 for(auto& it : m_atlas)
73 it = nullptr;
74}
75
76Point Atlas::cache(uint64_t hash, const Size& size, bool& draw)
77{
78 if (m_doReset) {
79 reset();
80 }
81 auto it = m_cache.find(hash);
82 if (it != m_cache.end()) {
83 return it->second;
84 }
85
86 int index = calculateIndex(size);
87 if (index < 0 || index > 4 || (index == 4 && m_size == 2048)) { // too big to be cached, max 512x512
88 draw = false;
89 return Point(-1, -1);
90 }
91
92 if (m_locations[0][index].empty() && !findSpace(0, index)) {
93 draw = false;
94 m_doReset = true;
95 return Point(-1, -1);
96 }
97
98 Point location = m_locations[0][index].front();
99 m_locations[0][index].pop_front();
100 m_cache.emplace(hash, location);
101 draw = true;
102 return location;
103}
104
105void Atlas::bind()
106{
107 m_atlas[0]->bind();
108 g_painter->setCompositionMode(Painter::CompositionMode_Replace);
109}
110
111void Atlas::release()
112{
113 m_atlas[0]->release();
114}
115
116Point Atlas::cacheFont(const TexturePtr& fontTexture)
117{
118 fontTexture->update();
119 int index = calculateIndex(fontTexture->getSize());
120 if (index < 0) {
121 g_logger.fatal("[Atlas] Too big font texture. Max is 2048x2048");
122 }
123 if (m_locations[1][index].empty() && !findSpace(1, index)) {
124 g_logger.fatal("[Atlas] Out of space for new fonts, compile with BIG_FONTS or DONT_CACHE_FONTS definition");
125 }
126 Point location = m_locations[1][index].front();
127 m_locations[1][index].pop_front();
128 m_atlas[1]->bind();
129 g_painter->setCompositionMode(Painter::CompositionMode_Replace);
130 g_painter->drawTexturedRect(Rect(location, fontTexture->getSize()), fontTexture);
131 m_atlas[1]->release();
132 return location;
133}
134
135int Atlas::calculateIndex(const Size& size)
136{
137 int s = std::max<int>(size.width(), size.height());
138 if (s <= 64)
139 return s <= 32 ? 0 : 1;
140 if (s <= 256)
141 return s <= 128 ? 2 : 3;
142 if (s <= 1024)
143 return s <= 512 ? 4 : 5;
144 return s <= 2048 ? 6 : -1;
145}
146
147bool Atlas::findSpace(int location, int index) {
148 static const size_t sizes[7] = { 32, 64, 128, 256, 512, 1024, 2048 };
149 if (location >= 2 || index >= 6) {
150 return false;
151 }
152 if (m_locations[location][index + 1].size() == 0 && !findSpace(location, index + 1)) {
153 return false;
154 }
155 auto pos = m_locations[location][index + 1].front();
156 m_locations[location][index + 1].pop_front();
157 m_locations[location][index].push_back(pos);
158 m_locations[location][index].push_back(Point(pos.x, pos.y + sizes[index]));
159 m_locations[location][index].push_back(Point(pos.x + sizes[index], pos.y));
160 m_locations[location][index].push_back(Point(pos.x + sizes[index], pos.y + sizes[index]));
161 return true;
162}
163
164std::string Atlas::getStats() {
165 std::stringstream ss;
166 for (int l = 0; l < 2; ++l) {
167 for (auto& it : m_locations[l]) {
168 ss << it.size() << " ";
169 }
170 ss << "| ";
171 }
172 ss << "(" << m_size << "|" << g_graphics.getMaxTextureSize() << ")";
173 return ss.str();
174}
175
Top