FifeGUI 0.3.0
A C++ GUI library designed for games.
backends/opengl/image.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later OR BSD-3-Clause
2// SPDX-FileCopyrightText: 2004 - 2008 Olof Naessén and Per Larsson
3// SPDX-FileCopyrightText: 2013 - 2026 Fifengine contributors
4
5// Corresponding header include
6#include "fifechan/backends/opengl/image.hpp"
7
8// Standard library includes
9#include <string>
10
11// Project headers (subdirs before local)
12#include "fifechan/exception.hpp"
13
14namespace fcn::opengl
15{
16 Image::Image(std::span<unsigned int const> pixels, int width, int height, bool convertToDisplayFormat) :
17 mTextureHandle(0), mAutoFree(true), mWidth(width), mHeight(height), mTextureWidth(1), mTextureHeight(1)
18 {
19 while (mTextureWidth < mWidth) {
20 mTextureWidth *= 2;
21 }
22
23 while (mTextureHeight < mHeight) {
24 mTextureHeight *= 2;
25 }
26
27 // Create a new pixel buffer and copy the pixels into it.
28 mPixels.resize(static_cast<size_t>(mTextureWidth) * static_cast<size_t>(mTextureHeight));
29
30#ifdef __BIG_ENDIAN__
31 unsigned int const magicPink = 0xff00ffff;
32#else
33 unsigned int const magicPink = 0xffff00ff;
34#endif
35 for (int y = 0; y < mTextureHeight; ++y) {
36 for (int x = 0; x < mTextureWidth; ++x) {
37 if (x < mWidth && y < mHeight) {
38 unsigned int c = pixels[static_cast<size_t>(x + (y * mWidth))];
39
40 // Magic pink to transparent
41 if (c == magicPink) {
42 c = 0x00000000;
43 }
44
45 mPixels.at(static_cast<size_t>(x + (y * mTextureWidth))) = c;
46 } else {
47 mPixels.at(static_cast<size_t>(x + (y * mTextureWidth))) = 0x00000000;
48 }
49 }
50 }
51
54 }
55 }
56
57 Image::Image(GLuint textureHandle, int width, int height, bool autoFree) :
58 mTextureHandle(textureHandle),
59 mAutoFree(autoFree),
60 mWidth(width),
61 mHeight(height),
64 {
65 mPixels.clear();
66
67 while (mTextureWidth < mWidth) {
68 mTextureWidth *= 2;
69 }
70
71 while (mTextureHeight < mHeight) {
72 mTextureHeight *= 2;
73 }
74 }
75
76 Image::~Image()
77 {
78 if (mAutoFree) {
79 if (mPixels.empty()) {
80 glDeleteTextures(1, &mTextureHandle);
81 } else {
82 mPixels.clear();
83 }
84 }
85 }
86
88 {
89 return mTextureHandle;
90 }
91
93 {
94 return mTextureWidth;
95 }
96
98 {
99 return mTextureHeight;
100 }
101
103 {
104 if (mPixels.empty()) {
105 glDeleteTextures(1, &mTextureHandle);
106 } else {
107 mPixels.clear();
108 }
109 }
110
111 int Image::getWidth() const
112 {
113 return mWidth;
114 }
115
117 {
118 return mHeight;
119 }
120
121 Color Image::getPixel(int x, int y)
122 {
123 if (mPixels.empty()) {
124 throwException("Image has been converted to display format");
125 }
126
127 if (x < 0 || x >= mWidth || y < 0 || y >= mHeight) {
128 throwException("Coordinates outside of the image");
129 }
130
131 unsigned int const c = mPixels.at(static_cast<size_t>(x + (y * mTextureWidth)));
132
133#ifdef __BIG_ENDIAN__
134 auto const r = static_cast<unsigned char>((c >> 24) & 0xff);
135 auto const g = static_cast<unsigned char>((c >> 16) & 0xff);
136 auto const b = static_cast<unsigned char>((c >> 8) & 0xff);
137 auto const a = static_cast<unsigned char>(c & 0xff);
138#else
139 auto const a = static_cast<unsigned char>((c >> 24) & 0xff);
140 auto const b = static_cast<unsigned char>((c >> 16) & 0xff);
141 auto const g = static_cast<unsigned char>((c >> 8) & 0xff);
142 auto const r = static_cast<unsigned char>(c & 0xff);
143#endif
144
145 return {r, g, b, a};
146 }
147
148 void Image::putPixel(int x, int y, Color const & color)
149 {
150 if (mPixels.empty()) {
151 throwException("Image has been converted to display format");
152 }
153
154 if (x < 0 || x >= mWidth || y < 0 || y >= mHeight) {
155 throwException("Coordinates outside of the image");
156 }
157
158#ifdef __BIG_ENDIAN__
159 unsigned int const c = color.a | color.b << 8 | color.g << 16 | color.r << 24;
160#else
161 unsigned int const c = color.r | color.g << 8 | color.b << 16 | color.a << 24;
162#endif
163
164 mPixels.at(static_cast<size_t>(x + (y * mTextureWidth))) = c;
165 }
166
168 {
169 if (mPixels.empty()) {
170 throwException("Image has already been converted to display format");
171 }
172
173 glGenTextures(1, &mTextureHandle);
174 glBindTexture(GL_TEXTURE_2D, mTextureHandle);
175
176 glTexImage2D(GL_TEXTURE_2D, 0, 4, mTextureWidth, mTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, mPixels.data());
177
178 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
179 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
180
181 mPixels.clear();
182
183 GLenum const error = glGetError();
184 if (error != GL_NO_ERROR) {
185 std::string errmsg;
186 switch (error) {
187 case GL_INVALID_ENUM:
188 errmsg = "GL_INVALID_ENUM";
189 break;
190
191 case GL_INVALID_VALUE:
192 errmsg = "GL_INVALID_VALUE";
193 break;
194
195 case GL_INVALID_OPERATION:
196 errmsg = "GL_INVALID_OPERATION";
197 break;
198
199 case GL_STACK_OVERFLOW:
200 errmsg = "GL_STACK_OVERFLOW";
201 break;
202
203 case GL_STACK_UNDERFLOW:
204 errmsg = "GL_STACK_UNDERFLOW";
205 break;
206
207 case GL_OUT_OF_MEMORY:
208 errmsg = "GL_OUT_OF_MEMORY";
209 break;
210 default:
211 errmsg = "UNKNOWN_ERROR";
212 break;
213 }
214 throwException(std::string("Unable to convert to OpenGL display format, glGetError said: ") + errmsg);
215 }
216 }
217} // namespace fcn::opengl
Color.
Definition color.hpp:58
uint8_t a
Alpha color component (0-255).
Definition color.hpp:350
uint8_t b
Blue color component (0-255).
Definition color.hpp:347
uint8_t g
Green color component (0-255).
Definition color.hpp:344
uint8_t r
Red color component (0-255).
Definition color.hpp:341
int getWidth() const override
Gets the width of the image.
bool mAutoFree
Whether the texture handle should be freed on destruction.
int getHeight() const override
Gets the height of the image.
void free() override
Frees an image.
void convertToDisplayFormat() override
Converts the image, if possible, to display format.
int mWidth
Logical image width in pixels.
virtual GLuint getTextureHandle() const
Gets the OpenGL texture handle for the image.
virtual int getTextureWidth() const
Gets the width of texture.
void putPixel(int x, int y, Color const &color) override
Puts a pixel with a certain color at coordinate (x, y).
int mTextureHeight
Actual texture height (power-of-two) used by GL.
Color getPixel(int x, int y) override
Gets the color of a pixel at coordinate (x, y) in the image.
GLuint mTextureHandle
OpenGL texture handle backing this image (if any).
int mTextureWidth
Actual texture width (power-of-two) used by GL.
Image(std::span< unsigned int const > pixels, int width, int height, bool convertToDisplayFormat=true)
Constructor.
virtual int getTextureHeight() const
Gets the height of the texture.
std::vector< unsigned int > mPixels
Pixel buffer copy for the image (RGBA packed).
int mHeight
Logical image height in pixels.
void throwException(std::string const &message, std::source_location location=std::source_location::current())
Throw an Exception capturing the current source location.