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 if (!texture)
61 return false;
62
63 // load first pixel color
64 auto pixelcolor = getpixel(surface, 0, 0);
65 CST_GetRGBA(pixelcolor, surface->format, &texFirstPixel);
66
67 // load texture size
68 CST_QueryTexture(texture, &texW, &texH);
69
70 // load texture
71 mTexture = texture;
72
73 return true;
74}
75
76bool Texture::loadFromCache(std::string &key)
77{
78 // check if the texture is cached
79 if (texCache.count(key))
80 {
81 TextureData *texData = &texCache[key];
82 mTexture = texData->texture;
83 texFirstPixel = texData->firstPixel;
84 CST_QueryTexture(mTexture, &texW, &texH);
85 return true;
86 }
87
88 return false;
89}
90
91bool Texture::loadFromSurfaceSaveToCache(std::string &key, CST_Surface *surface)
92{
93 bool success = loadFromSurface(surface);
94
95 // only save to caches if loading was successful
96 // and the texture isn't already cached
97 if (success && !texCache.count(key))
98 {
99 TextureData texData;
100 texData.texture = mTexture;
101 texData.firstPixel = texFirstPixel;
102 texCache[key] = texData;
103 }
104
105 return success;
106}
107
109{
110 // update xAbs and yAbs
112
113 if (!mTexture)
114 return;
115
116 if (hidden)
117 return;
118
119 // rect of element's size
120 CST_Rect rect;
121 rect.x = this->xAbs;
122 rect.y = this->yAbs;
123 rect.w = this->width;
124 rect.h = this->height;
125
126 if (CST_isRectOffscreen(&rect))
127 return;
128
129 CST_Renderer* renderer = getRenderer();
130
131 if (texScaleMode == SCALE_PROPORTIONAL_WITH_BG)
132 {
133 CST_SetDrawBlend(RootDisplay::renderer, false);
134
135 // draw colored background
136 CST_SetDrawColor(renderer, texFirstPixel);
137 auto color = (CST_Color){texFirstPixel.r, texFirstPixel.g, texFirstPixel.b, 0xFF};
138
139 // if the first pixel is transparent, use white
140 if (texFirstPixel.a == 0)
141 color = (CST_Color){0xFF,0xFF,0xFF,0xFF};
142
143 CST_SetDrawColor(renderer, color);
144 CST_FillRect(renderer, &rect);
145
146 // recompute drawing rect
147 if ((width * texH) > (height * texW))
148 {
149 // keep height, scale width
150 rect.h = height;
151 rect.w = (texW * rect.h) / texH;
152 }
153 else
154 {
155 // keep width, scale height
156 rect.w = width;
157 rect.h = (texH * rect.w) / texW;
158 }
159
160 // center the texture
161 rect.x += (width - rect.w) / 2;
162 rect.y += (height - rect.h) / 2;
163 }
164
165 if (angle != 0) {
166 // render the texture with a rotation
167 CST_SetQualityHint("best");
168 CST_RenderCopyRotate(renderer, mTexture, NULL, &rect, this->angle);
169 }
170 else if (useColorMask) {
171 // render the texture with a mask color (only can darken the texture)
172 SDL_SetTextureColorMod(mTexture, maskColor.r, maskColor.g, maskColor.b);
173 CST_RenderCopy(renderer, mTexture, NULL, &rect);
174 SDL_SetTextureColorMod(mTexture, 0xFF, 0xFF, 0xFF);
175 } else {
176 // render the texture normally
177 CST_RenderCopy(renderer, mTexture, NULL, &rect);
178 }
179}
180
181void Texture::resize(int w, int h)
182{
183 width = w;
184 height = h;
185}
186
187Texture* Texture::setSize(int w, int h)
188{
189 this->resize(w, h);
190 return this;
191}
192
193void Texture::setScaleMode(TextureScaleMode mode)
194{
195 texScaleMode = mode;
196}
197
198void Texture::getTextureSize(int *w, int *h)
199{
200 if (w)
201 *w = texW;
202 if (h)
203 *h = texH;
204}
205
206bool Texture::saveTo(std::string &path)
207{
208 if (!mTexture)
209 return false;
210
211 // render the texture to one that can be saved (TARGET ACCESS)
212 CST_Texture* target = SDL_CreateTexture(getRenderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, texW, texH);
213 if (!target)
214 return false;
215
216 // set the target texture
217 SDL_SetRenderTarget(getRenderer(), target);
218
219 // render the texture
220 SDL_RenderCopy(getRenderer(), mTexture, NULL, NULL);
221
222 // reset the target texture
223 SDL_SetRenderTarget(getRenderer(), NULL);
224
225
226 // save the surface to the path
227 return CST_SavePNG(target, path.c_str());
228}
229
230void Texture::loadPath(std::string& path, bool forceReload) {
231 if (forceReload || !loadFromCache(path))
232 {
233 CST_Surface *surface = IMG_Load(path.c_str());
234 loadFromSurfaceSaveToCache(path, surface);
235 CST_FreeSurface(surface);
236 }
237
238 width = texW;
239 height = texH;
240}
bool hidden
whether this element should skip rendering or not
Definition: Element.hpp:105
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:172
double angle
rotation angle in degrees
Definition: Element.hpp:128
CST_Color maskColor
The color to overlay on top.
Definition: Element.hpp:175
int width
width and height of this element (must be manually set, isn't usually calculated (but is in some case...
Definition: Element.hpp:118
Element * parent
the parent element (can sometimes be null if it isn't set)
Definition: Element.hpp:102
void getTextureSize(int *w, int *h)
Return texture's original size.
Definition: Texture.cpp:198
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:91
static std::unordered_map< std::string, TextureData > texCache
Cache previously displayed textures.
Definition: Texture.hpp:70
CST_Color texFirstPixel
The color of the first pixel.
Definition: Texture.hpp:79
int texW
The size of the texture.
Definition: Texture.hpp:76
void resize(int w, int h)
Resizes the texture.
Definition: Texture.cpp:181
bool loadFromCache(std::string &key)
Loads the texture from caches Returns true if successful.
Definition: Texture.cpp:76
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:108
bool saveTo(std::string &path)
save this texture to the given file path as a PNG
Definition: Texture.cpp:206
void setScaleMode(TextureScaleMode mode)
Sets texture scaling mode.
Definition: Texture.cpp:193
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:82
void loadPath(std::string &path, bool forceReload=false)
update and load or reload the texture
Definition: Texture.cpp:230
CST_Texture * mTexture
The actual texture.
Definition: Texture.hpp:73