FifeGUI 0.2.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#include "fifechan/backends/opengl/image.hpp"
6
7#include <string>
8
9#include "fifechan/exception.hpp"
10
11namespace fcn::opengl
12{
13 Image::Image(std::span<unsigned int const> pixels, int width, int height, bool convertToDisplayFormat) :
14 mTextureHandle(0), mAutoFree(true), mWidth(width), mHeight(height), mTextureWidth(1), mTextureHeight(1)
15 {
16 while (mTextureWidth < mWidth) {
17 mTextureWidth *= 2;
18 }
19
20 while (mTextureHeight < mHeight) {
21 mTextureHeight *= 2;
22 }
23
24 // Create a new pixel buffer and copy the pixels into it.
25 mPixels.resize(static_cast<size_t>(mTextureWidth) * static_cast<size_t>(mTextureHeight));
26
27#ifdef __BIG_ENDIAN__
28 unsigned int const magicPink = 0xff00ffff;
29#else
30 unsigned int const magicPink = 0xffff00ff;
31#endif
32 for (int y = 0; y < mTextureHeight; ++y) {
33 for (int x = 0; x < mTextureWidth; ++x) {
34 if (x < mWidth && y < mHeight) {
35 unsigned int c = pixels[x + (y * mWidth)];
36
37 // Magic pink to transparent
38 if (c == magicPink) {
39 c = 0x00000000;
40 }
41
42 mPixels[x + (y * mTextureWidth)] = c;
43 } else {
44 mPixels[x + (y * mTextureWidth)] = 0x00000000;
45 }
46 }
47 }
48
51 }
52 }
53
54 Image::Image(GLuint textureHandle, int width, int height, bool autoFree) :
55 mTextureHandle(textureHandle),
56 mAutoFree(autoFree),
57 mWidth(width),
58 mHeight(height),
61 {
62 mPixels.clear();
63
64 while (mTextureWidth < mWidth) {
65 mTextureWidth *= 2;
66 }
67
68 while (mTextureHeight < mHeight) {
69 mTextureHeight *= 2;
70 }
71 }
72
73 Image::~Image()
74 {
75 if (mAutoFree) {
76 if (mPixels.empty()) {
77 glDeleteTextures(1, &mTextureHandle);
78 } else {
79 mPixels.clear();
80 }
81 }
82 }
83
85 {
86 return mTextureHandle;
87 }
88
90 {
91 return mTextureWidth;
92 }
93
95 {
96 return mTextureHeight;
97 }
98
100 {
101 if (mPixels.empty()) {
102 glDeleteTextures(1, &mTextureHandle);
103 } else {
104 mPixels.clear();
105 }
106 }
107
108 int Image::getWidth() const
109 {
110 return mWidth;
111 }
112
114 {
115 return mHeight;
116 }
117
118 Color Image::getPixel(int x, int y)
119 {
120 if (mPixels.empty()) {
121 throwException("Image has been converted to display format");
122 }
123
124 if (x < 0 || x >= mWidth || y < 0 || y >= mHeight) {
125 throwException("Coordinates outside of the image");
126 }
127
128 unsigned int const c = mPixels[x + (y * mTextureWidth)];
129
130#ifdef __BIG_ENDIAN__
131 auto const r = static_cast<unsigned char>((c >> 24) & 0xff);
132 auto const g = static_cast<unsigned char>((c >> 16) & 0xff);
133 auto const b = static_cast<unsigned char>((c >> 8) & 0xff);
134 auto const a = static_cast<unsigned char>(c & 0xff);
135#else
136 auto const a = static_cast<unsigned char>((c >> 24) & 0xff);
137 auto const b = static_cast<unsigned char>((c >> 16) & 0xff);
138 auto const g = static_cast<unsigned char>((c >> 8) & 0xff);
139 auto const r = static_cast<unsigned char>(c & 0xff);
140#endif
141
142 return {r, g, b, a};
143 }
144
145 void Image::putPixel(int x, int y, Color const & color)
146 {
147 if (mPixels.empty()) {
148 throwException("Image has been converted to display format");
149 }
150
151 if (x < 0 || x >= mWidth || y < 0 || y >= mHeight) {
152 throwException(("Coordinates outside of the image"));
153 }
154
155#ifdef __BIG_ENDIAN__
156 const unsigned int c = color.a | color.b << 8 | color.g << 16 | color.r << 24;
157#else
158 const unsigned int c = color.r | color.g << 8 | color.b << 16 | color.a << 24;
159#endif
160
161 mPixels[x + (y * mTextureWidth)] = c;
162 }
163
165 {
166 if (mPixels.empty()) {
167 throwException("Image has already been converted to display format");
168 }
169
170 glGenTextures(1, &mTextureHandle);
171 glBindTexture(GL_TEXTURE_2D, mTextureHandle);
172
173 glTexImage2D(GL_TEXTURE_2D, 0, 4, mTextureWidth, mTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, mPixels.data());
174
175 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
176 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
177
178 mPixels.clear();
179
180 GLenum const error = glGetError();
181 if (error != GL_NO_ERROR) {
182 std::string errmsg;
183 switch (error) {
184 case GL_INVALID_ENUM:
185 errmsg = "GL_INVALID_ENUM";
186 break;
187
188 case GL_INVALID_VALUE:
189 errmsg = "GL_INVALID_VALUE";
190 break;
191
192 case GL_INVALID_OPERATION:
193 errmsg = "GL_INVALID_OPERATION";
194 break;
195
196 case GL_STACK_OVERFLOW:
197 errmsg = "GL_STACK_OVERFLOW";
198 break;
199
200 case GL_STACK_UNDERFLOW:
201 errmsg = "GL_STACK_UNDERFLOW";
202 break;
203
204 case GL_OUT_OF_MEMORY:
205 errmsg = "GL_OUT_OF_MEMORY";
206 break;
207 default:
208 errmsg = "UNKNOWN_ERROR";
209 break;
210 }
211 throwException(std::string("Unable to convert to OpenGL display format, glGetError said: ") + errmsg);
212 }
213 }
214} // namespace fcn::opengl
Color.
Definition color.hpp:56
uint8_t a
Alpha color component (0-255).
Definition color.hpp:322
uint8_t b
Blue color component (0-255).
Definition color.hpp:319
uint8_t g
Green color component (0-255).
Definition color.hpp:316
uint8_t r
Red color component (0-255).
Definition color.hpp:313
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.