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