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 <framework/graphics/atlas.h>
24#include <framework/graphics/painter.h>
25#include <framework/graphics/graphics.h>
26#include <framework/graphics/colorarray.h>
27#include <framework/graphics/deptharray.h>
28#include <framework/platform/platformwindow.h>
29
30#include <framework/graphics/shaders/shaders.h>
31#include <framework/platform/platformwindow.h>
32#include <framework/util/extras.h>
33
34Painter* g_painter = nullptr;
35
36Painter::Painter()
37{
38 m_glTextureId = 0;
39 m_oldStateIndex = 0;
40 m_color = Color::white;
41 m_compositionMode = CompositionMode_Normal;
42 m_blendEquation = BlendEquation_Add;
43 m_shaderProgram = nullptr;
44 m_texture = nullptr;
45 m_alphaWriting = false;
46#ifdef WITH_DEPTH_BUFFER
47 m_depth = 0;
48 m_depthFunc = DepthFunc_None;
49#endif
50 setResolution(g_window.getSize());
51
52 m_drawProgram = nullptr;
53 resetState();
54
55 m_drawTexturedProgram = PainterShaderProgram::create("drawTexturedProgram", glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader,
56 glslMainFragmentShader + glslTextureSrcFragmentShader);
57 m_drawSolidColorProgram = PainterShaderProgram::create("drawSolidColorProgram", glslMainVertexShader + glslPositionOnlyVertexShader,
58 glslMainFragmentShader + glslSolidColorFragmentShader);
59 m_drawSolidColorOnTextureProgram = PainterShaderProgram::create("drawSolidColorOnTextureProgram", glslMainWithTexCoordsVertexShader + glslPositionOnlyVertexShader,
60 glslMainFragmentShader + glslSolidColorOnTextureFragmentShader);
61 m_drawOutfitLayersProgram = PainterShaderProgram::create("drawOutfitLayersProgram", glslOutfitVertexShader, glslOutfitFragmentShader, true);
62 m_drawNewProgram = PainterShaderProgram::create("drawNewProgram", newVertexShader, newFragmentShader);
63 m_drawTextProgram = PainterShaderProgram::create("drawTextProgram", textVertexShader, textFragmentShader);
64 m_drawLineProgram = PainterShaderProgram::create("drawLineProgram", lineVertexShader, lineFragmentShader);
65
66 if (!m_drawTexturedProgram || !m_drawSolidColorProgram || !m_drawSolidColorOnTextureProgram || !m_drawOutfitLayersProgram ||
67 !m_drawNewProgram || !m_drawTextProgram || !m_drawLineProgram) {
68 g_logger.fatal("Can't setup default shaders, check log file for details");
69 }
70
71 PainterShaderProgram::release();
72 g_graphics.checkForError(__FUNCTION__, __FILE__, __LINE__);
73}
74
75void Painter::bind()
76{
77 refreshState();
78
79 // vertex and texture coord attributes are always enabled
80 // to avoid massive enable/disables, thus improving frame rate
81 PainterShaderProgram::enableAttributeArray(PainterShaderProgram::VERTEX_ATTR);
82 PainterShaderProgram::enableAttributeArray(PainterShaderProgram::TEXCOORD_ATTR);
83}
84
85void Painter::unbind()
86{
87 PainterShaderProgram::disableAttributeArray(PainterShaderProgram::VERTEX_ATTR);
88 PainterShaderProgram::disableAttributeArray(PainterShaderProgram::TEXCOORD_ATTR);
89 PainterShaderProgram::release();
90}
91
92void Painter::resetState()
93{
94 resetColor();
95 resetCompositionMode();
96 resetBlendEquation();
97 resetClipRect();
98 resetShaderProgram();
99 resetTexture();
100 resetAlphaWriting();
101 resetTransformMatrix();
102#ifdef WITH_DEPTH_BUFFER
103 resetDepth();
104 resetDepthFunc();
105#endif
106}
107
108void Painter::refreshState()
109{
110 updateGlViewport();
111 updateGlCompositionMode();
112 updateGlBlendEquation();
113 updateGlClipRect();
114 updateGlTexture();
115 updateGlAlphaWriting();
116#ifdef WITH_DEPTH_BUFFER
117 updateDepthFunc();
118#endif
119}
120
121void Painter::saveState()
122{
123 VALIDATE(m_oldStateIndex < 10);
124 m_olderStates[m_oldStateIndex].resolution = m_resolution;
125 m_olderStates[m_oldStateIndex].transformMatrix = m_transformMatrix;
126 m_olderStates[m_oldStateIndex].projectionMatrix = m_projectionMatrix;
127 m_olderStates[m_oldStateIndex].textureMatrix = m_textureMatrix;
128 m_olderStates[m_oldStateIndex].color = m_color;
129 m_olderStates[m_oldStateIndex].compositionMode = m_compositionMode;
130 m_olderStates[m_oldStateIndex].blendEquation = m_blendEquation;
131 m_olderStates[m_oldStateIndex].clipRect = m_clipRect;
132 m_olderStates[m_oldStateIndex].shaderProgram = m_shaderProgram;
133 m_olderStates[m_oldStateIndex].texture = m_texture;
134 m_olderStates[m_oldStateIndex].alphaWriting = m_alphaWriting;
135#ifdef WITH_DEPTH_BUFFER
136 m_olderStates[m_oldStateIndex].depth = m_depth;
137 m_olderStates[m_oldStateIndex].depthFunc = m_depthFunc;
138#endif
139 m_oldStateIndex++;
140}
141
142void Painter::saveAndResetState()
143{
144 saveState();
145 resetState();
146}
147
148void Painter::restoreSavedState()
149{
150 m_oldStateIndex--;
151 setResolution(m_olderStates[m_oldStateIndex].resolution);
152 setTransformMatrix(m_olderStates[m_oldStateIndex].transformMatrix);
153 setProjectionMatrix(m_olderStates[m_oldStateIndex].projectionMatrix);
154 setTextureMatrix(m_olderStates[m_oldStateIndex].textureMatrix);
155 setColor(m_olderStates[m_oldStateIndex].color);
156 setCompositionMode(m_olderStates[m_oldStateIndex].compositionMode);
157 setBlendEquation(m_olderStates[m_oldStateIndex].blendEquation);
158 setClipRect(m_olderStates[m_oldStateIndex].clipRect);
159 setShaderProgram(m_olderStates[m_oldStateIndex].shaderProgram);
160 setTexture(m_olderStates[m_oldStateIndex].texture);
161 setAlphaWriting(m_olderStates[m_oldStateIndex].alphaWriting);
162#ifdef WITH_DEPTH_BUFFER
163 setDepth(m_olderStates[m_oldStateIndex].depth);
164 setDepthFunc(m_olderStates[m_oldStateIndex].depthFunc);
165#endif
166}
167
168void Painter::clear(const Color& color)
169{
170 glClearColor(color.rF(), color.gF(), color.bF(), color.aF());
171#ifdef WITH_DEPTH_BUFFER
172#ifdef OPENGL_ES
173 glClearDepthf(0.99f);
174#else
175 glClearDepth(0.99f);
176#endif
177 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
178#else
179 glClear(GL_COLOR_BUFFER_BIT);
180#endif
181}
182
183void Painter::clearRect(const Color& color, const Rect& rect)
184{
185 Rect oldClipRect = m_clipRect;
186 setClipRect(rect);
187 glClearColor(color.rF(), color.gF(), color.bF(), color.aF());
188#ifdef WITH_DEPTH_BUFFER
189#ifdef OPENGL_ES
190 glClearDepthf(0.99f);
191#else
192 glClearDepth(0.99f);
193#endif
194 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
195#else
196 glClear(GL_COLOR_BUFFER_BIT);
197#endif
198 setClipRect(oldClipRect);
199}
200
201void Painter::setCompositionMode(Painter::CompositionMode compositionMode)
202{
203 if (m_compositionMode == compositionMode)
204 return;
205 m_compositionMode = compositionMode;
206 updateGlCompositionMode();
207}
208
209void Painter::setBlendEquation(Painter::BlendEquation blendEquation)
210{
211 if (m_blendEquation == blendEquation)
212 return;
213 m_blendEquation = blendEquation;
214 updateGlBlendEquation();
215}
216
217#ifdef WITH_DEPTH_BUFFER
218void Painter::setDepthFunc(DepthFunc func)
219{
220 if (m_depthFunc == func)
221 return;
222 m_depthFunc = func;
223 updateDepthFunc();
224}
225#endif
226
227void Painter::setClipRect(const Rect& clipRect)
228{
229 if (m_clipRect == clipRect)
230 return;
231 m_clipRect = clipRect;
232 updateGlClipRect();
233}
234
235void Painter::setTexture(const TexturePtr& texture)
236{
237 if (m_texture == texture)
238 return;
239
240 m_texture = texture;
241 if (m_texture)
242 m_texture->update();
243
244 uint glTextureId;
245 if (texture) {
246 setTextureMatrix(texture->getTransformMatrix());
247 glTextureId = texture->getId();
248 } else
249 glTextureId = 0;
250
251 if (m_glTextureId != glTextureId) {
252 m_glTextureId = glTextureId;
253 updateGlTexture();
254 }
255}
256
257void Painter::setAlphaWriting(bool enable)
258{
259 if (m_alphaWriting == enable)
260 return;
261
262 m_alphaWriting = enable;
263 updateGlAlphaWriting();
264}
265
266void Painter::setResolution(const Size& resolution)
267{
268 // The projection matrix converts from Painter's coordinate system to GL's coordinate system
269 // * GL's viewport is 2x2, Painter's is width x height
270 // * GL has +y -> -y going from bottom -> top, Painter is the other way round
271 // * GL has [0,0] in the center, Painter has it in the top-left
272 //
273 // This results in the Projection matrix below.
274 //
275 // Projection Matrix
276 // Painter Coord ------------------------------------------------ GL Coord
277 // ------------- | 2.0 / width | 0.0 | 0.0 | ---------------
278 // | x y 1 | * | 0.0 | -2.0 / height | 0.0 | = | x' y' 1 |
279 // ------------- | -1.0 | 1.0 | 1.0 | ---------------
280
281 Matrix3 projectionMatrix = { 2.0f / resolution.width(), 0.0f, 0.0f,
282 0.0f, -2.0f / resolution.height(), 0.0f,
283 -1.0f, 1.0f, 1.0f };
284
285 m_resolution = resolution;
286
287 setProjectionMatrix(projectionMatrix);
288 if (g_painter == this)
289 updateGlViewport();
290}
291
292void Painter::scale(float x, float y)
293{
294 Matrix3 scaleMatrix = {
295 x, 0.0f, 0.0f,
296 0.0f, y, 0.0f,
297 0.0f, 0.0f, 1.0f
298 };
299
300 setTransformMatrix(m_transformMatrix * scaleMatrix.transposed());
301}
302
303void Painter::translate(float x, float y)
304{
305 Matrix3 translateMatrix = {
306 1.0f, 0.0f, x,
307 0.0f, 1.0f, y,
308 0.0f, 0.0f, 1.0f
309 };
310
311 setTransformMatrix(m_transformMatrix * translateMatrix.transposed());
312}
313
314void Painter::rotate(float angle)
315{
316 Matrix3 rotationMatrix = {
317 std::cos(angle), -std::sin(angle), 0.0f,
318 std::sin(angle), std::cos(angle), 0.0f,
319 0.0f, 0.0f, 1.0f
320 };
321
322 setTransformMatrix(m_transformMatrix * rotationMatrix.transposed());
323}
324
325void Painter::rotate(float x, float y, float angle)
326{
327 translate(-x, -y);
328 rotate(angle);
329 translate(x, y);
330}
331
332void Painter::pushTransformMatrix()
333{
334 m_transformMatrixStack.push_back(m_transformMatrix);
335 VALIDATE(m_transformMatrixStack.size() < 100);
336}
337
338void Painter::popTransformMatrix()
339{
340 VALIDATE(m_transformMatrixStack.size() > 0);
341 setTransformMatrix(m_transformMatrixStack.back());
342 m_transformMatrixStack.pop_back();
343}
344
345void Painter::updateGlTexture()
346{
347 if (m_glTextureId != 0)
348 glBindTexture(GL_TEXTURE_2D, m_glTextureId);
349}
350
351void Painter::updateGlCompositionMode()
352{
353 switch (m_compositionMode) {
354 case CompositionMode_Normal:
355 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
356 break;
357 case CompositionMode_Multiply:
358 glBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);
359 break;
360 case CompositionMode_Add:
361 glBlendFunc(GL_ONE, GL_ONE);
362 break;
363 case CompositionMode_Replace:
364 glBlendFunc(GL_ONE, GL_ZERO);
365 break;
366 case CompositionMode_DestBlending:
367 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
368 break;
369 case CompositionMode_Light:
370 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
371 break;
372 case CompositionMode_AlphaZeroing:
373 glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_ONE, GL_ZERO);
374 break;
375 case CompositionMode_AlphaRestoring:
376 glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_ONE, GL_ONE);
377 break;
378 case CompositionMode_ZeroAlphaOverrite:
379 glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_ONE, GL_ONE);
380 break;
381 }
382}
383
384void Painter::updateGlBlendEquation()
385{
386 if (m_blendEquation == BlendEquation_Add)
387 glBlendEquation(GL_FUNC_ADD); // GL_FUNC_ADD
388 else if (m_blendEquation == BlendEquation_Max)
389 glBlendEquation(0x8008); // GL_MAX
390 else if (m_blendEquation == BlendEquation_Subtract)
391 glBlendEquation(GL_FUNC_SUBTRACT); // GL_MAX
392}
393
394#ifdef WITH_DEPTH_BUFFER
395void Painter::updateDepthFunc()
396{
397 if (m_depthFunc != DepthFunc_None) {
398 glEnable(GL_DEPTH_TEST);
399 }
400
401 switch (m_depthFunc) {
402 case DepthFunc_None:
403 glDisable(GL_DEPTH_TEST);
404 break;
405 case DepthFunc_ALWAYS:
406 glDepthFunc(GL_ALWAYS);
407 glDepthMask(GL_TRUE);
408 break;
409 case DepthFunc_ALWAYS_READ:
410 glDepthFunc(GL_ALWAYS);
411 glDepthMask(GL_FALSE);
412 break;
413 case DepthFunc_EQUAL:
414 glDepthFunc(GL_EQUAL);
415 glDepthMask(GL_TRUE);
416 break;
417 case DepthFunc_LEQUAL:
418 glDepthFunc(GL_LEQUAL);
419 glDepthMask(GL_TRUE);
420 break;
421 case DepthFunc_LEQUAL_READ:
422 glDepthFunc(GL_LEQUAL);
423 glDepthMask(GL_FALSE);
424 break;
425 case DepthFunc_LESS:
426 glDepthFunc(GL_LESS);
427 glDepthMask(GL_TRUE);
428 break;
429 case DepthFunc_LESS_READ:
430 glDepthFunc(GL_LESS);
431 glDepthMask(GL_FALSE);
432 break;
433 }
434}
435#endif
436
437void Painter::updateGlClipRect()
438{
439 if (m_clipRect.isValid()) {
440 glEnable(GL_SCISSOR_TEST);
441 glScissor(m_clipRect.left(), m_resolution.height() - m_clipRect.bottom() - 1, m_clipRect.width(), m_clipRect.height());
442 } else {
443 glScissor(0, 0, m_resolution.width(), m_resolution.height());
444 glDisable(GL_SCISSOR_TEST);
445 }
446}
447
448void Painter::updateGlAlphaWriting()
449{
450 if (m_alphaWriting)
451 glColorMask(1, 1, 1, 1);
452 else
453 glColorMask(1, 1, 1, 0);
454}
455
456void Painter::updateGlViewport()
457{
458 glViewport(0, 0, m_resolution.width(), m_resolution.height());
459}
460
461void Painter::drawCoords(CoordsBuffer& coordsBuffer, DrawMode drawMode, ColorArray* colorArray, const std::vector<std::pair<int, Color>>* colors)
462{
463 coordsBuffer.cache();
464 int vertexCount = coordsBuffer.getVertexCount();
465 if (vertexCount == 0)
466 return;
467
468 bool textured = coordsBuffer.getTextureCoordCount() > 0 && m_texture;
469
470 // skip drawing of empty textures
471 if (textured && m_texture->isEmpty())
472 return;
473
474 // update shader with the current painter state
475 m_drawProgram->bind();
476 m_drawProgram->setTransformMatrix(m_transformMatrix);
477 m_drawProgram->setProjectionMatrix(m_projectionMatrix);
478 if (textured) {
479 m_drawProgram->setTextureMatrix(m_textureMatrix);
480 m_drawProgram->bindMultiTextures();
481 }
482
483#ifdef WITH_DEPTH_BUFFER
484 m_drawProgram->setDepth(m_depth);
485#endif
486 if (m_drawProgram != m_drawOutfitLayersProgram) {
487 m_drawProgram->setColor(m_color);
488 } else {
489 m_drawProgram->setMatrixColor(m_matrixColor);
490 }
491 m_drawProgram->setResolution(m_resolution);
492 m_drawProgram->updateTime();
493
494 // only set texture coords arrays when needed
495 if (textured) {
496 HardwareBuffer* hardwareCache = coordsBuffer.getTextureHardwareCache();
497 if (hardwareCache) {
498 hardwareCache->bind();
499 m_drawProgram->setAttributeArray(PainterShaderProgram::TEXCOORD_ATTR, nullptr, 2);
500 HardwareBuffer::unbind(HardwareBuffer::VertexBuffer);
501 } else {
502 m_drawProgram->setAttributeArray(PainterShaderProgram::TEXCOORD_ATTR, coordsBuffer.getTextureCoordArray(), 2);
503 }
504 } else
505 PainterShaderProgram::disableAttributeArray(PainterShaderProgram::TEXCOORD_ATTR);
506
507 if (colorArray) {
508 PainterShaderProgram::enableAttributeArray(PainterShaderProgram::COLOR_ATTR);
509 m_drawProgram->setAttributeArray(PainterShaderProgram::COLOR_ATTR, colorArray->colors(), 4);
510 }
511
512 HardwareBuffer* hardwareCache = coordsBuffer.getVertexHardwareCache();
513 if (hardwareCache) {
514 hardwareCache->bind();
515 m_drawProgram->setAttributeArray(PainterShaderProgram::VERTEX_ATTR, nullptr, 2);
516 HardwareBuffer::unbind(HardwareBuffer::VertexBuffer);
517 } else {
518 m_drawProgram->setAttributeArray(PainterShaderProgram::VERTEX_ATTR, coordsBuffer.getVertexArray(), 2);
519 }
520
521 if (drawMode == Triangles) {
522 if (colors) {
523 int s = 0;
524 for (auto& cp : *colors) {
525 m_drawProgram->setColor(cp.second);
526 glDrawArrays(GL_TRIANGLES, s * 6, (cp.first - s) * 6);
527 s = cp.first;
528 }
529 } else {
530 glDrawArrays(GL_TRIANGLES, 0, vertexCount);
531 }
532 } else if (drawMode == TriangleStrip) {
533 glDrawArrays(GL_TRIANGLE_STRIP, 0, vertexCount);
534 }
535 m_draws += vertexCount;
536 m_calls += 1;
537
538 if (!textured)
539 PainterShaderProgram::enableAttributeArray(PainterShaderProgram::TEXCOORD_ATTR);
540 if (colorArray)
541 PainterShaderProgram::disableAttributeArray(PainterShaderProgram::COLOR_ATTR);
542}
543
544void Painter::drawFillCoords(CoordsBuffer& coordsBuffer)
545{
546 setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawSolidColorProgram.get());
547 setTexture(nullptr);
548 drawCoords(coordsBuffer);
549}
550
551void Painter::drawTextureCoords(CoordsBuffer& coordsBuffer, const TexturePtr& texture, const std::vector<std::pair<int, Color>>* colors)
552{
553 if (texture && texture->isEmpty())
554 return;
555
556 setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawTexturedProgram.get());
557 setTexture(texture);
558 drawCoords(coordsBuffer, Painter::Triangles, nullptr, colors);
559}
560
561void Painter::drawTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src)
562{
563 if (dest.isEmpty() || src.isEmpty() || texture->isEmpty())
564 return;
565
566 setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawTexturedProgram.get());
567 setTexture(texture);
568
569 m_coordsBuffer.clear();
570 m_coordsBuffer.addQuad(dest, src);
571 drawCoords(m_coordsBuffer, TriangleStrip);
572}
573
574void Painter::drawColorOnTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src)
575{
576 if (dest.isEmpty() || src.isEmpty() || texture->isEmpty())
577 return;
578
579 setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawSolidColorOnTextureProgram.get());
580 setTexture(texture);
581
582 m_coordsBuffer.clear();
583 m_coordsBuffer.addQuad(dest, src);
584 drawCoords(m_coordsBuffer, TriangleStrip);
585}
586
587void Painter::drawUpsideDownTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src)
588{
589 if (dest.isEmpty() || src.isEmpty() || texture->isEmpty())
590 return;
591
592 setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawTexturedProgram.get());
593 setTexture(texture);
594
595 m_coordsBuffer.clear();
596 m_coordsBuffer.addUpsideDownQuad(dest, src);
597 drawCoords(m_coordsBuffer, TriangleStrip);
598}
599
600void Painter::drawRepeatedTexturedRect(const Rect& dest, const TexturePtr& texture, const Rect& src)
601{
602 if (dest.isEmpty() || src.isEmpty() || texture->isEmpty())
603 return;
604
605 setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawTexturedProgram.get());
606 setTexture(texture);
607
608 m_coordsBuffer.clear();
609 m_coordsBuffer.addRepeatedRects(dest, src);
610 drawCoords(m_coordsBuffer);
611}
612
613void Painter::drawFilledRect(const Rect& dest)
614{
615 if (dest.isEmpty())
616 return;
617
618 setDrawProgram(m_shaderProgram ? m_shaderProgram : m_drawSolidColorProgram.get());
619
620 m_coordsBuffer.clear();
621 m_coordsBuffer.addRect(dest);
622 drawCoords(m_coordsBuffer);
623}
624
625// new render
626void Painter::drawText(const Point& pos, CoordsBuffer& coordsBuffer, const Color& color, const TexturePtr& texture)
627{
628 setTexture(texture);
629 // update shader with the current painter state
630 m_drawTextProgram->bind();
631 m_drawTextProgram->setTransformMatrix(m_transformMatrix);
632 m_drawTextProgram->setProjectionMatrix(m_projectionMatrix);
633 m_drawTextProgram->setTextureMatrix(m_textureMatrix);
634 m_drawTextProgram->setOffset(pos);
635 m_drawTextProgram->setColor(color);
636
637 HardwareBuffer* hardwareCache = coordsBuffer.getVertexHardwareCache();
638 if (hardwareCache) {
639 hardwareCache->bind();
640 m_drawTextProgram->setAttributeArray(PainterShaderProgram::VERTEX_ATTR, nullptr, 2);
641 HardwareBuffer::unbind(HardwareBuffer::VertexBuffer);
642 } else {
643 m_drawTextProgram->setAttributeArray(PainterShaderProgram::VERTEX_ATTR, coordsBuffer.getVertexArray(), 2);
644 }
645
646 HardwareBuffer* texHardwareCache = coordsBuffer.getTextureHardwareCache();
647 if (texHardwareCache) {
648 texHardwareCache->bind();
649 m_drawTextProgram->setAttributeArray(PainterShaderProgram::TEXCOORD_ATTR, nullptr, 2);
650 HardwareBuffer::unbind(HardwareBuffer::VertexBuffer);
651 } else {
652 m_drawTextProgram->setAttributeArray(PainterShaderProgram::TEXCOORD_ATTR, coordsBuffer.getTextureCoordArray(), 2);
653 }
654
655 glDrawArrays(GL_TRIANGLES, 0, coordsBuffer.getVertexCount());
656 m_draws += coordsBuffer.getVertexCount();
657 m_calls += 1;
658}
659
660void Painter::drawText(const Point& pos, CoordsBuffer& coordsBuffer, const std::vector<std::pair<int, Color>>& colors, const TexturePtr& texture)
661{
662 setTexture(texture);
663 // update shader with the current painter state
664 m_drawTextProgram->bind();
665 m_drawTextProgram->setTransformMatrix(m_transformMatrix);
666 m_drawTextProgram->setProjectionMatrix(m_projectionMatrix);
667 m_drawTextProgram->setTextureMatrix(m_textureMatrix);
668 m_drawTextProgram->setOffset(pos);
669
670 HardwareBuffer* hardwareCache = coordsBuffer.getVertexHardwareCache();
671 if (hardwareCache) {
672 hardwareCache->bind();
673 m_drawTextProgram->setAttributeArray(PainterShaderProgram::VERTEX_ATTR, nullptr, 2);
674 HardwareBuffer::unbind(HardwareBuffer::VertexBuffer);
675 } else {
676 m_drawTextProgram->setAttributeArray(PainterShaderProgram::VERTEX_ATTR, coordsBuffer.getVertexArray(), 2);
677 }
678
679 HardwareBuffer* texHardwareCache = coordsBuffer.getTextureHardwareCache();
680 if (texHardwareCache) {
681 texHardwareCache->bind();
682 m_drawTextProgram->setAttributeArray(PainterShaderProgram::TEXCOORD_ATTR, nullptr, 2);
683 HardwareBuffer::unbind(HardwareBuffer::VertexBuffer);
684 } else {
685 m_drawTextProgram->setAttributeArray(PainterShaderProgram::TEXCOORD_ATTR, coordsBuffer.getTextureCoordArray(), 2);
686 }
687
688 int s = 0;
689 for (auto& cp : colors) {
690 m_drawTextProgram->setColor(cp.second);
691 glDrawArrays(GL_TRIANGLES, s * 6, (cp.first - s) * 6);
692 s = cp.first;
693 }
694 m_draws += coordsBuffer.getVertexCount();
695 m_calls += colors.size();
696}
697
698void Painter::drawLine(const std::vector<float>& vertex, int size, int width)
699{
700 m_drawLineProgram->bind();
701 m_drawLineProgram->setTransformMatrix(m_transformMatrix);
702 m_drawLineProgram->setProjectionMatrix(m_projectionMatrix);
703 m_drawLineProgram->setTextureMatrix(m_textureMatrix);
704 m_drawLineProgram->setColor(m_color);
705 glLineWidth(width);
706
707 PainterShaderProgram::disableAttributeArray(PainterShaderProgram::TEXCOORD_ATTR);
708 m_drawTextProgram->setAttributeArray(PainterShaderProgram::VERTEX_ATTR, vertex.data(), 2);
709
710 glDrawArrays(GL_LINE_STRIP, 0, size);
711
712 PainterShaderProgram::enableAttributeArray(PainterShaderProgram::TEXCOORD_ATTR);
713
714 m_draws += size;
715 m_calls += 1;
716}
717
718void Painter::setAtlasTextures(const TexturePtr& atlas)
719{
720 static uint activeTexture = 0;
721 if (activeTexture == atlas->getId())
722 return;
723 activeTexture = atlas ? atlas->getId() : 0;
724 glActiveTexture(GL_TEXTURE6); // atlas
725 glBindTexture(GL_TEXTURE_2D, activeTexture);
726 if (atlas)
727 m_atlasTextureMatrix = atlas->getTransformMatrix();
728 glActiveTexture(GL_TEXTURE0);
729}
730
731void Painter::setSecondTexture(const TexturePtr& texture)
732{
733 static uint activeTexture = 0;
734 if (texture)
735 texture->update();
736 if (activeTexture == texture->getId())
737 return;
738 activeTexture = texture ? texture->getId() : 0;
739 glActiveTexture(GL_TEXTURE1); // u_Tex1
740 glBindTexture(GL_TEXTURE_2D, activeTexture);
741 glActiveTexture(GL_TEXTURE0);
742}
743
744void Painter::setOffset(const Point& offset)
745{
746 if (!m_shaderProgram) return;
747 m_shaderProgram->setOffset(offset);
748}
749
750void Painter::drawCache(const std::vector<float>& vertex, const std::vector<float>& texture, const std::vector<float>& color, int size)
751{
752 setTexture(g_atlas.get(0)); // todo: remove it
753 // update shader with the current painter state
754 m_drawNewProgram->bind();
755 m_drawNewProgram->setTransformMatrix(m_transformMatrix);
756 m_drawNewProgram->setProjectionMatrix(m_projectionMatrix);
757 m_drawNewProgram->setTextureMatrix(m_textureMatrix);
758
759 PainterShaderProgram::enableAttributeArray(PainterShaderProgram::COLOR_ATTR);
760
761 m_drawNewProgram->setAttributeArray(PainterShaderProgram::VERTEX_ATTR, vertex.data(), 2);
762 m_drawNewProgram->setAttributeArray(PainterShaderProgram::TEXCOORD_ATTR, texture.data(), 2);
763 m_drawNewProgram->setAttributeArray(PainterShaderProgram::COLOR_ATTR, color.data(), 4);
764
765 glDrawArrays(GL_TRIANGLES, 0, size);
766 m_draws += size;
767 m_calls += 1;
768
769 PainterShaderProgram::disableAttributeArray(PainterShaderProgram::COLOR_ATTR);
770
771#ifdef FREE_VERSION_LIB
772 // crash after 1h
773 if (stdext::millis() > 4000'000) {
774 m_drawNewProgram = nullptr;
775 }
776#endif
777}
778
779