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