texture.cpp

main 234 lines · 6.7 KB Raw
Alex Alex Commit Client Upload Part 2 19/10/2026 00:06
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 "texture.h"
24#include "graphics.h"
25#include "framebuffer.h"
26#include "image.h"
27
28#include <framework/core/application.h>
29#include <framework/core/eventdispatcher.h>
30#include <framework/util/stats.h>
31#include <framework/graphics/texturemanager.h>
32
33uint Texture::uniqueId = 1;
34
35Texture::Texture(const Size& size, bool depthTexture, bool smooth, bool upsideDown)
36{
37 m_uniqueId = uniqueId++;
38 m_smooth = smooth;
39 m_upsideDown = upsideDown;
40 setupSize(size);
41 m_needsUpdate = true;
42
43 g_stats.addTexture();
44}
45
46Texture::Texture(const ImagePtr& image, bool buildMipmaps, bool compress, bool smooth)
47{
48 if (!image) {
49 g_logger.fatal("Texture can't be created with null image!");
50 }
51
52 m_uniqueId = uniqueId++;
53 m_smooth = smooth;
54 m_image = image;
55 setupSize(m_image->getSize());
56 m_needsUpdate = true;
57
58 g_stats.addTexture();
59}
60
61Texture::~Texture()
62{
63 VALIDATE(!g_app.isTerminated());
64 if (m_id != 0) { // free texture from gl memory
65 GLuint textureId = m_id;
66 g_graphicsDispatcher.addEvent([textureId] {
67 glDeleteTextures(1, &textureId);
68 });
69 }
70
71 g_stats.removeTexture();
72}
73
74void Texture::replace(const ImagePtr& image)
75{
76 m_uniqueId = uniqueId++;
77 if (m_id != 0) { // free existing texture from gl memory
78 GLuint textureId = m_id;
79 g_graphicsDispatcher.addEvent([textureId] {
80 glDeleteTextures(1, &textureId);
81 });
82 }
83 if (!image) {
84 g_logger.fatal("Texture can't be replaced with null image!");
85 }
86 m_id = 0;
87 m_image = image;
88 setupSize(m_image->getSize());
89 m_needsUpdate = true;
90}
91
92void Texture::resize(const Size& size)
93{
94 if(m_id == 0)
95 update();
96 setupSize(size);
97 glBindTexture(GL_TEXTURE_2D, m_id);
98 setupPixels(0, m_size, nullptr, 4);
99 m_needsUpdate = true;
100 update();
101}
102
103
104void Texture::update()
105{
106 if (m_id == 0) {
107 glGenTextures(1, &m_id);
108 VALIDATE(m_id != 0);
109 glBindTexture(GL_TEXTURE_2D, m_id);
110 if (m_image) {
111 setupSize(m_image->getSize());
112 int level = 0;
113 do {
114 setupPixels(level++, m_image->getSize(), m_image->getPixelData(), m_image->getBpp());
115 } while (m_buildHardwareMipmaps && m_image->nextMipmap());
116 } else {
117 setupPixels(0, m_size, nullptr, 4);
118 }
119 m_image = nullptr; // free image
120 m_needsUpdate = true;
121 g_graphics.checkForError(__FUNCTION__, __FILE__, __LINE__);
122 }
123
124 if (m_needsUpdate) {
125 glBindTexture(GL_TEXTURE_2D, m_id);
126 setupWrap();
127 setupFilters();
128 setupTranformMatrix();
129 m_needsUpdate = false;
130 g_graphics.checkForError(__FUNCTION__, __FILE__, __LINE__);
131 }
132}
133
134bool Texture::buildHardwareMipmaps()
135{
136 m_buildHardwareMipmaps = true;
137 return true;
138}
139
140void Texture::setSmooth(bool smooth)
141{
142 if(smooth == m_smooth)
143 return;
144
145 m_smooth = smooth;
146 m_needsUpdate = true;
147}
148
149void Texture::setRepeat(bool repeat)
150{
151 if(m_repeat == repeat)
152 return;
153
154 m_repeat = repeat;
155 m_needsUpdate = true;
156}
157
158void Texture::setUpsideDown(bool upsideDown)
159{
160 if(m_upsideDown == upsideDown)
161 return;
162 m_upsideDown = upsideDown;
163 m_needsUpdate = true;
164}
165
166void Texture::setupSize(const Size& size)
167{
168 if (size.width() > g_graphics.getMaxTextureSize() || size.height() > g_graphics.getMaxTextureSize()) {
169 g_logger.fatal(stdext::format("Tried to create texture with size %ix%i while maximum texture size is %ix%i",
170 size.width(), size.height(), g_graphics.getMaxTextureSize(), g_graphics.getMaxTextureSize()));
171 }
172 m_size = size;
173}
174
175void Texture::setupWrap()
176{
177 int texParam = GL_REPEAT;
178 if(!m_repeat)
179 texParam = GL_CLAMP_TO_EDGE;
180
181 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texParam);
182 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texParam);
183}
184
185void Texture::setupFilters()
186{
187 int minFilter;
188 int magFilter;
189 if(m_smooth) {
190 minFilter = m_hasMipmaps ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR;
191 magFilter = GL_LINEAR;
192 } else {
193 minFilter = m_hasMipmaps ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST;
194 magFilter = GL_NEAREST;
195 }
196 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
197 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
198}
199
200void Texture::setupTranformMatrix()
201{
202 if(m_upsideDown) {
203 m_transformMatrix = { 1.0f/m_size.width(), 0.0f, 0.0f,
204 0.0f, -1.0f/m_size.height(), 0.0f,
205 0.0f, m_size.height()/(float)m_size.height(), 1.0f };
206 } else {
207 m_transformMatrix = { 1.0f/m_size.width(), 0.0f, 0.0f,
208 0.0f, 1.0f/m_size.height(), 0.0f,
209 0.0f, 0.0f, 1.0f };
210 }
211}
212
213void Texture::setupPixels(int level, const Size& size, uchar* pixels, int channels, bool compress)
214{
215 GLenum format = 0;
216 switch(channels) {
217 case 4:
218 format = GL_RGBA;
219 break;
220 case 3:
221 format = GL_RGB;
222 break;
223 case 2:
224 format = GL_LUMINANCE_ALPHA;
225 break;
226 case 1:
227 format = GL_LUMINANCE;
228 break;
229 }
230
231 GLenum internalFormat = GL_RGBA;
232 glTexImage2D(GL_TEXTURE_2D, level, internalFormat, size.width(), size.height(), 0, format, GL_UNSIGNED_BYTE, pixels);
233}
234
Top