Chesto 0.9
A declarative and element-based library for creating GUIs on homebrew'd consoles
Texture.cpp
1#include "Texture.hpp"
2
3namespace Chesto {
4
5std::unordered_map<std::string, TextureData> Texture::texCache;
6
7const std::string Texture::textElemPrefix = "(TextElement):";
8
9Texture::~Texture()
10{
11}
12
14{
15 mTexture = nullptr;
16 texW = 0;
17 texH = 0;
18 texFirstPixel = (CST_Color){0,0,0,0};
19}
20
21// https://stackoverflow.com/a/53067795
22Uint32 getpixel(CST_Surface *surface, int x, int y)
23{
24 int bpp = surface->format->BytesPerPixel;
25 /* Here p is the address to the pixel we want to retrieve */
26 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
27
28switch (bpp)
29{
30 case 1:
31 return *p;
32 break;
33
34 case 2:
35 return *(Uint16 *)p;
36 break;
37
38 case 3:
39 if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
40 return p[0] << 16 | p[1] << 8 | p[2];
41 else
42 return p[0] | p[1] << 8 | p[2] << 16;
43 break;
44
45 case 4:
46 return *(Uint32 *)p;
47 break;
48
49 default:
50 return 0; /* shouldn't happen, but avoids warnings */
51 }
52}
53
54bool Texture::loadFromSurface(CST_Surface *surface)
55{
56 if (!surface)
57 return false;
58
59 // will default MainDisplay's renderer if we don't have one in this->renderer
60 CST_Renderer* renderer = getRenderer();
61
62 // try to create a texture from the surface
63 CST_Texture *texture = CST_CreateTextureFromSurface(renderer, surface, true);
64 SDL_SetTextureBlendMode(texture, blendMode);
65 if (!texture)
66 return false;
67
68 // load first pixel color
69 auto pixelcolor = getpixel(surface, 0, 0);
70 CST_GetRGBA(pixelcolor, surface->format, &texFirstPixel);
71
72 // load texture size
73 CST_QueryTexture(texture, &texW, &texH);
74
75 // load texture
76 mTexture = texture;
77
78 return true;
79}
80
81bool Texture::loadFromCache(std::string &key)
82{
83 // check if the texture is cached
84 if (texCache.count(key))
85 {
86 TextureData *texData = &texCache[key];
87 mTexture = texData->texture;
88 texFirstPixel = texData->firstPixel;
89 CST_QueryTexture(mTexture, &texW, &texH);
90 return true;
91 }
92
93 return false;
94}
95
96bool Texture::loadFromSurfaceSaveToCache(std::string &key, CST_Surface *surface)
97{
98 bool success = loadFromSurface(surface);
99
100 // only save to caches if loading was successful
101 // and the texture isn't already cached
102 if (success && !texCache.count(key))
103 {
104 TextureData texData;
105 texData.texture = mTexture;
106 texData.firstPixel = texFirstPixel;
107 texCache[key] = texData;
108 }
109
110 return success;
111}
112
114{
115 texCache.clear();
116}
117
119{
120 for (auto it = texCache.begin(); it != texCache.end(); )
121 {
122 std::string key = it->first;
123 if (key.find(Texture::textElemPrefix) == 0) { // does the key start with our text prefix?
124 it = texCache.erase(it);
125 } else {
126 ++it;
127 }
128 }
129}
130
132{
133 // update xAbs and yAbs
135
136 if (!mTexture)
137 return;
138
139 if (hidden)
140 return;
141
142 float effectiveScale = getEffectiveScale();
143
144 // rect of element's size (scaled)
145 CST_Rect rect;
146 rect.x = this->xAbs;
147 rect.y = this->yAbs;
148 rect.w = (int)(this->width * effectiveScale);
149 rect.h = (int)(this->height * effectiveScale);
150
151 if (CST_isRectOffscreen(&rect))
152 return;
153
154 CST_Renderer* renderer = getRenderer();
155
156 if (texScaleMode == SCALE_PROPORTIONAL_WITH_BG || texScaleMode == SCALE_PROPORTIONAL_NO_BG)
157 {
158 CST_SetDrawBlend(RootDisplay::renderer, false);
159
160 // draw colored background
161 if (texScaleMode == SCALE_PROPORTIONAL_WITH_BG)
162 {
163 CST_SetDrawColor(renderer, texFirstPixel);
164 auto color = (CST_Color){ texFirstPixel.r, texFirstPixel.g, texFirstPixel.b, 0xFF };
165
166 // if the first pixel is transparent, use the background color
167 if (texFirstPixel.a == 0) {
168 auto r = (Uint8)(backgroundColor.r * 0xff);
169 auto g = (Uint8)(backgroundColor.g * 0xff);
170 auto b = (Uint8)(backgroundColor.b * 0xff);
171 color = (CST_Color){ r, g, b, 0xFF };
172 }
173
174 CST_roundedBoxRGBA(renderer, rect.x, rect.y, rect.x + rect.w, rect.y + rect.h, cornerRadius,
175 color.r, color.g, color.b, 0xFF);
176 }
177
178 // recompute drawing rect
179 if ((width * texH) > (height * texW))
180 {
181 // keep height, scale width
182 rect.h = height;
183 rect.w = (texW * rect.h) / texH;
184 }
185 else
186 {
187 // keep width, scale height
188 rect.w = width;
189 rect.h = (texH * rect.w) / texW;
190 }
191
192 // center the texture
193 rect.x += (width - rect.w) / 2;
194 rect.y += (height - rect.h) / 2;
195 }
196
197 if (angle != 0) {
198 // render the texture with a rotation
199 CST_SetQualityHint("best");
200 CST_RenderCopyRotate(renderer, mTexture, NULL, &rect, this->angle);
201 }
202 else if (useColorMask) {
203 // render the texture with a mask color (only can darken the texture)
204 SDL_SetTextureColorMod(mTexture, maskColor.r, maskColor.g, maskColor.b);
205 CST_RenderCopy(renderer, mTexture, NULL, &rect);
206 SDL_SetTextureColorMod(mTexture, 0xFF, 0xFF, 0xFF);
207 } else {
208 // render the texture normally
209 CST_RenderCopy(renderer, mTexture, NULL, &rect);
210 }
211}
212
213void Texture::resize(int w, int h)
214{
215 width = w;
216 height = h;
217}
218
219Texture* Texture::setSize(int w, int h)
220{
221 this->resize(w, h);
222 return this;
223}
224
225void Texture::setScaleMode(TextureScaleMode mode)
226{
227 texScaleMode = mode;
228}
229
230void Texture::getTextureSize(int *w, int *h)
231{
232 if (w)
233 *w = texW;
234 if (h)
235 *h = texH;
236}
237
238bool Texture::saveTo(std::string &path)
239{
240 if (!mTexture)
241 return false;
242
243 // render the texture to one that can be saved (TARGET ACCESS)
244 CST_Texture* target = SDL_CreateTexture(getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, texW, texH);
245 if (!target)
246 return false;
247
248 // set the target texture
249 SDL_SetRenderTarget(getRenderer(), target);
250
251 // render the texture
252 SDL_RenderCopy(getRenderer(), mTexture, NULL, NULL);
253
254 // reset the target texture
255 SDL_SetRenderTarget(getRenderer(), NULL);
256
257
258 // save the surface to the path
259 return CST_SavePNG(target, path.c_str());
260}
261
262void Texture::loadPath(std::string& path, bool forceReload) {
263 // Guard against empty paths
264 if (path.empty()) {
265 width = 0;
266 height = 0;
267 return;
268 }
269
270 if (forceReload || !loadFromCache(path))
271 {
272 CST_Surface *surface = IMG_Load(path.c_str());
273 loadFromSurfaceSaveToCache(path, surface);
274 CST_FreeSurface(surface);
275 }
276
277 width = texW;
278 height = texH;
279}
280} // namespace Chesto
double angle
rotation angle in degrees
Definition: Element.hpp:144
int width
width and height of this element (must be manually set, isn't usually calculated (but is in some case...
Definition: Element.hpp:132
virtual void render(Element *parent)
display the current state of the display
Definition: Element.cpp:89
bool hidden
whether this element should skip rendering or not
Definition: Element.hpp:119
CST_Color maskColor
The color to overlay on top.
Definition: Element.hpp:193
Element * parent
the parent element (reference only, not owned)
Definition: Element.hpp:116
bool useColorMask
whether or not to overlay a color mask on top of this element
Definition: Element.hpp:190
int cornerRadius
Rounded corner radius (if >0, will round)
Definition: Texture.hpp:71
static void wipeEntireCache()
Wipes the entire texture cache (generally, should only be used to reload entire theme / text)
Definition: Texture.cpp:113
TextureScaleMode texScaleMode
Texture's scaling mode.
Definition: Texture.hpp:99
bool loadFromSurfaceSaveToCache(std::string &key, CST_Surface *surface)
Loads the texture from a surface and saves the results in caches Returns true if successful.
Definition: Texture.cpp:96
void resize(int w, int h)
Resizes the texture.
Definition: Texture.cpp:213
void loadPath(std::string &path, bool forceReload=false)
update and load or reload the texture
Definition: Texture.cpp:262
void clear(void)
Reinitialize Texture Resets texture content, size and color.
Definition: Texture.cpp:13
void setScaleMode(TextureScaleMode mode)
Sets texture scaling mode.
Definition: Texture.cpp:225
static void wipeTextCache()
Similar to wipeEntireCache, but only wipes cached text textures (made by TextElement)
Definition: Texture.cpp:118
bool loadFromSurface(CST_Surface *surface)
Loads the texture from a surface Returns true if successful.
Definition: Texture.cpp:54
bool saveTo(std::string &path)
save this texture to the given file path as a PNG
Definition: Texture.cpp:238
int texW
The size of the texture.
Definition: Texture.hpp:93
static std::unordered_map< std::string, TextureData > texCache
Cache previously displayed textures.
Definition: Texture.hpp:87
bool loadFromCache(std::string &key)
Loads the texture from caches Returns true if successful.
Definition: Texture.cpp:81
SDL_BlendMode blendMode
Blend mode to use for this texture.
Definition: Texture.hpp:74
CST_Color texFirstPixel
The color of the first pixel.
Definition: Texture.hpp:96
void render(Element *parent)
Renders the texture.
Definition: Texture.cpp:131
void getTextureSize(int *w, int *h)
Return texture's original size.
Definition: Texture.cpp:230
CST_Texture * mTexture
The actual texture.
Definition: Texture.hpp:90