Client Upload Part 2

RD Core / Commit #5

Commit Client Upload Part 2

Alex Alex committed 19/10/2026 00:06 main Patch
1,244 files +271,215 -0
A RD_Client/src/framework/graphics/atlas.cpp +174-0 View file
@@ -0,0 +1,174 @@
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+
8+Atlas g_atlas;
9+
10+void 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+
37+void Atlas::reset()
38+{
39+ m_doReset = false;
40+ resetAtlas(0);
41+ m_cache.clear();
42+}
43+
44+void Atlas::reload()
45+{
46+ reset();
47+ resetAtlas(1);
48+}
49+
50+void 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+
71+void Atlas::terminate() {
72+ for(auto& it : m_atlas)
73+ it = nullptr;
74+}
75+
76+Point 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+
105+void Atlas::bind()
106+{
107+ m_atlas[0]->bind();
108+ g_painter->setCompositionMode(Painter::CompositionMode_Replace);
109+}
110+
111+void Atlas::release()
112+{
113+ m_atlas[0]->release();
114+}
115+
116+Point 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+
135+int 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+
147+bool 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+
164+std::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+}
A RD_Client/src/framework/graphics/atlas.h +39-0 View file
@@ -0,0 +1,39 @@
1+#ifndef ATLAS_H
2+#define ATLAS_H
3+
4+#include "drawqueue.h"
5+#include "framebuffer.h"
6+#include <map>
7+#include <vector>
8+
9+class Atlas {
10+public:
11+ void init();
12+ void terminate();
13+ void reload();
14+
15+ Point cache(uint64_t hash, const Size& size, bool& draw);
16+ Point cacheFont(const TexturePtr& fontTexture);
17+
18+ TexturePtr get(int location) { return m_atlas[location]->getTexture(); }
19+ void bind();
20+ void release();
21+
22+ std::string getStats(); // not thread safe!
23+
24+private:
25+ void reset();
26+ void resetAtlas(int location);
27+ bool findSpace(int location, int index);
28+ inline int calculateIndex(const Size& size);
29+
30+ FrameBufferPtr m_atlas[2];
31+ std::map<uint64_t, Point> m_cache;
32+ std::list<Point> m_locations[2][7];
33+ size_t m_size;
34+ bool m_doReset = false;
35+};
36+
37+extern Atlas g_atlas;
38+
39+#endif
A RD_Client/src/framework/graphics/bitmapfont.cpp +389-0 View file
@@ -0,0 +1,389 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#include "atlas.h"
24+#include "bitmapfont.h"
25+#include "texturemanager.h"
26+#include "graphics.h"
27+#include "image.h"
28+
29+#include <framework/core/eventdispatcher.h>
30+#include <framework/otml/otml.h>
31+#include <framework/util/extras.h>
32+
33+void BitmapFont::load(const OTMLNodePtr& fontNode)
34+{
35+ OTMLNodePtr textureNode = fontNode->at("texture");
36+ std::string textureFile = stdext::resolve_path(textureNode->value(), textureNode->source());
37+ Size glyphSize = fontNode->valueAt<Size>("glyph-size");
38+ m_glyphHeight = fontNode->valueAt<int>("height");
39+ m_yOffset = fontNode->valueAt("y-offset", 0);
40+ m_firstGlyph = fontNode->valueAt("first-glyph", 32);
41+ m_glyphSpacing = fontNode->valueAt("spacing", Size(0,0));
42+ int spaceWidth = fontNode->valueAt("space-width", glyphSize.width());
43+
44+ if(OTMLNodePtr node = fontNode->get("fixed-glyph-width")) {
45+ for(int glyph = m_firstGlyph; glyph < 256; ++glyph)
46+ m_glyphsSize[glyph] = Size(node->value<int>(), m_glyphHeight);
47+ } else {
48+ calculateGlyphsWidthsAutomatically(Image::load(textureFile), glyphSize);
49+ }
50+
51+ // 32 is space
52+ m_glyphsSize[32].setWidth(spaceWidth);
53+
54+ // use 127 as spacer [Width: 1], Important for the current NPC highlighting system
55+ m_glyphsSize[127].setWidth(1);
56+
57+ // new line actually has a size that will be useful in multiline algorithm
58+ m_glyphsSize[(uchar)'\n'] = Size(1, m_glyphHeight);
59+
60+ // read custom widths
61+ /*
62+ if(OTMLNodePtr node = fontNode->get("glyph-widths")) {
63+ for(const OTMLNodePtr& child : node->children())
64+ m_glyphsSize[stdext::safe_cast<int>(child->tag())].setWidth(child->value<int>());
65+ }
66+ */
67+
68+ // load font texture
69+ m_texture = g_textures.getTexture(textureFile);
70+ if (!m_texture)
71+ return;
72+ m_texture->update();
73+
74+ int numHorizontalGlyphs = m_texture->getSize().width() / glyphSize.width();
75+#ifdef DONT_CACHE_FONTS
76+ Point offset(0, 0);
77+#else
78+ Point offset = g_atlas.cacheFont(m_texture);
79+ m_texture = g_atlas.get(1);
80+#endif
81+ for (int glyph = m_firstGlyph; glyph < 256; ++glyph) {
82+ m_glyphsTextureCoords[glyph].setRect(((glyph - m_firstGlyph) % numHorizontalGlyphs) * glyphSize.width() + offset.x,
83+ ((glyph - m_firstGlyph) / numHorizontalGlyphs) * glyphSize.height() + offset.y,
84+ m_glyphsSize[glyph].width(),
85+ m_glyphHeight);
86+ }
87+}
88+
89+void BitmapFont::drawText(const std::string& text, const Point& startPos, const Color& color, bool shadow)
90+{
91+ Size boxSize = g_painter->getResolution() - startPos.toSize();
92+ Rect screenCoords(startPos, boxSize);
93+ drawText(text, screenCoords, Fw::AlignTopLeft, shadow);
94+}
95+
96+void BitmapFont::drawText(const std::string& text, const Rect& screenCoords, Fw::AlignmentFlag align, const Color& color, bool shadow)
97+{
98+ g_drawQueue->addText(static_self_cast<BitmapFont>(), text, screenCoords, align, color, shadow);
99+}
100+
101+void BitmapFont::drawColoredText(const std::string& text, const Rect& screenCoords, Fw::AlignmentFlag align, const std::vector<std::pair<int, Color>>& colors, bool shadow)
102+{
103+ g_drawQueue->addColoredText(static_self_cast<BitmapFont>(), text, screenCoords, align, colors, shadow);
104+}
105+
106+void BitmapFont::calculateDrawTextCoords(CoordsBuffer& coordsBuffer, const std::string& text, const Rect& screenCoords, Fw::AlignmentFlag align)
107+{
108+ // prevent glitches from invalid rects
109+ if (!screenCoords.isValid() || !m_texture)
110+ return;
111+
112+ int textLenght = text.length();
113+
114+ // map glyphs positions
115+ Size textBoxSize;
116+ const std::vector<Point>& glyphsPositions = calculateGlyphsPositions(text, align, &textBoxSize);
117+
118+ for (int i = 0; i < textLenght; ++i) {
119+ int glyph = (uchar)text[i];
120+
121+ // skip invalid glyphs
122+ if (glyph < 32)
123+ continue;
124+
125+ // calculate initial glyph rect and texture coords
126+ Rect glyphScreenCoords(glyphsPositions[i], m_glyphsSize[glyph]);
127+ Rect glyphTextureCoords = m_glyphsTextureCoords[glyph];
128+
129+ // first translate to align position
130+ if (align & Fw::AlignBottom) {
131+ glyphScreenCoords.translate(0, screenCoords.height() - textBoxSize.height());
132+ } else if (align & Fw::AlignVerticalCenter) {
133+ glyphScreenCoords.translate(0, (screenCoords.height() - textBoxSize.height()) / 2);
134+ } else { // AlignTop
135+ // nothing to do
136+ }
137+
138+ if (align & Fw::AlignRight) {
139+ glyphScreenCoords.translate(screenCoords.width() - textBoxSize.width(), 0);
140+ } else if (align & Fw::AlignHorizontalCenter) {
141+ glyphScreenCoords.translate((screenCoords.width() - textBoxSize.width()) / 2, 0);
142+ } else { // AlignLeft
143+ // nothing to do
144+ }
145+
146+ // only render glyphs that are after 0, 0
147+ if (glyphScreenCoords.bottom() < 0 || glyphScreenCoords.right() < 0)
148+ continue;
149+
150+ // bound glyph topLeft to 0,0 if needed
151+ if (glyphScreenCoords.top() < 0) {
152+ glyphTextureCoords.setTop(glyphTextureCoords.top() - glyphScreenCoords.top());
153+ glyphScreenCoords.setTop(0);
154+ }
155+ if (glyphScreenCoords.left() < 0) {
156+ glyphTextureCoords.setLeft(glyphTextureCoords.left() - glyphScreenCoords.left());
157+ glyphScreenCoords.setLeft(0);
158+ }
159+
160+ // translate rect to screen coords
161+ glyphScreenCoords.translate(screenCoords.topLeft());
162+
163+ // only render if glyph rect is visible on screenCoords
164+ if (!screenCoords.intersects(glyphScreenCoords))
165+ continue;
166+
167+ // bound glyph bottomRight to screenCoords bottomRight
168+ if (glyphScreenCoords.bottom() > screenCoords.bottom()) {
169+ glyphTextureCoords.setBottom(glyphTextureCoords.bottom() + (screenCoords.bottom() - glyphScreenCoords.bottom()));
170+ glyphScreenCoords.setBottom(screenCoords.bottom());
171+ }
172+ if (glyphScreenCoords.right() > screenCoords.right()) {
173+ glyphTextureCoords.setRight(glyphTextureCoords.right() + (screenCoords.right() - glyphScreenCoords.right()));
174+ glyphScreenCoords.setRight(screenCoords.right());
175+ }
176+
177+ // render glyph
178+ coordsBuffer.addRect(glyphScreenCoords, glyphTextureCoords);
179+ }
180+}
181+
182+const std::vector<Point>& BitmapFont::calculateGlyphsPositions(const std::string& text,
183+ Fw::AlignmentFlag align,
184+ Size *textBoxSize)
185+{
186+ // for performance reasons we use statics vectors that are allocated on demand
187+ static thread_local std::vector<Point> glyphsPositions(1);
188+ static thread_local std::vector<int> lineWidths(1);
189+
190+ int textLength = text.length();
191+ int maxLineWidth = 0;
192+ int lines = 0;
193+ int glyph;
194+ int i;
195+
196+ // return if there is no text
197+ if(textLength == 0) {
198+ if(textBoxSize)
199+ textBoxSize->resize(0,m_glyphHeight);
200+ return glyphsPositions;
201+ }
202+
203+ // resize glyphsPositions vector when needed
204+ if(textLength > (int)glyphsPositions.size())
205+ glyphsPositions.resize(textLength);
206+
207+ // calculate lines width
208+ if((align & Fw::AlignRight || align & Fw::AlignHorizontalCenter) || textBoxSize) {
209+ lineWidths[0] = 0;
210+ for(i = 0; i< textLength; ++i) {
211+ glyph = (uchar)text[i];
212+
213+ if(glyph == (uchar)'\n') {
214+ lines++;
215+ if(lines+1 > (int)lineWidths.size())
216+ lineWidths.resize(lines+1);
217+ lineWidths[lines] = 0;
218+ } else if(glyph >= 32) {
219+ lineWidths[lines] += m_glyphsSize[glyph].width() ;
220+ if((i+1 != textLength && text[i+1] != '\n')) // only add space if letter is not the last or before a \n.
221+ lineWidths[lines] += m_glyphSpacing.width();
222+ maxLineWidth = std::max<int>(maxLineWidth, lineWidths[lines]);
223+ }
224+ }
225+ }
226+
227+ Point virtualPos(0, m_yOffset);
228+ lines = 0;
229+ for(i = 0; i < textLength; ++i) {
230+ glyph = (uchar)text[i];
231+
232+ // new line or first glyph
233+ if(glyph == (uchar)'\n' || i == 0) {
234+ if(glyph == (uchar)'\n') {
235+ virtualPos.y += m_glyphHeight + m_glyphSpacing.height();
236+ lines++;
237+ }
238+
239+ // calculate start x pos
240+ if(align & Fw::AlignRight) {
241+ virtualPos.x = (maxLineWidth - lineWidths[lines]);
242+ } else if(align & Fw::AlignHorizontalCenter) {
243+ virtualPos.x = (maxLineWidth - lineWidths[lines]) / 2;
244+ } else { // AlignLeft
245+ virtualPos.x = 0;
246+ }
247+ }
248+
249+ // store current glyph topLeft
250+ glyphsPositions[i] = virtualPos;
251+
252+ // render only if the glyph is valid
253+ if(glyph >= 32 && glyph != (uchar)'\n') {
254+ virtualPos.x += m_glyphsSize[glyph].width() + m_glyphSpacing.width();
255+ }
256+ }
257+
258+ if(textBoxSize) {
259+ textBoxSize->setWidth(maxLineWidth);
260+ textBoxSize->setHeight(virtualPos.y + m_glyphHeight);
261+ }
262+
263+ return glyphsPositions;
264+}
265+
266+Size BitmapFont::calculateTextRectSize(const std::string& text)
267+{
268+ Size size;
269+ calculateGlyphsPositions(text, Fw::AlignTopLeft, &size);
270+ return size;
271+}
272+
273+std::string BitmapFont::wrapText(const std::string& text, int maxWidth, std::vector<std::pair<int, Color>>* colors)
274+{
275+ std::string outText;
276+ outText.reserve(text.size() * 2); // string append optimization
277+
278+ int lastSeparator = 0, lastColorSeparator = 0, lineLength = 0, wordLength = 0;
279+ for (size_t i = 0, c = 0; i < text.size(); ++i) {
280+ uchar glyph = (uchar)text[i];
281+ if (text[i] == '\n' || text[i] == ' ') {
282+ lineLength += wordLength;
283+ if (lineLength > maxWidth) { // too long line with this word
284+ if (text[lastSeparator] == ' ') {
285+ c -= 1;
286+ updateColors(colors, lastColorSeparator, -1);
287+ lastSeparator += 1;
288+ lastColorSeparator += 1;
289+ }
290+ outText += '\n';
291+ lineLength = wordLength;
292+ }
293+ for (size_t j = lastSeparator; j < i; ++j) { // copy word
294+ outText += text[j];
295+ }
296+ if (text[i] == '\n') { // if new line was added reset line length
297+ outText += '\n';
298+ wordLength = 0;
299+ lineLength = 0;
300+ lastSeparator = i + 1;
301+ lastColorSeparator = c;
302+ } else { // space
303+ wordLength = m_glyphsSize[glyph].width() + m_glyphSpacing.width(); // space
304+ lastSeparator = i;
305+ lastColorSeparator = c;
306+ c += 1;
307+ }
308+ continue;
309+ }
310+
311+ if (glyph < 32) // invalid character
312+ continue;
313+
314+ wordLength += m_glyphsSize[glyph].width() + m_glyphSpacing.width();
315+ if (wordLength > maxWidth) { // too long word, split it
316+ if (lineLength != 0) { // add new line if current one is not empty
317+ outText += '\n';
318+ }
319+ if (text[lastSeparator] == ' ') { // ignore space if it's first character in new line
320+ c -= 1;
321+ lastSeparator += 1;
322+ lastColorSeparator += 1;
323+ }
324+ for (size_t j = lastSeparator; j < i; ++j) { // copy word
325+ outText += text[j];
326+ }
327+ updateColors(colors, lastColorSeparator, 1);
328+ outText += '-'; // word continuation
329+ outText += '\n'; // new line
330+
331+ wordLength = m_glyphsSize[glyph].width() + m_glyphSpacing.width();
332+ lineLength = 0;
333+ lastSeparator = i;
334+ lastColorSeparator = c;
335+ }
336+ c += 1;
337+ }
338+
339+ lineLength += wordLength;
340+ if (lineLength > maxWidth) { // too long line with this word
341+ updateColors(colors, lastColorSeparator, 1);
342+ outText += '\n';
343+ lineLength = wordLength;
344+ }
345+ for (size_t j = lastSeparator; j < text.size(); ++j) { // copy word
346+ outText += text[j];
347+ }
348+ return outText;
349+}
350+
351+void BitmapFont::calculateGlyphsWidthsAutomatically(const ImagePtr& image, const Size& glyphSize)
352+{
353+ if (!image)
354+ return;
355+
356+ int numHorizontalGlyphs = image->getSize().width() / glyphSize.width();
357+ auto texturePixels = image->getPixels();
358+
359+ // small AI to auto calculate pixels widths
360+ for (int glyph = m_firstGlyph; glyph < 256; ++glyph) {
361+ Rect glyphCoords(((glyph - m_firstGlyph) % numHorizontalGlyphs) * glyphSize.width(),
362+ ((glyph - m_firstGlyph) / numHorizontalGlyphs) * glyphSize.height(),
363+ glyphSize.width(),
364+ m_glyphHeight);
365+ int width = glyphSize.width();
366+ for (int x = glyphCoords.left(); x <= glyphCoords.right(); ++x) {
367+ int filledPixels = 0;
368+ // check if all vertical pixels are alpha
369+ for (int y = glyphCoords.top(); y <= glyphCoords.bottom(); ++y) {
370+ if (texturePixels[(y * image->getSize().width() * 4) + (x * 4) + 3] != 0)
371+ filledPixels++;
372+ }
373+ if (filledPixels > 0)
374+ width = x - glyphCoords.left() + 1;
375+ }
376+ // store glyph size
377+ m_glyphsSize[glyph].resize(width, m_glyphHeight);
378+ }
379+}
380+
381+void BitmapFont::updateColors(std::vector<std::pair<int, Color>>* colors, int pos, int newTextLen)
382+{
383+ if (!colors) return;
384+ for (auto& it : *colors) {
385+ if (it.first > pos) {
386+ it.first += newTextLen;
387+ }
388+ }
389+}
A RD_Client/src/framework/graphics/bitmapfont.h +89-0 View file
@@ -0,0 +1,89 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef BITMAPFONT_H
24+#define BITMAPFONT_H
25+
26+#include "declarations.h"
27+#include "texture.h"
28+
29+#include <framework/otml/declarations.h>
30+#include <framework/graphics/coordsbuffer.h>
31+
32+class BitmapFont : public stdext::shared_object
33+{
34+public:
35+ BitmapFont(const std::string& name) : m_name(name) {
36+ static int id = 1;
37+ m_id = id++;
38+ }
39+
40+ /// Load font from otml node
41+ void load(const OTMLNodePtr& fontNode);
42+
43+ /// Simple text render starting at startPos
44+ void drawText(const std::string& text, const Point& startPos, const Color& color = Color::white, bool shadow = false);
45+
46+ /// Advanced text render delimited by a screen region and alignment
47+ void drawText(const std::string& text, const Rect& screenCoords, Fw::AlignmentFlag align = Fw::AlignTopLeft, const Color& color = Color::white, bool shadow = false);
48+ void drawColoredText(const std::string& text, const Rect& screenCoords, Fw::AlignmentFlag align, const std::vector<std::pair<int, Color>>& colors, bool shadow = false);
49+
50+ void calculateDrawTextCoords(CoordsBuffer& coordsBuffer, const std::string& text, const Rect& screenCoords, Fw::AlignmentFlag align = Fw::AlignTopLeft);
51+
52+ /// Calculate glyphs positions to use on render, also calculates textBoxSize if wanted
53+ const std::vector<Point>& calculateGlyphsPositions(const std::string& text,
54+ Fw::AlignmentFlag align = Fw::AlignTopLeft,
55+ Size* textBoxSize = NULL);
56+
57+ /// Simulate render and calculate text size
58+ Size calculateTextRectSize(const std::string& text);
59+
60+ std::string wrapText(const std::string& text, int maxWidth, std::vector<std::pair<int, Color>>* colors = nullptr);
61+
62+ int getId() { return m_id; }
63+ std::string getName() { return m_name; }
64+ int getGlyphHeight() { return m_glyphHeight; }
65+ const Rect* getGlyphsTextureCoords() { return m_glyphsTextureCoords; }
66+ const Size* getGlyphsSize() { return m_glyphsSize; }
67+ const TexturePtr& getTexture() { return m_texture; }
68+ int getYOffset() { return m_yOffset; }
69+ Size getGlyphSpacing() { return m_glyphSpacing; }
70+
71+private:
72+ /// Calculates each font character by inspecting font bitmap
73+ void calculateGlyphsWidthsAutomatically(const ImagePtr& image, const Size& glyphSize);
74+ void updateColors(std::vector<std::pair<int, Color>>* colors, int pos, int newTextLen);
75+
76+ std::string m_name;
77+ int m_glyphHeight;
78+ int m_firstGlyph;
79+ int m_yOffset;
80+ int m_id;
81+ Size m_glyphSpacing;
82+ TexturePtr m_texture;
83+ Rect m_glyphsTextureCoords[256];
84+ Size m_glyphsSize[256];
85+};
86+
87+
88+#endif
89+
A RD_Client/src/framework/graphics/cachedtext.cpp +81-0 View file
@@ -0,0 +1,81 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#include "cachedtext.h"
24+#include "painter.h"
25+#include "fontmanager.h"
26+#include "bitmapfont.h"
27+
28+CachedText::CachedText()
29+{
30+ m_font = g_fonts.getDefaultFont();
31+ m_align = Fw::AlignCenter;
32+}
33+
34+void CachedText::draw(const Rect& rect, const Color& color)
35+{
36+ if(!m_font)
37+ return;
38+
39+ if(m_textMustRecache || m_textCachedScreenCoords != rect) {
40+ m_textMustRecache = false;
41+ m_textCachedScreenCoords = rect;
42+ }
43+
44+ if (m_textColors.empty()) {
45+ m_font->drawText(m_text, m_textCachedScreenCoords, Fw::AlignCenter, color);
46+ } else {
47+ m_font->drawColoredText(m_text, m_textCachedScreenCoords, Fw::AlignCenter, m_textColors);
48+ }
49+}
50+
51+void CachedText::setColoredText(const std::vector<std::string>& texts)
52+{
53+ m_text = "";
54+ m_textColors.clear();
55+ for (size_t i = 0, p = 0; i < texts.size() - 1; i += 2) {
56+ Color c(Color::white);
57+ stdext::cast<Color>(texts[i + 1], c);
58+ m_text += texts[i];
59+ for (auto& c : texts[i]) {
60+ if ((uint8)c >= 32)
61+ p += 1;
62+ }
63+ m_textColors.push_back(std::make_pair(p, c));
64+ }
65+ update();
66+}
67+
68+void CachedText::update()
69+{
70+ if(m_font)
71+ m_textSize = m_font->calculateTextRectSize(m_text);
72+ m_textMustRecache = true;
73+}
74+
75+void CachedText::wrapText(int maxWidth)
76+{
77+ if(m_font) {
78+ m_text = m_font->wrapText(m_text, maxWidth, m_textColors.empty() ? nullptr : &m_textColors);
79+ update();
80+ }
81+}
A RD_Client/src/framework/graphics/cachedtext.h +62-0 View file
@@ -0,0 +1,62 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef CACHEDTEXT_H
24+#define CACHEDTEXT_H
25+
26+#include "declarations.h"
27+#include "coordsbuffer.h"
28+#include "drawqueue.h"
29+
30+class CachedText
31+{
32+public:
33+ CachedText();
34+
35+ void draw(const Rect& rect, const Color& color);
36+
37+ void wrapText(int maxWidth);
38+ void setFont(const BitmapFontPtr& font) { m_font = font; update(); }
39+ void setText(const std::string& text) { m_textColors.clear(); m_text = text; update(); }
40+ void setColoredText(const std::vector<std::string>& texts);
41+ void setAlign(Fw::AlignmentFlag align) { m_align = align; update(); }
42+
43+ Size getTextSize() { return m_textSize; }
44+ std::string getText() const { return m_text; }
45+ BitmapFontPtr getFont() const { return m_font; }
46+ Fw::AlignmentFlag getAlign() { return m_align; }
47+
48+ bool hasText() { return !m_text.empty(); }
49+
50+private:
51+ void update();
52+
53+ std::string m_text;
54+ std::vector<std::pair<int, Color>> m_textColors;
55+ Size m_textSize;
56+ stdext::boolean<true> m_textMustRecache;
57+ Rect m_textCachedScreenCoords;
58+ BitmapFontPtr m_font;
59+ Fw::AlignmentFlag m_align;
60+};
61+
62+#endif
A RD_Client/src/framework/graphics/colorarray.h +46-0 View file
@@ -0,0 +1,46 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef COLORARRAY_H
24+#define COLORARRAY_H
25+
26+#include "declarations.h"
27+#include <framework/util/databuffer.h>
28+
29+class ColorArray
30+{
31+public:
32+ inline void addColor(float r, float g, float b, float a) { m_buffer << r << g << b << a; }
33+ inline void addColor(const Color& c) { addColor(c.rF(), c.gF(), c.bF(), c.aF()); }
34+
35+ void clear() { m_buffer.reset(); }
36+ float *colors() const { return m_buffer.data(); }
37+ float *data() const { return m_buffer.data(); }
38+ int colorCount() const { return m_buffer.size() / 4; }
39+ int count() const { return m_buffer.size() / 4; }
40+ int size() const { return m_buffer.size(); }
41+
42+private:
43+ DataBuffer<float> m_buffer;
44+};
45+
46+#endif
A RD_Client/src/framework/graphics/coordsbuffer.cpp +115-0 View file
@@ -0,0 +1,115 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#include "coordsbuffer.h"
24+#include "graphics.h"
25+
26+CoordsBuffer::CoordsBuffer()
27+{
28+ m_vertexArray = std::make_shared<VertexArray>();
29+ m_textureCoordArray = std::make_shared<VertexArray>();
30+}
31+
32+CoordsBuffer::~CoordsBuffer()
33+{
34+}
35+
36+void CoordsBuffer::addBoudingRect(const Rect& dest, int innerLineWidth)
37+{
38+ if (m_locked)
39+ unlock();
40+
41+ int left = dest.left();
42+ int right = dest.right();
43+ int top = dest.top();
44+ int bottom = dest.bottom();
45+ int width = dest.width();
46+ int height = dest.height();
47+ int w = innerLineWidth;
48+
49+ addRect(Rect(left, top, width - w, w)); // top
50+ addRect(Rect(right - w + 1, top, w, height - w)); // right
51+ addRect(Rect(left + w, bottom - w + 1, width - w, w)); // bottom
52+ addRect(Rect(left, top + w, w, height - w)); // left
53+}
54+
55+void CoordsBuffer::addRepeatedRects(const Rect& dest, const Rect& src)
56+{
57+ if(dest.isEmpty() || src.isEmpty())
58+ return;
59+ if (m_locked)
60+ unlock();
61+
62+ Rect virtualDest(0, 0, dest.size());
63+ for(int y = 0; y <= virtualDest.height(); y += src.height()) {
64+ for(int x = 0; x <= virtualDest.width(); x += src.width()) {
65+ Rect partialDest(x, y, src.size());
66+ Rect partialSrc(src);
67+
68+ // partialCoords to screenCoords bottomRight
69+ if(partialDest.bottom() > virtualDest.bottom()) {
70+ partialSrc.setBottom(partialSrc.bottom() + (virtualDest.bottom() - partialDest.bottom()));
71+ partialDest.setBottom(virtualDest.bottom());
72+ }
73+ if(partialDest.right() > virtualDest.right()) {
74+ partialSrc.setRight(partialSrc.right() + (virtualDest.right() - partialDest.right()));
75+ partialDest.setRight(virtualDest.right());
76+ }
77+
78+ partialDest.translate(dest.topLeft());
79+ m_vertexArray->addRect(partialDest);
80+ m_textureCoordArray->addRect(partialSrc);
81+ }
82+ }
83+}
84+
85+void CoordsBuffer::unlock(bool clear)
86+{
87+ m_locked = false;
88+ if (clear) {
89+ m_vertexArray = std::make_shared<VertexArray>();
90+ m_textureCoordArray = std::make_shared<VertexArray>();
91+ } else {
92+ m_vertexArray = std::make_shared<VertexArray>(*m_vertexArray);
93+ m_textureCoordArray = std::make_shared<VertexArray>(*m_textureCoordArray);
94+ }
95+}
96+
97+Rect CoordsBuffer::getTextureRect()
98+{
99+ float* vertices = getTextureCoordArray();
100+ int size = getTextureCoordCount() * 2;
101+ float x1 = 0, y1 = 0, x2 = 0, y2 = 0;
102+ for (int i = 0; i < size; i += 2) {
103+ float x = vertices[i];
104+ float y = vertices[i + 1];
105+ if (x < x1)
106+ x1 = x;
107+ else if (x > x2)
108+ x2 = x;
109+ if (y < y1)
110+ y1 = y;
111+ else if (y > y2)
112+ y2 = y;
113+ }
114+ return Rect(Point(x1, y1), Point(x2, y2));
115+}
A RD_Client/src/framework/graphics/coordsbuffer.h +109-0 View file
@@ -0,0 +1,109 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef COORDSBUFFER_H
24+#define COORDSBUFFER_H
25+
26+#include "vertexarray.h"
27+
28+class CoordsBuffer
29+{
30+public:
31+ CoordsBuffer();
32+ ~CoordsBuffer();
33+ CoordsBuffer(CoordsBuffer& c) = delete;
34+ CoordsBuffer& operator=(CoordsBuffer& c) = delete;
35+ CoordsBuffer(CoordsBuffer&& c) noexcept : m_vertexArray(c.m_vertexArray), m_textureCoordArray(c.m_textureCoordArray)
36+ {
37+ m_locked = c.m_locked = true;
38+ };
39+
40+ void clear() {
41+ if (m_locked)
42+ unlock(true);
43+ m_textureCoordArray->clear();
44+ m_vertexArray->clear();
45+ }
46+
47+ void addTriangle(const Point& a, const Point& b, const Point& c) {
48+ if (m_locked)
49+ unlock();
50+ m_vertexArray->addTriangle(a, b, c);
51+ }
52+ void addRect(const Rect& dest) {
53+ if (m_locked)
54+ unlock();
55+ m_vertexArray->addRect(dest);
56+ }
57+ void addRect(const Rect& dest, const Rect& src)
58+ {
59+ if (m_locked)
60+ unlock();
61+ m_vertexArray->addRect(dest);
62+ m_textureCoordArray->addRect(src);
63+ }
64+ void addRect(const RectF& dest, const RectF& src)
65+ {
66+ if (m_locked)
67+ unlock();
68+ m_vertexArray->addRect(dest);
69+ m_textureCoordArray->addRect(src);
70+ }
71+ void addQuad(const Rect& dest, const Rect& src) {
72+ if (m_locked)
73+ unlock();
74+ m_vertexArray->addQuad(dest);
75+ m_textureCoordArray->addQuad(src);
76+ }
77+ void addUpsideDownQuad(const Rect& dest, const Rect& src) {
78+ if (m_locked)
79+ unlock();
80+ m_vertexArray->addUpsideDownQuad(dest);
81+ m_textureCoordArray->addQuad(src);
82+ }
83+
84+ void addBoudingRect(const Rect& dest, int innerLineWidth);
85+ void addRepeatedRects(const Rect& dest, const Rect& src);
86+
87+ float *getVertexArray() { return m_vertexArray->vertices(); }
88+ float *getTextureCoordArray() { return m_textureCoordArray->vertices(); }
89+ int getVertexCount() { return m_vertexArray->vertexCount(); }
90+ int getTextureCoordCount() { return m_textureCoordArray->vertexCount(); }
91+ HardwareBuffer* getVertexHardwareCache() { return m_vertexArray->getHardwareCache(); }
92+ HardwareBuffer* getTextureHardwareCache() { return m_textureCoordArray->getHardwareCache(); }
93+
94+ void unlock(bool clear = false);
95+ void cache()
96+ {
97+ m_locked = true;
98+ m_vertexArray->cache();
99+ m_textureCoordArray->cache();
100+ }
101+ Rect getTextureRect();
102+
103+private:
104+ bool m_locked = false;
105+ std::shared_ptr<VertexArray> m_vertexArray;
106+ std::shared_ptr<VertexArray> m_textureCoordArray;
107+};
108+
109+#endif
A RD_Client/src/framework/graphics/declarations.h +52-0 View file
@@ -0,0 +1,52 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef FRAMEWORK_GRAPHICS_DECLARATIONS_H
24+#define FRAMEWORK_GRAPHICS_DECLARATIONS_H
25+
26+#include <framework/global.h>
27+#include "glutil.h"
28+
29+class Texture;
30+class TextureManager;
31+class Image;
32+class AnimatedTexture;
33+class BitmapFont;
34+class CachedText;
35+class FrameBuffer;
36+class FrameBufferManager;
37+class Shader;
38+class ShaderProgram;
39+class PainterShaderProgram;
40+
41+typedef stdext::shared_object_ptr<Image> ImagePtr;
42+typedef stdext::shared_object_ptr<Texture> TexturePtr;
43+typedef stdext::shared_object_ptr<AnimatedTexture> AnimatedTexturePtr;
44+typedef stdext::shared_object_ptr<BitmapFont> BitmapFontPtr;
45+typedef stdext::shared_object_ptr<CachedText> CachedTextPtr;
46+typedef stdext::shared_object_ptr<FrameBuffer> FrameBufferPtr;
47+typedef stdext::shared_object_ptr<Shader> ShaderPtr;
48+typedef stdext::shared_object_ptr<ShaderProgram> ShaderProgramPtr;
49+typedef stdext::shared_object_ptr<PainterShaderProgram> PainterShaderProgramPtr;
50+typedef std::vector<ShaderPtr> ShaderList;
51+
52+#endif
A RD_Client/src/framework/graphics/deptharray.h +45-0 View file
@@ -0,0 +1,45 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef DEPTHARRAY_H
24+#define DEPTHARRAY_H
25+
26+#include "declarations.h"
27+#include <framework/util/databuffer.h>
28+
29+class DepthArray
30+{
31+public:
32+ inline void addDepth(float depth) { m_buffer << depth; }
33+
34+ void clear() { m_buffer.reset(); }
35+ float *depths() const { return m_buffer.data(); }
36+ float *data() const { return m_buffer.data(); }
37+ int depthCount() const { return m_buffer.size(); }
38+ int count() const { return m_buffer.size(); }
39+ int size() const { return m_buffer.size(); }
40+
41+private:
42+ DataBuffer<float> m_buffer;
43+};
44+
45+#endif
A RD_Client/src/framework/graphics/drawcache.cpp +65-0 View file
@@ -0,0 +1,65 @@
1+#include "drawcache.h"
2+
3+DrawCache g_drawCache;
4+
5+void DrawCache::draw()
6+{
7+ release();
8+ if (m_size == 0) return;
9+ g_painter->drawCache(m_destCoord, m_srcCoord, m_color, m_size);
10+ m_size = 0;
11+}
12+
13+void DrawCache::bind()
14+{
15+ if (m_bound) return;
16+ g_atlas.bind();
17+ m_bound = true;
18+}
19+
20+void DrawCache::release()
21+{
22+ if (!m_bound) return;
23+ g_atlas.release();
24+ m_bound = false;
25+}
26+
27+void DrawCache::addRect(const Rect& dest, const Color& color)
28+{
29+ static Rect emptyRect(Point(-10, -10), Point(-10, -10));
30+ addRectRaw(m_destCoord.data() + (m_size * 2), dest);
31+ addRectRaw(m_srcCoord.data() + (m_size * 2), emptyRect);
32+ addColorRaw(color, 6);
33+ m_size += 6;
34+}
35+
36+void DrawCache::addTexturedRect(const Rect& dest, const Rect& src, const Color& color)
37+{
38+ addRectRaw(m_destCoord.data() + (m_size * 2), dest);
39+ addRectRaw(m_srcCoord.data() + (m_size * 2), src);
40+ addColorRaw(color, 6);
41+ m_size += 6;
42+}
43+
44+void DrawCache::addCoords(CoordsBuffer& coords, const Color& color)
45+{
46+ int size = coords.getVertexCount();
47+ memcpy(m_destCoord.data() + m_size * 2, coords.getVertexArray(), size * 2 * sizeof(float));
48+ for (int start = m_size * 2, end = (m_size + size) * 2; start < end; ++start)
49+ m_srcCoord[start] = -10;
50+ addColorRaw(color, size);
51+ m_size += size;
52+}
53+
54+void DrawCache::addTexturedCoords(CoordsBuffer& coords, const Point& offset, const Color& color)
55+{
56+ int size = coords.getVertexCount();
57+ float* src = coords.getTextureCoordArray();
58+ memcpy(m_destCoord.data() + m_size * 2, coords.getVertexArray(), size * 2 * sizeof(float));
59+ for (int i = m_size * 2, j = 0, end = (m_size + size) * 2; i < end; ) {
60+ m_srcCoord[i++] = src[j++] + offset.x;
61+ m_srcCoord[i++] = src[j++] + offset.y;
62+ }
63+ addColorRaw(color, size);
64+ m_size += size;
65+}
A RD_Client/src/framework/graphics/drawcache.h +55-0 View file
@@ -0,0 +1,55 @@
1+#ifndef DRAW_CACHE
2+#define DRAW_CACHE
3+
4+#include "atlas.h"
5+#include "coordsbuffer.h"
6+#include "graphics.h"
7+#include "painter.h"
8+
9+class DrawCache {
10+public:
11+ static const int MAX_SIZE = 65536;
12+ static const int HALF_MAX_SIZE = MAX_SIZE / 2;
13+
14+ void draw();
15+ void bind();
16+ void release();
17+ bool hasSpace(int size) {
18+ return size + m_size < MAX_SIZE;
19+ }
20+ inline int getSize() { return m_size; }
21+ void addRect(const Rect& dest, const Color& color);
22+ void addTexturedRect(const Rect& dest, const Rect& src, const Color& color);
23+ void addCoords(CoordsBuffer& coords, const Color& color);
24+ void addTexturedCoords(CoordsBuffer& coords, const Point& offset, const Color& color);
25+
26+private:
27+ inline void addRectRaw(float* dest, const Rect& rect)
28+ {
29+ dest[0] = dest[4] = dest[6] = rect.left();
30+ dest[1] = dest[3] = dest[9] = rect.top();
31+ dest[2] = dest[8] = dest[10] = rect.right() + 1;
32+ dest[5] = dest[7] = dest[11] = rect.bottom() + 1;
33+ }
34+ inline void addColorRaw(const Color& color, int count)
35+ {
36+ static float c[4];
37+ c[0] = color.rF();
38+ c[1] = color.gF();
39+ c[2] = color.bF();
40+ c[3] = color.aF();
41+ for (int start = m_size * 4, end = (m_size + count) * 4; start < end; start += 4) {
42+ memcpy(m_color.data() + start, c, 4 * sizeof(float));
43+ }
44+ }
45+
46+ std::vector<float> m_destCoord = std::vector<float>(MAX_SIZE * 2);
47+ std::vector<float> m_srcCoord = std::vector<float>(MAX_SIZE * 2);
48+ std::vector<float> m_color = std::vector<float>(MAX_SIZE * 4);
49+ bool m_bound = false;
50+ int m_size = 0;
51+};
52+
53+extern DrawCache g_drawCache;
54+
55+#endif
A RD_Client/src/framework/graphics/drawqueue.cpp +374-0 View file
@@ -0,0 +1,374 @@
1+#include <client/outfit.h>
2+#include <client/spritemanager.h>
3+#include <framework/graphics/atlas.h>
4+#include <framework/graphics/drawcache.h>
5+#include <framework/graphics/drawqueue.h>
6+#include <framework/graphics/framebuffermanager.h>
7+#include <framework/graphics/graphics.h>
8+#include <framework/graphics/image.h>
9+#include <framework/graphics/painter.h>
10+#include <framework/graphics/shadermanager.h>
11+#include <framework/graphics/textrender.h>
12+#include <stack>
13+
14+std::shared_ptr<DrawQueue> g_drawQueue;
15+
16+void DrawQueueItemTextureCoords::draw() {
17+ g_painter->setColor(m_color);
18+ g_painter->drawTextureCoords(m_coordsBuffer, m_texture);
19+}
20+
21+bool DrawQueueItemTextureCoords::cache() {
22+ if (!m_texture->canCache())
23+ return false;
24+ m_texture->update();
25+
26+ uint64_t hash = 100 + m_texture->getUniqueId();
27+ bool drawNow = false;
28+ Point atlasPos = g_atlas.cache(hash, m_texture->getSize(), drawNow);
29+ if (atlasPos.x < 0) {
30+ return false;
31+ } // can't be cached
32+ if (drawNow) {
33+ g_drawCache.bind();
34+ draw(atlasPos);
35+ }
36+
37+ int size = m_coordsBuffer.getVertexCount();
38+ if (!g_drawCache.hasSpace(size))
39+ return false;
40+
41+ g_drawCache.addTexturedCoords(m_coordsBuffer, atlasPos, m_color);
42+ return true;
43+}
44+
45+void DrawQueueItemTextureCoords::draw(const Point &pos) {
46+ g_painter->resetColor();
47+ g_painter->drawTexturedRect(Rect(pos, m_texture->getSize()), m_texture);
48+}
49+
50+void DrawQueueItemColoredTextureCoords::draw() {
51+ g_painter->drawTextureCoords(m_coordsBuffer, m_texture, &m_colors);
52+}
53+
54+void DrawQueueItemImageWithShader::draw() {
55+ if (!m_texture)
56+ return;
57+ PainterShaderProgramPtr shader = g_shaders.getShader(m_shader);
58+ if (!shader)
59+ return;
60+
61+ g_painter->setShaderProgram(shader);
62+ shader->bindMultiTextures();
63+ g_painter->setColor(m_color);
64+ g_painter->drawTextureCoords(m_coordsBuffer, m_texture);
65+ g_painter->resetShaderProgram();
66+}
67+
68+void DrawQueueItemImageWithShader::draw(const Point &pos) {
69+ if (!m_texture)
70+ return;
71+ PainterShaderProgramPtr shader = g_shaders.getShader(m_shader);
72+ if (!shader)
73+ return;
74+
75+ g_painter->setShaderProgram(shader);
76+ shader->bindMultiTextures();
77+ g_painter->resetColor();
78+ g_painter->drawTexturedRect(Rect(pos, m_texture->getSize()), m_texture);
79+ g_painter->resetShaderProgram();
80+}
81+
82+void DrawQueueItemTexturedRect::draw() {
83+ g_painter->setColor(m_color);
84+ g_painter->drawTexturedRect(m_dest, m_texture, m_src);
85+}
86+
87+bool DrawQueueItemTexturedRect::cache() {
88+ if (m_dest.size() > m_src.size()) // upscaling may create artifacts
89+ return false;
90+ if (!m_texture->canCache())
91+ return false;
92+
93+ m_texture->update();
94+ uint64_t hash = 100 + m_texture->getUniqueId();
95+ bool drawNow = false;
96+ Point atlasPos = g_atlas.cache(hash, m_texture->getSize(), drawNow);
97+ if (atlasPos.x < 0) {
98+ return false;
99+ } // can't be cached
100+ if (drawNow) {
101+ g_drawCache.bind();
102+ draw(atlasPos);
103+ }
104+
105+ if (!g_drawCache.hasSpace(6))
106+ return false;
107+
108+ g_drawCache.addTexturedRect(m_dest, m_src + atlasPos, m_color);
109+ return true;
110+}
111+
112+void DrawQueueItemTexturedRect::draw(const Point &pos) {
113+ g_painter->resetColor();
114+ g_painter->drawTexturedRect(Rect(pos, m_texture->getSize()), m_texture);
115+}
116+
117+bool DrawQueueItemFilledRect::cache() {
118+ if (!g_drawCache.hasSpace(6))
119+ return false;
120+ g_drawCache.addRect(m_dest, m_color);
121+ return true;
122+}
123+
124+void DrawQueueItemClearRect::draw() { g_painter->clearRect(m_color, m_dest); }
125+
126+bool DrawQueueItemFillCoords::cache() {
127+ int size = m_coordsBuffer.getVertexCount();
128+ if (!g_drawCache.hasSpace(size))
129+ return false;
130+
131+ g_drawCache.addCoords(m_coordsBuffer, m_color);
132+ return true;
133+}
134+
135+void DrawQueueItemText::draw() {
136+ g_text.drawText(m_point, m_hash, m_color, m_shadow);
137+}
138+
139+void DrawQueueItemTextColored::draw() {
140+ g_text.drawColoredText(m_point, m_hash, m_colors, m_shadow);
141+}
142+
143+void ::DrawQueueItemLine::draw() {
144+ g_painter->setColor(m_color);
145+ static std::vector<float> vertices(1024, 0);
146+ if (vertices.size() < m_points.size())
147+ vertices.resize(m_points.size());
148+ int i = 0;
149+ for (Point &point : m_points) {
150+ vertices[i++] = point.x;
151+ vertices[i++] = point.y;
152+ }
153+ g_painter->drawLine(vertices, i / 2, m_width);
154+}
155+
156+void DrawQueueConditionClip::start(DrawQueue *) {
157+ m_prevClip = g_painter->getClipRect();
158+ g_painter->setClipRect(m_rect);
159+}
160+
161+void DrawQueueConditionClip::end(DrawQueue *) {
162+ g_painter->setClipRect(m_prevClip);
163+}
164+
165+void DrawQueueConditionRotation::start(DrawQueue *) {
166+ g_painter->pushTransformMatrix();
167+ g_painter->rotate(m_center, m_angle);
168+}
169+
170+void DrawQueueConditionRotation::end(DrawQueue *) {
171+ g_painter->popTransformMatrix();
172+}
173+
174+void DrawQueueConditionMark::start(DrawQueue *) {
175+ // nothing
176+}
177+
178+void DrawQueueConditionMark::end(DrawQueue *queue) {
179+ g_painter->setDrawColorOnTextureShaderProgram();
180+ g_painter->setColor(m_color);
181+ for (size_t i = m_start; i < m_end; ++i) {
182+ DrawQueueItemTexturedRect *texture =
183+ dynamic_cast<DrawQueueItemTexturedRect *>(queue->m_queue[i]);
184+ if (texture)
185+ g_painter->drawTexturedRect(texture->m_dest, texture->m_texture,
186+ texture->m_src);
187+ }
188+ g_painter->resetShaderProgram();
189+}
190+
191+void DrawQueue::setFrameBuffer(const Rect &dest, const Size &size,
192+ const Rect &src) {
193+ m_useFrameBuffer = true;
194+ m_frameBufferSize = size;
195+ m_frameBufferDest = dest;
196+ m_frameBufferSrc = src;
197+ size_t max_size =
198+ std::max(m_frameBufferSize.width(), m_frameBufferSize.height());
199+ while (max_size > 2048u) {
200+ max_size /= 2;
201+ m_scaling /= 2.f;
202+ }
203+ if (m_scaling < 0.99f) {
204+ m_frameBufferSize = Size(2048, 2048);
205+ m_frameBufferSrc = m_frameBufferSrc * m_scaling;
206+ }
207+}
208+
209+void DrawQueue::addText(BitmapFontPtr font, const std::string &text,
210+ const Rect &screenCoords, Fw::AlignmentFlag align,
211+ const Color &color, bool shadow) {
212+ if (!font || text.empty())
213+ return;
214+ uint64_t hash = g_text.addText(font, text, screenCoords.size(), align);
215+ m_queue.push_back(new DrawQueueItemText(
216+ screenCoords.topLeft(), font->getTexture(), hash, color, shadow));
217+}
218+
219+void DrawQueue::addColoredText(BitmapFontPtr font, const std::string &text,
220+ const Rect &screenCoords,
221+ Fw::AlignmentFlag align,
222+ const std::vector<std::pair<int, Color>> &colors,
223+ bool shadow) {
224+ if (!font || text.empty())
225+ return;
226+ uint64_t hash = g_text.addText(font, text, screenCoords.size(), align);
227+ m_queue.push_back(new DrawQueueItemTextColored(
228+ screenCoords.topLeft(), font->getTexture(), hash, colors, shadow));
229+}
230+
231+void DrawQueue::correctOutfit(const Rect &dest, int fromPos, bool oldScaling) {
232+ std::vector<Rect *> rects;
233+ if (!oldScaling) {
234+ bool center = false;
235+ int centerX = 0;
236+ int centerY = 0;
237+ for (size_t i = fromPos; i < m_queue.size(); ++i) {
238+ if (DrawQueueItemOutfit *texture =
239+ dynamic_cast<DrawQueueItemOutfit *>(m_queue[i])) {
240+ rects.push_back(&texture->m_dest);
241+ if (!center) {
242+ center = texture->m_doCenter;
243+ }
244+
245+ if (texture->m_doCenter) {
246+ centerX = std::max<int>(centerX, texture->m_dest.center().x);
247+ centerY = std::max<int>(centerY, texture->m_dest.center().y);
248+ }
249+ } else if (DrawQueueItemOutfitWithShader *texture =
250+ dynamic_cast<DrawQueueItemOutfitWithShader *>(
251+ m_queue[i])) {
252+ rects.push_back(&texture->m_dest);
253+ if (!center) {
254+ center = texture->m_doCenter;
255+ }
256+
257+ if (texture->m_doCenter) {
258+ centerX = std::max<int>(centerX, texture->m_dest.center().x);
259+ }
260+ } else if (DrawQueueItemTexturedRect *texture =
261+ dynamic_cast<DrawQueueItemTexturedRect *>(m_queue[i])) {
262+ rects.push_back(&texture->m_dest);
263+ }
264+ }
265+
266+ int x1 = -g_sprites.spriteSize(), y1 = -g_sprites.spriteSize(),
267+ x2 = g_sprites.spriteSize(), y2 = g_sprites.spriteSize();
268+ float scale = std::min<float>((float)dest.height() / (y2 - y1),
269+ (float)dest.width() / (x2 - x1));
270+ for (auto &rect : rects) {
271+ int x = rect->left() - x1 - centerX,
272+ y = rect->top() - y1 - centerY; // offset
273+ *rect = Rect(dest.left() + x * scale, dest.top() + y * scale,
274+ rect->size() * scale);
275+ }
276+ } else {
277+ for (size_t i = fromPos; i < m_queue.size(); ++i) {
278+ if (DrawQueueItemTexturedRect *texture =
279+ dynamic_cast<DrawQueueItemTexturedRect *>(m_queue[i]))
280+ rects.push_back(&texture->m_dest);
281+ }
282+
283+ int x1 = 0, y1 = 1, x2 = 0, y2 = 0;
284+ for (auto &rect : rects) {
285+ x1 = std::min<int>(x1, rect->left());
286+ y1 = std::min<int>(y1, rect->top());
287+ x2 = std::max<int>(x2, rect->right());
288+ y2 = std::max<int>(y2, rect->bottom());
289+ }
290+ if (x1 == x2 || y1 == y2)
291+ return;
292+
293+ float scale = std::min<float>((float)dest.height() / (y2 - y1),
294+ (float)dest.width() / (x2 - x1));
295+ for (auto &rect : rects) {
296+ int x = rect->left() - x1, y = rect->top() - y1; // offset
297+ *rect = Rect(dest.left() + x * scale, dest.top() + y * scale,
298+ rect->size() * scale);
299+ }
300+ }
301+}
302+
303+void DrawQueue::draw(DrawType drawType) {
304+ size_t start = 0;
305+ size_t end = m_queue.size();
306+ if (drawType == DRAW_BEFORE_MAP) {
307+ end = mapPosition;
308+ } else if (drawType == DRAW_AFTER_MAP) {
309+ start = mapPosition;
310+ }
311+
312+ std::sort(
313+ m_conditions.begin(), m_conditions.end(),
314+ [](const DrawQueueCondition *a, const DrawQueueCondition *b) -> bool {
315+ return a->m_start == b->m_start ? a->m_end < b->m_end
316+ : a->m_start < b->m_start;
317+ });
318+
319+ Size originalResolution = g_painter->getResolution();
320+ if (m_scaling > 0.f && m_scaling < 0.99f) {
321+ Size resolution = originalResolution * (1.f / m_scaling);
322+ Matrix3 projectionMatrix = {2.0f / resolution.width(),
323+ 0.0f,
324+ 0.0f,
325+ 0.0f,
326+ -2.0f / resolution.height(),
327+ 0.0f,
328+ -1.0f,
329+ 1.0f,
330+ 1.0f};
331+ g_painter->setProjectionMatrix(projectionMatrix);
332+ }
333+
334+ auto condition = m_conditions.begin();
335+ std::stack<DrawQueueCondition *> activeConditions;
336+ // skip conditions
337+ while (condition != m_conditions.end() && (*condition)->m_end <= start)
338+ ++condition;
339+ // execute conditions & draw
340+ for (size_t i = start; i < end; ++i) {
341+ while (!activeConditions.empty() && activeConditions.top()->m_end <= i) {
342+ g_drawCache.draw();
343+ activeConditions.top()->end(this);
344+ activeConditions.pop();
345+ }
346+ while (condition != m_conditions.end() && (*condition)->m_start <= i) {
347+ g_drawCache.draw();
348+ (*condition)->start(this);
349+ activeConditions.push(*condition);
350+ ++condition;
351+ }
352+
353+ if (!m_queue[i]->cache()) {
354+ g_drawCache.draw();
355+ if (!m_queue[i]->cache()) { // try to cache again, now g_drawCache should
356+ // be empty, maybe there's new space
357+ m_queue[i]->draw();
358+ }
359+ }
360+ if (g_drawCache.getSize() >= g_drawCache.HALF_MAX_SIZE) {
361+ g_drawCache.draw();
362+ }
363+ }
364+ g_drawCache.draw();
365+ // end all actibe conditions
366+ while (!activeConditions.empty()) {
367+ activeConditions.top()->end(this);
368+ activeConditions.pop();
369+ }
370+
371+ g_painter->setResolution(originalResolution);
372+ g_painter->resetState();
373+ g_graphics.checkForError(__FUNCTION__, __FILE__, __LINE__);
374+}
A RD_Client/src/framework/graphics/drawqueue.h +334-0 View file
@@ -0,0 +1,334 @@
1+#ifndef DRAWQUEUE_H
2+#define DRAWQUEUE_H
3+
4+#include <framework/graphics/colorarray.h>
5+#include <framework/graphics/coordsbuffer.h>
6+#include <framework/graphics/declarations.h>
7+#include <framework/graphics/deptharray.h>
8+#include <framework/graphics/paintershaderprogram.h>
9+#include <framework/graphics/texture.h>
10+#include <framework/ui/uiwidget.h>
11+#include <vector>
12+
13+class DrawQueue;
14+struct DrawQueueItem;
15+
16+enum DrawType : uint8_t {
17+ DRAW_ALL = 0,
18+ DRAW_BEFORE_MAP = 1,
19+ DRAW_AFTER_MAP = 2
20+};
21+
22+struct DrawQueueItem {
23+ DrawQueueItem(const TexturePtr &texture, const Color &color = Color::white)
24+ : m_texture(texture), m_color(color) {}
25+ virtual ~DrawQueueItem() = default;
26+ virtual void draw() {}
27+ virtual void draw(const Point &pos) {}
28+ virtual bool cache() { return false; }
29+
30+ TexturePtr m_texture;
31+ Color m_color;
32+};
33+
34+struct DrawQueueItemTexturedRect : public DrawQueueItem {
35+ DrawQueueItemTexturedRect() : DrawQueueItem(nullptr) {}
36+ DrawQueueItemTexturedRect(const Rect &dest, const TexturePtr &texture,
37+ const Rect &src, const Color &color)
38+ : DrawQueueItem(texture, color), m_dest(dest), m_src(src) {};
39+ virtual ~DrawQueueItemTexturedRect() = default;
40+
41+ virtual void draw();
42+ virtual void draw(const Point &pos);
43+ virtual bool cache();
44+
45+ Rect m_dest;
46+ Rect m_src;
47+};
48+
49+struct DrawQueueItemTextureCoords : public DrawQueueItem {
50+ DrawQueueItemTextureCoords(CoordsBuffer &coordsBuffer,
51+ const TexturePtr &texture, const Color &color)
52+ : DrawQueueItem(texture, color),
53+ m_coordsBuffer(std::move(coordsBuffer)) {};
54+
55+ void draw();
56+ void draw(const Point &pos);
57+ bool cache();
58+
59+ CoordsBuffer m_coordsBuffer;
60+};
61+
62+struct DrawQueueItemColoredTextureCoords : public DrawQueueItem {
63+ DrawQueueItemColoredTextureCoords(
64+ CoordsBuffer &coordsBuffer, const TexturePtr &texture,
65+ const std::vector<std::pair<int, Color>> &colors)
66+ : DrawQueueItem(texture), m_coordsBuffer(std::move(coordsBuffer)),
67+ m_colors(colors) {};
68+
69+ void draw();
70+
71+ CoordsBuffer m_coordsBuffer;
72+ std::vector<std::pair<int, Color>> m_colors;
73+};
74+
75+struct DrawQueueItemImageWithShader : public DrawQueueItemTextureCoords {
76+ DrawQueueItemImageWithShader(CoordsBuffer &coords, const TexturePtr &texture,
77+ const Color &color, const std::string &shader)
78+ : DrawQueueItemTextureCoords(coords, texture, color), m_shader(shader) {};
79+
80+ void draw() override;
81+ void draw(const Point &pos) override;
82+ bool cache() override { return false; }
83+
84+ std::string m_shader;
85+};
86+
87+struct DrawQueueItemFilledRect : public DrawQueueItem {
88+ DrawQueueItemFilledRect(const Rect &rect, const Color &color)
89+ : DrawQueueItem(nullptr, color), m_dest(rect) {};
90+ bool cache();
91+
92+ Rect m_dest;
93+};
94+
95+struct DrawQueueItemClearRect : public DrawQueueItem {
96+ DrawQueueItemClearRect(const Rect &rect, const Color &color)
97+ : DrawQueueItem(nullptr, color), m_dest(rect) {};
98+ void draw();
99+
100+ Rect m_dest;
101+};
102+
103+struct DrawQueueItemFillCoords : public DrawQueueItem {
104+ DrawQueueItemFillCoords(CoordsBuffer &coordsBuffer, const Color &color)
105+ : DrawQueueItem(nullptr, color),
106+ m_coordsBuffer(std::move(coordsBuffer)) {};
107+ bool cache();
108+
109+ CoordsBuffer m_coordsBuffer;
110+};
111+
112+struct DrawQueueItemText : public DrawQueueItem {
113+ DrawQueueItemText(const Point &point, const TexturePtr &texture,
114+ uint64_t hash, const Color &color, bool shadow = false)
115+ : DrawQueueItem(texture, color), m_point(point), m_hash(hash),
116+ m_shadow(shadow) {};
117+ void draw();
118+
119+ Point m_point;
120+ uint64_t m_hash;
121+ bool m_shadow = false;
122+};
123+
124+struct DrawQueueItemTextColored : public DrawQueueItem {
125+ DrawQueueItemTextColored(const Point &point, const TexturePtr &texture,
126+ uint64_t hash,
127+ const std::vector<std::pair<int, Color>> &colors,
128+ bool shadow = false)
129+ : DrawQueueItem(texture), m_point(point), m_hash(hash), m_colors(colors),
130+ m_shadow(shadow) {};
131+ void draw();
132+
133+ Point m_point;
134+ uint64_t m_hash;
135+ std::vector<std::pair<int, Color>> m_colors;
136+ bool m_shadow = false;
137+};
138+
139+struct DrawQueueItemLine : public DrawQueueItem {
140+ DrawQueueItemLine(const std::vector<Point> &points, int width,
141+ const Color &color)
142+ : DrawQueueItem(nullptr, color), m_points(points), m_width(width) {};
143+ void draw();
144+
145+ std::vector<Point> m_points;
146+ int m_width;
147+};
148+
149+struct DrawQueueCondition {
150+ DrawQueueCondition(size_t start, size_t end) : m_start(start), m_end(end) {}
151+ virtual ~DrawQueueCondition() = default;
152+
153+ virtual void start(DrawQueue *) = 0;
154+ virtual void end(DrawQueue *) = 0;
155+
156+ size_t m_start;
157+ size_t m_end;
158+};
159+
160+struct DrawQueueConditionClip : public DrawQueueCondition {
161+ DrawQueueConditionClip(size_t start, size_t end, const Rect &rect)
162+ : DrawQueueCondition(start, end), m_rect(rect) {}
163+
164+ void start(DrawQueue *queue) override;
165+ void end(DrawQueue *queue) override;
166+
167+ Rect m_rect;
168+ Rect m_prevClip;
169+};
170+
171+struct DrawQueueConditionRotation : public DrawQueueCondition {
172+ DrawQueueConditionRotation(size_t start, size_t end, const Point &center,
173+ float angle)
174+ : DrawQueueCondition(start, end), m_center(center), m_angle(angle) {}
175+
176+ void start(DrawQueue *queue) override;
177+ void end(DrawQueue *queue) override;
178+
179+ Point m_center;
180+ float m_angle;
181+};
182+
183+struct DrawQueueConditionMark : public DrawQueueCondition {
184+ DrawQueueConditionMark(size_t start, size_t end, const Color &color)
185+ : DrawQueueCondition(start, end), m_color(color) {}
186+
187+ void start(DrawQueue *queue) override;
188+ void end(DrawQueue *queue) override;
189+
190+ Color m_color;
191+};
192+
193+class DrawQueue {
194+public:
195+ DrawQueue() = default;
196+ DrawQueue(const DrawQueue &) = delete;
197+ DrawQueue &operator=(const DrawQueue &) = delete;
198+ ~DrawQueue() {
199+ for (auto &item : m_queue)
200+ delete item;
201+ m_queue.clear();
202+ for (auto &condition : m_conditions)
203+ delete condition;
204+ m_conditions.clear();
205+ }
206+
207+ void draw(DrawType drawType = DRAW_ALL);
208+
209+ void add(DrawQueueItem *item) {
210+ if (!item)
211+ return;
212+ m_queue.push_back(item);
213+ }
214+ DrawQueueItemTexturedRect *
215+ addTexturedRect(const Rect &dest, const TexturePtr &texture, const Rect &src,
216+ const Color &color = Color::white) {
217+ DrawQueueItemTexturedRect *item(
218+ new DrawQueueItemTexturedRect(dest, texture, src, color));
219+ m_queue.push_back(item);
220+ return item;
221+ }
222+ void addTextureCoords(CoordsBuffer &coords, const TexturePtr &texture,
223+ const Color &color = Color::white) {
224+ m_queue.push_back(new DrawQueueItemTextureCoords(coords, texture, color));
225+ }
226+ void
227+ addColoredTextureCoords(CoordsBuffer &coords, const TexturePtr &texture,
228+ const std::vector<std::pair<int, Color>> &colors) {
229+ m_queue.push_back(
230+ new DrawQueueItemColoredTextureCoords(coords, texture, colors));
231+ }
232+ void addFilledRect(const Rect &dest, const Color &color = Color::white) {
233+ m_queue.push_back(new DrawQueueItemFilledRect(dest, color));
234+ }
235+ void addFillCoords(CoordsBuffer &coords, const Color &color = Color::white) {
236+ m_queue.push_back(new DrawQueueItemFillCoords(coords, color));
237+ }
238+ void addClearRect(const Rect &dest, const Color &color = Color::white) {
239+ m_queue.push_back(new DrawQueueItemClearRect(dest, color));
240+ }
241+ void addText(BitmapFontPtr font, const std::string &text,
242+ const Rect &screenCoords,
243+ Fw::AlignmentFlag align = Fw::AlignTopLeft,
244+ const Color &color = Color::white, bool shadow = false);
245+ void addColoredText(BitmapFontPtr font, const std::string &text,
246+ const Rect &screenCoords, Fw::AlignmentFlag align,
247+ const std::vector<std::pair<int, Color>> &colors,
248+ bool shadow = false);
249+
250+ void addFilledTriangle(const Point &a, const Point &b, const Point &c,
251+ const Color &color = Color::white) {
252+ if (a == b || a == c || b == c)
253+ return;
254+
255+ CoordsBuffer coordsBuffer;
256+ coordsBuffer.addTriangle(a, b, c);
257+ addFillCoords(coordsBuffer, color);
258+ }
259+ void addBoundingRect(const Rect &dest, int innerLineWidth,
260+ const Color &color = Color::white) {
261+ if (dest.isEmpty() || innerLineWidth == 0)
262+ return;
263+
264+ CoordsBuffer coordsBuffer;
265+ coordsBuffer.addBoudingRect(dest, innerLineWidth);
266+ addFillCoords(coordsBuffer, color);
267+ }
268+
269+ void addLine(const std::vector<Point> &points, int width,
270+ const Color &color = Color::white) {
271+ if (points.empty() || width < 0)
272+ return;
273+
274+ m_queue.push_back(new DrawQueueItemLine(points, width, color));
275+ }
276+
277+ void setFrameBuffer(const Rect &dest, const Size &size, const Rect &src);
278+ bool hasFrameBuffer() { return m_useFrameBuffer; }
279+ Rect getFrameBufferDest() { return m_frameBufferDest; }
280+ Size getFrameBufferSize() { return m_frameBufferSize; }
281+ Rect getFrameBufferSrc() { return m_frameBufferSrc; }
282+
283+ size_t size() { return m_queue.size(); }
284+
285+ void setOpacity(size_t start, float opacity) {
286+ for (size_t i = start; i < m_queue.size(); ++i) {
287+ m_queue[i]->m_color = m_queue[i]->m_color.opacity(opacity);
288+ }
289+ }
290+
291+ void setClip(size_t start, const Rect &clip) {
292+ if (start == m_queue.size())
293+ return;
294+ m_conditions.push_back(
295+ new DrawQueueConditionClip(start, m_queue.size(), clip));
296+ }
297+
298+ void setRotation(size_t start, const Point &center, float angle) {
299+ if (start == m_queue.size() || angle == 0)
300+ return;
301+ m_conditions.push_back(
302+ new DrawQueueConditionRotation(start, m_queue.size(), center, angle));
303+ }
304+
305+ void setMark(size_t start, const Color &color) {
306+ if (start == m_queue.size())
307+ return;
308+ m_conditions.push_back(
309+ new DrawQueueConditionMark(start, m_queue.size(), color));
310+ }
311+
312+ void markMapPosition() { mapPosition = m_queue.size(); }
313+ void correctOutfit(const Rect &dest, int fromPos, bool oldScaling);
314+
315+ void setShader(const std::string &shader) { m_shader = shader; }
316+
317+ std::string getShader() { return m_shader; }
318+
319+private:
320+ std::vector<DrawQueueItem *> m_queue;
321+ std::vector<DrawQueueCondition *> m_conditions;
322+ Size m_frameBufferSize;
323+ Rect m_frameBufferDest, m_frameBufferSrc;
324+ size_t mapPosition = 0;
325+ bool m_useFrameBuffer = false;
326+ float m_scaling = 1.f;
327+ std::string m_shader;
328+
329+ friend struct DrawQueueConditionMark;
330+};
331+
332+extern std::shared_ptr<DrawQueue> g_drawQueue;
333+
334+#endif
A RD_Client/src/framework/graphics/fontmanager.cpp +107-0 View file
@@ -0,0 +1,107 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#include "atlas.h"
24+#include "fontmanager.h"
25+#include "texture.h"
26+
27+#include <framework/core/eventdispatcher.h>
28+#include <framework/core/resourcemanager.h>
29+#include <framework/otml/otml.h>
30+
31+FontManager g_fonts;
32+
33+FontManager::FontManager()
34+{
35+ m_defaultFont = BitmapFontPtr(new BitmapFont("emptyfont"));
36+}
37+
38+void FontManager::terminate()
39+{
40+ m_fonts.clear();
41+ m_defaultFont = nullptr;
42+}
43+
44+void FontManager::clearFonts()
45+{
46+ m_fonts.clear();
47+ m_defaultFont = BitmapFontPtr(new BitmapFont("emptyfont"));
48+}
49+
50+void FontManager::importFont(std::string file)
51+{
52+ if (g_graphicsThreadId != std::this_thread::get_id()) {
53+ g_graphicsDispatcher.addEvent(std::bind(&FontManager::importFont, this, file));
54+ return;
55+ }
56+ try {
57+ file = g_resources.guessFilePath(file, "otfont");
58+
59+ OTMLDocumentPtr doc = OTMLDocument::parse(file);
60+ OTMLNodePtr fontNode = doc->at("Font");
61+
62+ std::string name = fontNode->valueAt("name");
63+ if (fontExists(name))
64+ return;
65+
66+ // remove any font with the same name
67+ for(auto it = m_fonts.begin(); it != m_fonts.end(); ++it) {
68+ if((*it)->getName() == name) {
69+ m_fonts.erase(it);
70+ break;
71+ }
72+ }
73+
74+ BitmapFontPtr font(new BitmapFont(name));
75+ font->load(fontNode);
76+ m_fonts.push_back(font);
77+
78+ // set as default if needed
79+ if(!m_defaultFont || fontNode->valueAt<bool>("default", false))
80+ m_defaultFont = font;
81+
82+ } catch(stdext::exception& e) {
83+ g_logger.error(stdext::format("Unable to load font from file '%s': %s", file, e.what()));
84+ }
85+}
86+
87+bool FontManager::fontExists(const std::string& fontName)
88+{
89+ for(const BitmapFontPtr& font : m_fonts) {
90+ if(font->getName() == fontName)
91+ return true;
92+ }
93+ return false;
94+}
95+
96+BitmapFontPtr FontManager::getFont(const std::string& fontName)
97+{
98+ // find font by name
99+ for(const BitmapFontPtr& font : m_fonts) {
100+ if(font->getName() == fontName)
101+ return font;
102+ }
103+
104+ // when not found, fallback to default font
105+ g_logger.error(stdext::format("font '%s' not found", fontName));
106+ return getDefaultFont();
107+}
A RD_Client/src/framework/graphics/fontmanager.h +52-0 View file
@@ -0,0 +1,52 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef FONTMANAGER_H
24+#define FONTMANAGER_H
25+
26+#include "bitmapfont.h"
27+
28+//@bindsingleton g_fonts
29+class FontManager
30+{
31+public:
32+ FontManager();
33+
34+ void terminate();
35+ void clearFonts();
36+
37+ void importFont(std::string file);
38+
39+ bool fontExists(const std::string& fontName);
40+ BitmapFontPtr getFont(const std::string& fontName);
41+ BitmapFontPtr getDefaultFont() { return m_defaultFont; }
42+
43+ void setDefaultFont(const std::string& fontName) { m_defaultFont = getFont(fontName); }
44+
45+private:
46+ std::vector<BitmapFontPtr> m_fonts;
47+ BitmapFontPtr m_defaultFont;
48+};
49+
50+extern FontManager g_fonts;
51+
52+#endif
A RD_Client/src/framework/graphics/framebuffer.cpp +239-0 View file
@@ -0,0 +1,239 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#include "framebuffer.h"
24+#include "graphics.h"
25+#include "texture.h"
26+
27+#include <framework/platform/platformwindow.h>
28+#include <framework/core/application.h>
29+#include <framework/core/eventdispatcher.h>
30+#include <framework/core/asyncdispatcher.h>
31+#include <framework/graphics/image.h>
32+
33+uint FrameBuffer::boundFbo = 0;
34+
35+FrameBuffer::FrameBuffer(bool withDepth)
36+{
37+#ifdef WITH_DEPTH_BUFFER
38+ m_depth = withDepth;
39+#else
40+ if(withDepth)
41+ g_logger.fatal("Depth buffer is not supported. Compile OTCv8 with WITH_DEPTH_BUFFER definition.");
42+#endif
43+ internalCreate();
44+}
45+
46+void FrameBuffer::internalCreate()
47+{
48+ m_prevBoundFbo = 0;
49+ m_fbo = 0;
50+ glGenFramebuffers(1, &m_fbo);
51+ if (!m_fbo)
52+ g_logger.fatal("Unable to create framebuffer object");
53+#ifdef WITH_DEPTH_BUFFER
54+ if (m_depth) {
55+ glGenRenderbuffers(1, &m_depthRbo);
56+ if (!m_depthRbo)
57+ g_logger.fatal("Unable to create renderbuffer object");
58+ }
59+#endif
60+ g_graphics.checkForError(__FUNCTION__, __FILE__, __LINE__);
61+}
62+
63+FrameBuffer::~FrameBuffer()
64+{
65+ VALIDATE(!g_app.isTerminated());
66+ if (g_graphics.ok() && m_fbo != 0) {
67+ if (m_fbo != 0)
68+ glDeleteFramebuffers(1, &m_fbo);
69+#ifdef WITH_DEPTH_BUFFER
70+ if (m_depthRbo != 0)
71+ glDeleteRenderbuffers(1, &m_depthRbo);
72+#endif
73+ }
74+ g_graphics.checkForError(__FUNCTION__, __FILE__, __LINE__);
75+}
76+
77+void FrameBuffer::resize(const Size& size)
78+{
79+ if (!size.isValid())
80+ g_logger.fatal(stdext::format("Invalid framebuffer size: %ix%i", size.width(), size.height()));
81+
82+ if (m_texture && m_texture->getSize() == size)
83+ return;
84+
85+ m_texture = TexturePtr(new Texture(size, false, m_smooth, true));
86+ m_texture->update();
87+
88+#ifdef WITH_DEPTH_BUFFER
89+ if (m_depth) {
90+ glBindRenderbuffer(GL_RENDERBUFFER, m_depthRbo);
91+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.width(), size.height());
92+ }
93+#endif
94+
95+ internalBind();
96+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture->getId(), 0);
97+
98+#ifdef WITH_DEPTH_BUFFER
99+ if (m_depth) {
100+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthRbo);
101+ }
102+#endif
103+
104+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
105+ if (status != GL_FRAMEBUFFER_COMPLETE)
106+ g_logger.fatal(stdext::format("Unable to setup framebuffer object - %i - %ix%i", status, size.width(), size.height()));
107+ internalRelease();
108+ g_graphics.checkForError(__FUNCTION__, __FILE__, __LINE__);
109+}
110+
111+void FrameBuffer::bind(const FrameBufferPtr& depthFramebuffer)
112+{
113+ g_painter->saveAndResetState();
114+ internalBind();
115+ g_painter->setResolution(m_texture->getSize());
116+#ifdef WITH_DEPTH_BUFFER
117+ if (!m_depth && depthFramebuffer && depthFramebuffer->hasDepth()) {
118+ m_depthRbo = depthFramebuffer->getDepthRenderBuffer();
119+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthRbo);
120+ }
121+#endif
122+ g_graphics.checkForError(__FUNCTION__, __FILE__, __LINE__);
123+}
124+
125+void FrameBuffer::release()
126+{
127+#ifdef WITH_DEPTH_BUFFER
128+ if (!m_depth && m_depthRbo) {
129+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
130+ m_depthRbo = 0;
131+ }
132+#endif
133+ internalRelease();
134+ g_painter->restoreSavedState();
135+ g_graphics.checkForError(__FUNCTION__, __FILE__, __LINE__);
136+}
137+
138+void FrameBuffer::draw()
139+{
140+ Rect rect(0, 0, getSize());
141+ g_painter->drawTexturedRect(rect, m_texture, rect);
142+}
143+
144+void FrameBuffer::draw(const Rect& dest, const Rect& src)
145+{
146+ g_painter->drawTexturedRect(dest, m_texture, src);
147+}
148+
149+void FrameBuffer::draw(const Rect& dest)
150+{
151+ g_painter->drawTexturedRect(dest, m_texture, Rect(0, 0, getSize()));
152+}
153+
154+std::vector<uint32_t> FrameBuffer::readPixels()
155+{
156+ internalBind();
157+ Size size = getSize();
158+ int width = size.width();
159+ int height = size.height();
160+ std::vector<uint32_t> ret(width * height * sizeof(GLubyte), 0);
161+ glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (GLubyte*)(ret.data()));
162+ internalRelease();
163+ int halfWidth = width / 2;
164+ for (int y = 0; y < height; ++y) {
165+ for (int x = 0; x < halfWidth; ++x) {
166+ std::swap(ret[y * width + x], ret[y * width + width - x - 1]);
167+ }
168+ }
169+ for (int y = 0; y < height; ++y) {
170+ for (int x = 0; x < halfWidth; ++x) {
171+ std::swap(ret[y * width + x], ret[(height - y - 1) * width + width - x - 1]);
172+ }
173+ }
174+ return ret;
175+}
176+
177+void FrameBuffer::internalBind()
178+{
179+ VALIDATE(boundFbo != m_fbo);
180+ glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
181+ m_prevBoundFbo = boundFbo;
182+ boundFbo = m_fbo;
183+}
184+
185+void FrameBuffer::internalRelease()
186+{
187+ VALIDATE(boundFbo == m_fbo);
188+ glBindFramebuffer(GL_FRAMEBUFFER, m_prevBoundFbo);
189+ boundFbo = m_prevBoundFbo;
190+}
191+
192+Size FrameBuffer::getSize()
193+{
194+ return m_texture->getSize();
195+}
196+
197+void FrameBuffer::setSmooth(bool value)
198+{
199+ if (!m_texture || m_smooth == value) return;
200+
201+ m_smooth = value;
202+ m_texture->setSmooth(value);
203+}
204+
205+void FrameBuffer::doScreenshot(std::string fileName)
206+{
207+ if (g_mainThreadId != std::this_thread::get_id()) {
208+ g_graphicsDispatcher.addEvent(std::bind(&FrameBuffer::doScreenshot, this, fileName));
209+ return;
210+ }
211+
212+ if (fileName.empty()) {
213+ fileName = "screenshot_map.png";
214+ }
215+
216+ internalBind();
217+ Size size = getSize();
218+ int width = size.width();
219+ int height = size.height();
220+ auto pixels = std::make_shared<std::vector<uint8_t>>(width * height * 4 * sizeof(GLubyte), 0);
221+ glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (GLubyte*)(pixels->data()));
222+ internalRelease();
223+
224+ g_asyncDispatcher.dispatch([size, pixels, fileName] {
225+ for (int line = 0, h = size.height(), w = size.width(); line != h / 2; ++line) {
226+ std::swap_ranges(
227+ pixels->begin() + 4 * w * line,
228+ pixels->begin() + 4 * w * (line + 1),
229+ pixels->begin() + 4 * w * (h - line - 1));
230+ }
231+ try {
232+ Image image(size, 4, pixels->data());
233+ image.savePNG(fileName);
234+ }
235+ catch (stdext::exception& e) {
236+ g_logger.error(std::string("Can't do map screenshot: ") + e.what());
237+ }
238+ });
239+}
A RD_Client/src/framework/graphics/framebuffer.h +82-0 View file
@@ -0,0 +1,82 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef FRAMEBUFFER_H
24+#define FRAMEBUFFER_H
25+
26+#include "declarations.h"
27+#include "texture.h"
28+
29+class FrameBuffer : public stdext::shared_object
30+{
31+public:
32+ FrameBuffer(bool withDepth = false);
33+
34+protected:
35+ friend class FrameBufferManager;
36+
37+public:
38+ virtual ~FrameBuffer();
39+
40+ void resize(const Size& size);
41+ void bind(const FrameBufferPtr& depthFramebuffer = nullptr);
42+ void release();
43+ void draw();
44+ void draw(const Rect& dest);
45+ void draw(const Rect& dest, const Rect& src);
46+
47+ void setSmooth(bool enabled);
48+
49+ TexturePtr getTexture() { return m_texture; }
50+ Size getSize();
51+ bool isSmooth() { return m_smooth; }
52+
53+#ifdef WITH_DEPTH_BUFFER
54+ uint getDepthRenderBuffer() { return m_depthRbo; }
55+ bool hasDepth() { return m_depth; }
56+#endif
57+
58+ std::vector<uint32_t> readPixels();
59+
60+ void doScreenshot(std::string fileName);
61+
62+private:
63+ void internalCreate();
64+ void internalBind();
65+ void internalRelease();
66+
67+ TexturePtr m_texture;
68+ TexturePtr m_screenBackup;
69+ Size m_oldViewportSize;
70+ uint m_fbo;
71+ uint m_prevBoundFbo;
72+ bool m_smooth = true;
73+
74+#ifdef WITH_DEPTH_BUFFER
75+ uint m_depthRbo = 0;
76+ bool m_depth = false;
77+#endif
78+
79+ static uint boundFbo;
80+};
81+
82+#endif
A RD_Client/src/framework/graphics/framebuffermanager.cpp +48-0 View file
@@ -0,0 +1,48 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+
24+#include "framebuffermanager.h"
25+
26+FrameBufferManager g_framebuffers;
27+
28+void FrameBufferManager::init()
29+{
30+ m_temporaryFramebuffer = FrameBufferPtr(new FrameBuffer());
31+ m_temporaryFramebuffer->setSmooth(true);
32+ m_drawQueueTemporaryFramebuffer = FrameBufferPtr(new FrameBuffer());
33+ m_drawQueueTemporaryFramebuffer->setSmooth(true);
34+}
35+
36+void FrameBufferManager::terminate()
37+{
38+ m_framebuffers.clear();
39+ m_temporaryFramebuffer = nullptr;
40+ m_drawQueueTemporaryFramebuffer = nullptr;
41+}
42+
43+FrameBufferPtr FrameBufferManager::createFrameBuffer(bool withDepth)
44+{
45+ FrameBufferPtr fbo = FrameBufferPtr(new FrameBuffer(withDepth));
46+ m_framebuffers.push_back(fbo);
47+ return fbo;
48+}
A RD_Client/src/framework/graphics/framebuffermanager.h +48-0 View file
@@ -0,0 +1,48 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+
24+#ifndef FRAMEBUFFERMANAGER_H
25+#define FRAMEBUFFERMANAGER_H
26+
27+#include "framebuffer.h"
28+
29+class FrameBufferManager
30+{
31+public:
32+ void init();
33+ void terminate();
34+ void clear();
35+
36+ FrameBufferPtr createFrameBuffer(bool withDepth = false);
37+ const FrameBufferPtr& getTemporaryFrameBuffer() { return m_temporaryFramebuffer; }
38+ const FrameBufferPtr& getDrawQueueTemporaryFrameBuffer() { return m_drawQueueTemporaryFramebuffer; }
39+
40+protected:
41+ FrameBufferPtr m_temporaryFramebuffer;
42+ FrameBufferPtr m_drawQueueTemporaryFramebuffer;
43+ std::vector<FrameBufferPtr> m_framebuffers;
44+};
45+
46+extern FrameBufferManager g_framebuffers;
47+
48+#endif
A RD_Client/src/framework/graphics/glutil.h +52-0 View file
@@ -0,0 +1,52 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+
24+#ifndef GLUTIL_H
25+#define GLUTIL_H
26+
27+#if defined(ANDROID) || defined(__EMSCRIPTEN__)
28+#include <GLES2/gl2.h>
29+#include <GLES2/gl2ext.h>
30+#include <EGL/egl.h>
31+#include <EGL/eglext.h>
32+#elif OPENGL_ES
33+#define EGL_EGL_PROTOTYPES 1
34+#define GL_GLEXT_PROTOTYPES 1
35+#define EGL_EGLEXT_PROTOTYPES 1
36+// for static linking
37+#define GL_APICALL
38+#define EGLAPI
39+
40+#include <GLES2/gl2.h>
41+#include <GLES2/gl2ext.h>
42+#include <EGL/egl.h>
43+#include <EGL/eglext.h>
44+#include <EGL/eglext_angle.h>
45+#else
46+#ifndef _MSC_VER
47+#define GLEW_STATIC
48+#endif
49+#include <GL/glew.h>
50+#endif
51+
52+#endif
A RD_Client/src/framework/graphics/graph.cpp +94-0 View file
@@ -0,0 +1,94 @@
1+#include "graph.h"
2+#include "painter.h"
3+#include "textrender.h"
4+#include "fontmanager.h"
5+#include <framework/core/eventdispatcher.h>
6+
7+Graph g_graphs[GRAPH_LAST + 1] = {
8+ {"Total frame time"},
9+ {"CPU render time"},
10+ {"GPU calls"},
11+ {"GPU draws"},
12+ {"Processing poll time"},
13+ {"Graphics poll time"},
14+ {"Dispatcher events"},
15+ {"Graphics events"},
16+ {"Latency"}
17+};
18+
19+Graph::Graph(const std::string& name, size_t capacity) : m_name(name), m_capacity(capacity)
20+{
21+ if (capacity > MAX_CAPACITY)
22+ g_logger.fatal(stdext::format("Max Graph capacity is %i, tried to create graph with capacity: %i", MAX_CAPACITY, capacity));
23+}
24+
25+void Graph::draw(const Rect& dest)
26+{
27+ VALIDATE_GRAPHICS_THREAD();
28+ static std::vector<float> vertices(MAX_CAPACITY * 2, 0); // max 512 lines
29+ if (dest.width() < 50) return;
30+ float offsetX = dest.left() + 2;
31+ float offsetY = dest.top() + 17;
32+ size_t elements = std::min<size_t>(m_values.size(), dest.width() / 2 - 2);
33+
34+ vertices[0] = dest.left();
35+ vertices[1] = offsetY;
36+ vertices[2] = dest.right();
37+ vertices[3] = offsetY;
38+ vertices[4] = dest.right();
39+ vertices[5] = dest.bottom();
40+ vertices[6] = dest.left();
41+ vertices[7] = dest.bottom();
42+ vertices[8] = dest.left();
43+ vertices[9] = offsetY;
44+
45+ g_painter->drawLine(vertices, 5);
46+ g_text.drawText(dest, m_name, g_fonts.getDefaultFont());
47+
48+ m_mutex.lock();
49+ size_t start = m_values.size() - elements;
50+ int minVal = 0xFFFFFF, maxVal = -0xFFFFFF;
51+ for (size_t i = start; i < m_values.size(); ++i) {
52+ if (minVal > m_values[i])
53+ minVal = m_values[i];
54+ if (maxVal < m_values[i])
55+ maxVal = m_values[i];
56+ }
57+ // round
58+ maxVal = (1 + maxVal / 10) * 10;
59+ minVal = (minVal / 10) * 10;
60+ float step = (float)(dest.height() - 21) / std::max<float>(1, (maxVal - minVal));
61+ for (size_t i = start, j = 0; i < m_values.size(); ++i) {
62+ vertices[j] = offsetX + j;
63+ vertices[j + 1] = offsetY + 1 + (maxVal - m_values[i]) * step;
64+ j += 2;
65+ }
66+ m_mutex.unlock();
67+
68+ if (elements > 0) {
69+ g_text.drawText(dest, std::to_string(m_values.back()), g_fonts.getDefaultFont(), Color::white, Fw::AlignTopRight);
70+ g_text.drawText(Rect(dest.left() + 1, offsetY, 50, 15), std::to_string(maxVal), g_fonts.getDefaultFont());
71+ g_text.drawText(Rect(dest.left() + 1, dest.bottom() - 14, 50, 15), std::to_string(minVal), g_fonts.getDefaultFont());
72+ }
73+ g_painter->setColor(Color::white);
74+ g_painter->drawLine(vertices, elements);
75+}
76+
77+void Graph::clear()
78+{
79+ std::lock_guard<std::mutex> lock(m_mutex);
80+ m_values.clear();
81+}
82+
83+void Graph::addValue(int value, bool ignoreSmallValues)
84+{
85+ std::lock_guard<std::mutex> lock(m_mutex);
86+ if (ignoreSmallValues) {
87+ if (!m_values.empty() && m_values.back() <= 2 && value <= 2 && ++m_ignores <= 10)
88+ return;
89+ m_ignores = 0;
90+ }
91+ m_values.push_back(value);
92+ if (m_values.size() > m_capacity)
93+ m_values.pop_front();
94+}
A RD_Client/src/framework/graphics/graph.h +43-0 View file
@@ -0,0 +1,43 @@
1+// Graph is a simple, thread-safe class to draw debug informations about FPS, CPU time per frame, Ping, etc.
2+// It's not optimized, so should be used only as debugging tool
3+
4+#ifndef GRAPH_H
5+#define GRAPH_H
6+
7+#include <framework/global.h>
8+
9+enum GraphType {
10+ GRAPH_TOTAL_FRAME_TIME = 0,
11+ GRAPH_CPU_FRAME_TIME = 1,
12+ GRAPH_GPU_CALLS = 2,
13+ GRAPH_GPU_DRAWS = 3,
14+ GRAPH_PROCESSING_POLL = 4,
15+ GRAPH_GRAPHICS_POLL = 5,
16+ GRAPH_DISPATCHER_EVENTS = 6,
17+ GRAPH_GRAPHICS_EVENTS = 7,
18+ GRAPH_LATENCY = 8,
19+ GRAPH_LAST = GRAPH_LATENCY
20+};
21+
22+class Graph
23+{
24+ static constexpr int MAX_CAPACITY = 512;
25+public:
26+ Graph(const std::string& name, size_t capacity = 100);
27+
28+ void draw(const Rect& dest);
29+
30+ void clear();
31+ void addValue(int value, bool ignoreSmallValues = false);
32+
33+private:
34+ std::string m_name;
35+ size_t m_capacity;
36+ size_t m_ignores = 0;
37+ std::deque<int> m_values;
38+ std::mutex m_mutex;
39+};
40+
41+extern Graph g_graphs[GRAPH_LAST + 1];
42+
43+#endif
A RD_Client/src/framework/graphics/graphics.cpp +159-0 View file
@@ -0,0 +1,159 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#include "fontmanager.h"
24+
25+#include "painter.h"
26+
27+#include <framework/graphics/atlas.h>
28+#include <framework/graphics/graphics.h>
29+#include <framework/graphics/texture.h>
30+#include "texturemanager.h"
31+#include "framebuffermanager.h"
32+#include <framework/platform/platformwindow.h>
33+#include <framework/graphics/textrender.h>
34+
35+Graphics g_graphics;
36+
37+Graphics::Graphics()
38+{
39+ m_maxTextureSize = 2048;
40+}
41+
42+void Graphics::init()
43+{
44+ g_graphics.checkForError(__FUNCTION__, __FILE__, __LINE__);
45+ glGetString(GL_NONE); glGetError(); // REQUIRED, DON'T REMOVE
46+ m_vendor = std::string((const char*)glGetString(GL_VENDOR) ? (const char*)glGetString(GL_VENDOR) : "");
47+ m_renderer = std::string((const char*)glGetString(GL_RENDERER) ? (const char*)glGetString(GL_RENDERER) : "");
48+ m_version = std::string((const char*)glGetString(GL_VERSION) ? (const char*)glGetString(GL_VERSION) : "");
49+ m_extensions = std::string((const char*)glGetString(GL_EXTENSIONS) ? (const char*)glGetString(GL_EXTENSIONS) : "");
50+
51+ g_logger.info(stdext::format("GPU %s (%s)", m_renderer, m_vendor));
52+ g_logger.info(stdext::format("OpenGL %s", m_version));
53+
54+ // init GL extensions
55+#ifndef OPENGL_ES
56+ float glVersion = 1.0;
57+ try {
58+ glVersion = std::atof(m_version.c_str());
59+ }
60+ catch (const std::exception&) {}
61+
62+ if (glVersion < 2.0) {
63+ g_logger.fatal(stdext::format("Your device doesn't support OpenGL >= 2.0, try to use DX version or install graphics drivers. GPU: %s OpenGL: %s (%f), Ext: %s",
64+ m_renderer, m_version, glVersion, m_extensions));
65+ }
66+
67+ GLenum err = glewInit();
68+ if(err != GLEW_OK)
69+ g_logger.fatal(stdext::format("Unable to init GLEW: %s", glewGetErrorString(err)));
70+
71+ // overwrite framebuffer API if needed
72+ if(GLEW_EXT_framebuffer_object && !GLEW_ARB_framebuffer_object) {
73+ glGenFramebuffers = glGenFramebuffersEXT;
74+ glDeleteFramebuffers = glDeleteFramebuffersEXT;
75+ glBindFramebuffer = glBindFramebufferEXT;
76+ glFramebufferTexture2D = glFramebufferTexture2DEXT;
77+ glCheckFramebufferStatus = glCheckFramebufferStatusEXT;
78+ glGenerateMipmap = glGenerateMipmapEXT;
79+ }
80+#endif
81+
82+ // blending is always enabled
83+ glEnable(GL_BLEND);
84+
85+ int maxTextureSize = 0;
86+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
87+ if (m_maxTextureSize == -1 || m_maxTextureSize < maxTextureSize)
88+ m_maxTextureSize = maxTextureSize;
89+
90+#ifdef WITH_DEPTH_BUFFER
91+ checkDepthSupport();
92+#endif
93+ g_graphics.checkForError(__FUNCTION__, __FILE__, __LINE__);
94+
95+ m_ok = true;
96+
97+ g_painter = new Painter();
98+ g_painter->bind();
99+
100+ g_textures.init();
101+ g_framebuffers.init();
102+ g_atlas.init();
103+ g_text.init();
104+ g_graphics.checkForError(__FUNCTION__, __FILE__, __LINE__);
105+}
106+
107+void Graphics::terminate()
108+{
109+ g_fonts.terminate();
110+ g_framebuffers.terminate();
111+ g_textures.terminate();
112+ g_atlas.terminate();
113+ g_text.terminate();
114+
115+ if (g_painter) {
116+ g_painter->unbind();
117+ delete g_painter;
118+ g_painter = nullptr;
119+ }
120+
121+ m_ok = false;
122+}
123+
124+void Graphics::resize(const Size& size)
125+{
126+ m_viewportSize = size;
127+ if(g_painter)
128+ g_painter->setResolution(size);
129+}
130+
131+#ifdef WITH_DEPTH_BUFFER
132+void Graphics::checkDepthSupport()
133+{
134+ glGetError(); // clear error
135+ uint32 rbo = 0;
136+ glGenRenderbuffers(1, &rbo);
137+ if (rbo) {
138+ glBindRenderbuffer(GL_RENDERBUFFER, rbo);
139+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 64, 64);
140+ glDeleteRenderbuffers(1, &rbo);
141+ if (glGetError() == GL_NO_ERROR)
142+ return;
143+ }
144+ g_logger.fatal("Depth buffer is not supported. Your computer or graphics drivers are too old to use this program.")
145+}
146+#endif
147+
148+void Graphics::checkForError(const std::string& function, const std::string& file, int line)
149+{
150+ auto error = glGetError();
151+ if (error != GL_NO_ERROR) {
152+#ifndef NDEBUG
153+ g_logger.fatal(
154+#else
155+ g_logger.error(
156+#endif
157+ stdext::format("Render error: %i in %s (%s:%i)", error, function, file, line));
158+ }
159+}
Top