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
35Graphics g_graphics;
36
37Graphics::Graphics()
38{
39 m_maxTextureSize = 2048;
40}
41
42void 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
107void 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
124void 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
132void 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
148void 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}
160