]> git.lizzy.rs Git - nothing.git/blob - src/game/sprite_font.c
(#265) sprite_font_boundary_box
[nothing.git] / src / game / sprite_font.c
1 #include <SDL2/SDL.h>
2 #include <assert.h>
3 #include <stdio.h>
4 #include <string.h>
5
6 #include "math/rect.h"
7 #include "sdl/renderer.h"
8 #include "sprite_font.h"
9 #include "system/error.h"
10 #include "system/lt.h"
11
12 #define FONT_ROW_SIZE 18
13 #define CHAR_WIDTH 7
14 #define CHAR_HEIGHT 9
15
16 struct sprite_font_t
17 {
18     lt_t *lt;
19     SDL_Texture *texture;
20 };
21
22 sprite_font_t *create_sprite_font_from_file(const char *bmp_file_path,
23                                             SDL_Renderer *renderer)
24 {
25     assert(bmp_file_path);
26     assert(renderer);
27
28     lt_t * const lt = create_lt();
29     if (lt == NULL) {
30         return NULL;
31     }
32
33     sprite_font_t * const sprite_font = PUSH_LT(lt, malloc(sizeof(sprite_font_t)), free);
34     if (sprite_font == NULL) {
35         throw_error(ERROR_TYPE_LIBC);
36         RETURN_LT(lt, NULL);
37     }
38
39     SDL_Surface * const surface = PUSH_LT(lt, SDL_LoadBMP(bmp_file_path), SDL_FreeSurface);
40     if (surface == NULL) {
41         throw_error(ERROR_TYPE_SDL2);
42         RETURN_LT(lt, NULL);
43     }
44
45     if (SDL_SetColorKey(surface,
46                         SDL_TRUE,
47                         SDL_MapRGB(surface->format,
48                                    0, 0, 0)) < 0) {
49         throw_error(ERROR_TYPE_SDL2);
50         RETURN_LT(lt, NULL);
51     }
52
53     sprite_font->texture = PUSH_LT(
54         lt,
55         SDL_CreateTextureFromSurface(renderer, surface),
56         SDL_DestroyTexture);
57     if (sprite_font->texture == NULL) {
58         throw_error(ERROR_TYPE_SDL2);
59         RETURN_LT(lt, NULL);
60     }
61
62     SDL_FreeSurface(RELEASE_LT(lt, surface));
63
64     sprite_font->lt = lt;
65
66     return sprite_font;
67 }
68
69 void destroy_sprite_font(sprite_font_t *sprite_font)
70 {
71     assert(sprite_font);
72     RETURN_LT0(sprite_font->lt);
73 }
74
75 static SDL_Rect sprite_font_char_rect(const sprite_font_t *sprite_font, char x)
76 {
77     assert(sprite_font);
78
79     if (32 <= x && x <= 126) {
80         const SDL_Rect rect = {
81             .x = ((x - 32) % FONT_ROW_SIZE) * CHAR_WIDTH,
82             .y = ((x - 32) / FONT_ROW_SIZE) * CHAR_HEIGHT,
83             .w = CHAR_WIDTH,
84             .h = CHAR_HEIGHT
85         };
86         return rect;
87     } else {
88         return sprite_font_char_rect(sprite_font, '?');
89     }
90 }
91
92 int sprite_font_render_text(const sprite_font_t *sprite_font,
93                             SDL_Renderer *renderer,
94                             vec_t position,
95                             vec_t size,
96                             color_t color,
97                             const char *text)
98 {
99     assert(sprite_font);
100     assert(renderer);
101     assert(text);
102
103     const SDL_Color sdl_color = color_for_sdl(color);
104
105     if (SDL_SetTextureColorMod(sprite_font->texture, sdl_color.r, sdl_color.g, sdl_color.b) < 0) {
106         throw_error(ERROR_TYPE_SDL2);
107         return -1;
108     }
109
110     if (SDL_SetTextureAlphaMod(sprite_font->texture, sdl_color.a) < 0) {
111         throw_error(ERROR_TYPE_SDL2);
112         return -1;
113     }
114
115     const size_t text_size = strlen(text);
116     for (size_t i = 0; i < text_size; ++i) {
117         const SDL_Rect char_rect = sprite_font_char_rect(sprite_font, text[i]);
118         const SDL_Rect dest_rect = rect_for_sdl(
119             rect(
120                 position.x + (float) CHAR_WIDTH * (float) i * size.x,
121                 position.y,
122                 (float) char_rect.w * size.x,
123                 (float) char_rect.h * size.y));
124         if (SDL_RenderCopy(renderer, sprite_font->texture, &char_rect, &dest_rect) < 0) {
125             return -1;
126         }
127     }
128
129     return 0;
130 }
131
132 rect_t sprite_font_boundary_box(const sprite_font_t *sprite_font,
133                                 vec_t position,
134                                 vec_t size,
135                                 const char *text)
136 {
137     assert(sprite_font);
138     assert(text);
139     return rect(position.x, position.y, size.x * CHAR_WIDTH * (float) strlen(text), size.y * CHAR_HEIGHT);
140 }