11 #include "font_cache.hpp"
12 #include "texture.hpp"
13 #include <renderer_sdl.hpp>
16 void cache_font(TTF_Font *Font, uint16_t font_and_size);
18 void process_surfaces(std::vector<std::pair<uint16_t, SDL_Surface *>> &surfaces_pairs);
21 static const uint16_t ATLAS_SIZE = 4096;
22 static const uint16_t atlas_grid_size = ATLAS_SIZE / 32;
25 SDL_Renderer *sdl_renderer;
27 static SDL_Renderer *sdl_renderer;
31 static SDL_Window *window;
35 static int16_t height;
39 ska::bytell_hash_map<uint16_t, ST::renderer_sdl::texture> textures{};
41 static ska::bytell_hash_map<uint16_t, ST::renderer_sdl::texture> textures{};
44 static ska::bytell_hash_map<uint16_t, SDL_Surface *> *surfaces_pointer;
45 static ska::bytell_hash_map<uint16_t, TTF_Font *> *fonts_pointer;
50 static ska::bytell_hash_map<uint16_t, TTF_Font *> fonts{};
53 static ska::bytell_hash_map<uint16_t, std::vector<ST::renderer_sdl::texture>> fonts_cache{};
55 static bool vsync =
false;
57 static bool singleton_initialized =
false;
67 font_cache::set_max(100);
69 if (singleton_initialized) {
70 throw std::runtime_error(
"The renderer cannot be initialized more than once!");
72 singleton_initialized =
true;
80 sdl_renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE |
81 SDL_RENDERER_PRESENTVSYNC);
83 sdl_renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
85 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
86 SDL_SetRenderDrawBlendMode(sdl_renderer, SDL_BLENDMODE_BLEND);
87 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY,
"2");
96 for (
auto &it: fonts) {
97 if (it.second !=
nullptr) {
98 if (fonts[it.first] !=
nullptr) {
99 for (
auto &k: fonts_cache[it.first]) {
100 if (k.atlas !=
nullptr) {
101 SDL_DestroyTexture(k.atlas);
105 fonts[it.first] =
nullptr;
110 for (
auto &it: textures) {
111 if (it.second.atlas !=
nullptr) {
112 SDL_DestroyTexture(it.second.atlas);
113 it.second.atlas =
nullptr;
118 SDL_DestroyRenderer(sdl_renderer);
119 sdl_renderer =
nullptr;
120 singleton_initialized =
false;
137 TTF_Font *_font = fonts[font];
139 if (_font !=
nullptr) [[likely]] {
141 SDL_Texture *cached_texture = font_cache::get_cached_string(arg2, font);
142 if (cached_texture !=
144 SDL_QueryTexture(cached_texture,
nullptr,
nullptr, &texW, &texH);
145 SDL_Rect Rect = {x, y - texH, texW, texH};
146 SDL_SetTextureColorMod(cached_texture, color_font.r, color_font.g, color_font.b);
147 SDL_RenderCopy(sdl_renderer, cached_texture,
nullptr, &Rect);
149 SDL_Surface *
text = TTF_RenderUTF8_Blended(_font, arg2.c_str(), color_font);
150 SDL_Texture *
texture = SDL_CreateTextureFromSurface(sdl_renderer,
text);
151 SDL_QueryTexture(
texture,
nullptr,
nullptr, &texW, &texH);
152 SDL_Rect Rect = {x, y - texH, texW, texH};
153 SDL_SetTextureColorMod(
texture, color_font.r, color_font.g, color_font.b);
154 SDL_RenderCopy(sdl_renderer,
texture,
nullptr, &Rect);
155 SDL_FreeSurface(
text);
156 font_cache::cache_string(arg2,
texture, font);
159 return static_cast<uint16_t
>(texW);
176 const SDL_Color color_font) {
178 auto cached_vector = fonts_cache.find(font);
179 if (cached_vector != fonts_cache.end()) [[likely]] {
180 std::vector<ST::renderer_sdl::texture> tempVector = cached_vector->second;
181 if (!tempVector.empty()) [[likely]] {
183 const char *arg3 =
text.c_str();
184 for (
int j = 0; arg3[j] != 0; j++) {
186 SDL_Texture *
texture = glyph.atlas;
187 SDL_Rect dstRect = {tempX, y - glyph.height, glyph.width, glyph.height};
188 SDL_Rect srcRect = {glyph.atlas_h_offset, glyph.atlas_v_offset, glyph.width, glyph.height};
189 SDL_SetTextureColorMod(
texture, color_font.r, color_font.g, color_font.b);
190 SDL_RenderCopy(sdl_renderer,
texture, &srcRect, &dstRect);
191 tempX += glyph.width;
195 return static_cast<uint16_t
>(tempX - x);
203 if (surfaces !=
nullptr) {
204 surfaces_pointer = surfaces;
207 for (
auto &it: textures) {
208 if (it.second.atlas !=
nullptr) {
209 SDL_DestroyTexture(it.second.atlas);
210 it.second.atlas =
nullptr;
213 std::vector<std::pair<uint16_t, SDL_Surface *>> surfaces_pairs{};
214 for (
auto &it: *surfaces) {
215 surfaces_pairs.emplace_back(it.first, it.second);
223 sort_by_surface_width_height(
const std::pair<uint16_t, SDL_Surface *> &a,
const std::pair<uint16_t, SDL_Surface *> &b) {
224 if (a.second->w == b.second->w) {
225 return a.second->h > b.second->h;
227 return a.second->w > b.second->w;
237 if (surfaces_pairs.empty()) {
239 }
else if (surfaces_pairs.size() == 1) {
241 tex.width = surfaces_pairs.back().second->w;
242 tex.height = surfaces_pairs.back().second->h;
243 tex.atlas_v_offset = 0;
244 tex.atlas_h_offset = 0;
245 tex.atlas = SDL_CreateTextureFromSurface(sdl_renderer, surfaces_pairs.back().second);
246 textures[surfaces_pairs.back().first] = tex;
249 sort(surfaces_pairs.begin(), surfaces_pairs.end(), sort_by_surface_width_height);
251 std::vector<std::pair<uint16_t, SDL_Surface *>> remaining_surface_pairs{};
252 uint8_t atlas[atlas_grid_size][atlas_grid_size] = {0};
256 SDL_Texture *atlas_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC,
257 ATLAS_SIZE, ATLAS_SIZE);
258 SDL_SetTextureBlendMode(atlas_texture, SDL_BLENDMODE_BLEND);
259 for (
auto &it: surfaces_pairs) {
260 int t_width = it.second->w / 32;
261 int t_height = it.second->h / 32;
264 if ((it.second->w & (it.second->w - 1)) != 0 || (it.second->h & (it.second->h - 1)) != 0 ||
265 t_width > atlas_grid_size || t_height > atlas_grid_size) {
267 tex.width = it.second->w;
268 tex.height = it.second->h;
269 tex.atlas_v_offset = 0;
270 tex.atlas_h_offset = 0;
271 tex.atlas = SDL_CreateTextureFromSurface(sdl_renderer, it.second);
272 textures[it.first] = tex;
276 while (atlas[h_index][v_index] != 0) {
278 if (h_index == atlas_grid_size) {
282 if (v_index == atlas_grid_size) {
283 remaining_surface_pairs.emplace_back(it);
289 if (v_index + t_height > atlas_grid_size) {
290 remaining_surface_pairs.emplace_back(it);
294 for (
int i = h_index; i < h_index + t_width; ++i) {
295 for (
int j = v_index; j < v_index + t_height; ++j) {
302 tex.width = it.second->w;
303 tex.height = it.second->h;
304 tex.atlas_h_offset = h_index * 32;
305 tex.atlas_v_offset = v_index * 32;
306 tex.atlas = atlas_texture;
307 textures[it.first] = tex;
309 SDL_Rect dst_rect = {tex.atlas_h_offset, tex.atlas_v_offset, tex.width, tex.height};
310 SDL_UpdateTexture(atlas_texture, &dst_rect, it.second->pixels, it.second->pitch);
313 if (h_index == atlas_grid_size) {
325 if (fonts_t !=
nullptr) {
326 fonts_pointer = fonts_t;
327 for (
auto &it: *fonts_t) {
328 if (it.second ==
nullptr) {
329 for (
auto &k: fonts_cache[it.first]) {
330 if (k.atlas !=
nullptr) {
331 SDL_DestroyTexture(k.atlas);
335 fonts[it.first] =
nullptr;
336 }
else if (it.second !=
nullptr) {
337 if (fonts[it.first] !=
nullptr) {
338 for (
auto &k: fonts_cache[it.first]) {
339 if (k.atlas !=
nullptr) {
340 SDL_DestroyTexture(k.atlas);
344 fonts[it.first] =
nullptr;
346 fonts[it.first] = it.second;
362 SDL_Color color_font = {255, 255, 255, 255};
365 std::vector<ST::renderer_sdl::texture> result_glyphs{};
366 std::vector<SDL_Surface *> glyph_surfaces{};
367 result_glyphs.reserve(95);
368 glyph_surfaces.reserve(95);
369 int32_t total_width = 0;
370 int32_t max_height = 0;
371 for (
char j = 32; j < 127; j++) {
373 SDL_Surface *glyph_surface = TTF_RenderUTF8_Blended(Font, temp, color_font);
374 total_width += glyph_surface->w;
375 if (glyph_surface->h > max_height) {
376 max_height = glyph_surface->h;
378 glyph_surfaces.emplace_back(glyph_surface);
380 SDL_Texture *atlas_texture = SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC,
381 total_width, max_height);
382 SDL_SetTextureBlendMode(atlas_texture, SDL_BLENDMODE_BLEND);
383 int atlas_offset = 0;
384 for (
auto surface: glyph_surfaces) {
386 glyph.width = surface->w;
387 glyph.height = surface->h;
388 glyph.atlas_h_offset = atlas_offset;
389 glyph.atlas_v_offset = 0;
390 glyph.atlas = atlas_texture;
391 result_glyphs.push_back(glyph);
392 SDL_Rect dst_rect = {glyph.atlas_h_offset, glyph.atlas_v_offset, glyph.width, glyph.height};
393 SDL_UpdateTexture(atlas_texture, &dst_rect, surface->pixels, surface->pitch);
394 SDL_FreeSurface(surface);
395 atlas_offset += glyph.width;
397 fonts_cache[font_and_size] = result_glyphs;
404 SDL_RendererInfo info;
405 SDL_GetRendererInfo(sdl_renderer, &info);
406 if (!(info.flags & SDL_RENDERER_PRESENTVSYNC)) {
419 SDL_RendererInfo info;
420 SDL_GetRendererInfo(sdl_renderer, &info);
421 if (info.flags & SDL_RENDERER_PRESENTVSYNC) {
439 auto data = textures.find(arg);
440 if (data != textures.end()) {
444 SDL_RenderCopy(sdl_renderer,
texture.atlas, &src_rect, &dst_rect);
455 auto data = textures.find(arg);
456 if (data != textures.end()) {
459 SDL_Rect dst_rect = {x,
460 y -
static_cast<int>(
static_cast<float>(
texture.height) * scale_y),
461 static_cast<int>(
static_cast<float>(
texture.width) * scale_x),
462 static_cast<int>(
static_cast<float>(
texture.height) * scale_y)};
464 SDL_RenderCopy(sdl_renderer,
texture.atlas, &src_rect, &dst_rect);
477 SDL_Rect Rect = {x, y, w, h};
478 SDL_SetRenderDrawColor(sdl_renderer, color.r, color.g, color.b, color.a);
479 SDL_RenderFillRect(sdl_renderer, &Rect);
480 SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255);
492 SDL_Rect Rect = {x, y, w, h};
493 SDL_SetRenderDrawColor(sdl_renderer, color.r, color.g, color.b, color.a);
494 SDL_RenderDrawRect(sdl_renderer, &Rect);
495 SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 255);
503 auto data = textures.find(arg);
504 if (data != textures.end()) {
507 SDL_RenderCopy(sdl_renderer,
texture.atlas, &src_rect,
nullptr);
516 auto data = textures.find(arg);
517 if (data != textures.end()) {
520 float bg_ratio = (float)
texture.width / (
float) width;
521 int src_offset = (int) ((
float) offset * bg_ratio);
523 SDL_Rect dst_rect1 = {0, 0, width - offset, height};
524 SDL_Rect src_rect1 = {
texture.atlas_h_offset + src_offset,
texture.atlas_v_offset,
texture.width - src_offset,
527 SDL_Rect dst_rect2 = {width - offset, 0, offset, height};
529 SDL_RenderCopy(sdl_renderer,
texture.atlas, &src_rect1, &dst_rect1);
530 SDL_RenderCopy(sdl_renderer,
texture.atlas, &src_rect2, &dst_rect2);
545 uint8_t animation_num, uint8_t sprite_num) {
546 auto data = textures.find(arg);
547 if (data != textures.end()) {
550 int temp1 =
texture.height / animation_num;
551 int temp2 =
texture.width / sprite_num;
552 SDL_Rect dst_rect = {x, y - temp1, temp2, temp1};
553 SDL_Rect src_rect = {
texture.atlas_h_offset + (sprite * temp2),
554 texture.atlas_v_offset + (temp1 * (animation - 1)), temp2, temp1};
555 SDL_RenderCopy(sdl_renderer,
texture.atlas, &src_rect, &dst_rect);
570 uint8_t animation_num, uint8_t sprite_num,
float scale_x,
float scale_y) {
571 auto data = textures.find(arg);
572 if (data != textures.end()) {
575 int temp1 =
texture.height / animation_num;
576 int temp2 =
texture.width / sprite_num;
577 SDL_Rect dst_rect = {x,
578 y -
static_cast<int>(
static_cast<float>(temp1) * scale_y),
579 static_cast<int>(
static_cast<float>(temp2) * scale_x),
580 static_cast<int>(
static_cast<float>(temp1) * scale_y)};
581 SDL_Rect src_rect = {
texture.atlas_h_offset + (sprite * temp2),
582 texture.atlas_v_offset + (temp1 * (animation - 1)), temp2, temp1};
583 SDL_RenderCopy(sdl_renderer,
texture.atlas, &src_rect, &dst_rect);
595 auto data = textures.find(arg);
596 if (data != textures.end()) {
599 SDL_Rect src_rect = {sprite * (
texture.width / sprite_num), 0,
texture.width / sprite_num,
texture.height};
600 SDL_RenderCopy(sdl_renderer,
texture.atlas, &src_rect,
nullptr);
608 SDL_SetRenderDrawColor(sdl_renderer, color.r, color.g, color.b, color.a);
609 SDL_RenderClear(sdl_renderer);
610 SDL_SetRenderDrawColor(sdl_renderer, 0, 0, 0, 0);
617 SDL_RenderClear(sdl_renderer);
628 SDL_SetRenderDrawColor(sdl_renderer, r, g, b, a);
635 SDL_RenderPresent(sdl_renderer);
646 SDL_RenderSetLogicalSize(sdl_renderer, width, height);
The renderer for the engine.
uint16_t draw_text_lru_cached(uint16_t font, const std::string &arg2, int x, int y, SDL_Color color_font)
void upload_fonts(ska::bytell_hash_map< uint16_t, TTF_Font * > *fonts)
void cache_font(TTF_Font *Font, uint16_t font_and_size)
void upload_surfaces(ska::bytell_hash_map< uint16_t, SDL_Surface * > *surfaces)
void draw_overlay(uint16_t arg, uint8_t sprite, uint8_t sprite_num)
void draw_sprite_scaled(uint16_t arg, int32_t x, int32_t y, uint8_t sprite, uint8_t animation, uint8_t animation_num, uint8_t sprite_num, float scale_x, float scale_y)
void draw_sprite(uint16_t arg, int32_t x, int32_t y, uint8_t sprite, uint8_t animation, uint8_t animation_num, uint8_t sprite_num)
void clear_screen(SDL_Color color)
void draw_texture(uint16_t arg, int32_t x, int32_t y)
uint16_t draw_text_cached_glyphs(uint16_t font, const std::string &text, int x, int y, SDL_Color color_font)
void draw_background_parallax(uint16_t arg, uint16_t offset)
int8_t initialize(SDL_Window *win, int16_t width, int16_t height)
void draw_texture_scaled(uint16_t arg, int32_t x, int32_t y, float scale_x, float scale_y)
void set_resolution(int16_t r_width, int16_t r_height)
void draw_background(uint16_t arg)
void process_surfaces(std::vector< std::pair< uint16_t, SDL_Surface * >> &surfaces_pairs)
void draw_rectangle(int32_t x, int32_t y, int32_t w, int32_t h, SDL_Color color)
void set_draw_color(uint8_t, uint8_t, uint8_t, uint8_t)
void draw_rectangle_filled(int32_t x, int32_t y, int32_t w, int32_t h, SDL_Color color)
This struct represents text objects in the game.