]> git.lizzy.rs Git - nothing.git/blob - src/sdl/renderer.c
Merge pull request #229 from tsoding/render_text
[nothing.git] / src / sdl / renderer.c
1 #include <SDL2/SDL.h>
2 #include <assert.h>
3
4 #include "renderer.h"
5 #include "system/error.h"
6 #include "system/lt.h"
7
8 int draw_triangle(SDL_Renderer *render,
9                   triangle_t t)
10 {
11     assert(render);
12
13     if (SDL_RenderDrawLine(render,
14                            (int) roundf(t.p1.x),
15                            (int) roundf(t.p1.y),
16                            (int) roundf(t.p2.x),
17                            (int) roundf(t.p2.y)) < 0) {
18         throw_error(ERROR_TYPE_SDL2);
19         return -1;
20     }
21
22     if (SDL_RenderDrawLine(render,
23                            (int) roundf(t.p2.x),
24                            (int) roundf(t.p2.y),
25                            (int) roundf(t.p3.x),
26                            (int) roundf(t.p3.y)) < 0) {
27         throw_error(ERROR_TYPE_SDL2);
28         return -1;
29     }
30
31     if (SDL_RenderDrawLine(render,
32                            (int) roundf(t.p3.x),
33                            (int) roundf(t.p3.y),
34                            (int) roundf(t.p1.x),
35                            (int) roundf(t.p1.y)) < 0) {
36         throw_error(ERROR_TYPE_SDL2);
37         return -1;
38     }
39
40     return 0;
41 }
42
43 static int fill_bottom_flat_triangle(SDL_Renderer *render,
44                                      triangle_t t)
45 {
46     assert(render);
47
48     const float invslope1 = (t.p2.x - t.p1.x) / (t.p2.y - t.p1.y);
49     const float invslope2 = (t.p3.x - t.p1.x) / (t.p3.y - t.p1.y);
50
51     const int y0 = (int) roundf(t.p1.y);
52     const int y1 = (int) roundf(t.p2.y);
53
54     float curx1 = t.p1.x;
55     float curx2 = t.p1.x;
56
57     for (int scanline = y0; scanline < y1; scanline++) {
58         if (SDL_RenderDrawLine(render,
59                                (int) roundf(curx1),
60                                scanline,
61                                (int) roundf(curx2),
62                                scanline) < 0) {
63             return -1;
64         }
65         curx1 += invslope1;
66         curx2 += invslope2;
67     }
68
69     return 0;
70 }
71
72 static int fill_top_flat_triangle(SDL_Renderer *render,
73                                   triangle_t t)
74 {
75     assert(render);
76
77     const float invslope1 = (t.p3.x - t.p1.x) / (t.p3.y - t.p1.y);
78     const float invslope2 = (t.p3.x - t.p2.x) / (t.p3.y - t.p2.y);
79
80     const int y0 = (int) roundf(t.p3.y);
81     const int y1 = (int) roundf(t.p1.y);
82
83     float curx1 = t.p3.x;
84     float curx2 = t.p3.x;
85
86     for (int scanline = y0; scanline > y1; --scanline) {
87         if (SDL_RenderDrawLine(render,
88                                (int) roundf(curx1),
89                                scanline,
90                                (int) roundf(curx2),
91                                scanline) < 0) {
92             return -1;
93         }
94
95         curx1 -= invslope1;
96         curx2 -= invslope2;
97     }
98
99     return 0;
100 }
101
102 int fill_triangle(SDL_Renderer *render,
103                   triangle_t t)
104 {
105     t = triangle_sorted_by_y(t);
106
107     if (fabs(t.p2.y - t.p3.y) < 1e-6) {
108         if (fill_bottom_flat_triangle(render, t) < 0) {
109             return -1;
110         }
111     } else if (fabs(t.p1.y - t.p2.y) < 1e-6) {
112         if (fill_top_flat_triangle(render, t) < 0) {
113             return -1;
114         }
115     } else {
116         const point_t p4 = vec(t.p1.x + ((t.p2.y - t.p1.y) / (t.p3.y - t.p1.y)) * (t.p3.x - t.p1.x), t.p2.y);
117
118         if (fill_bottom_flat_triangle(render, triangle(t.p1, t.p2, p4)) < 0) {
119             return -1;
120         }
121
122         if (fill_top_flat_triangle(render, triangle(t.p2, p4, t.p3)) < 0) {
123             return -1;
124         }
125
126         if (SDL_RenderDrawLine(render,
127                                (int) roundf(t.p2.x),
128                                (int) roundf(t.p2.y),
129                                (int) roundf(p4.x),
130                                (int) roundf(p4.y)) < 0) {
131             return -1;
132         }
133     }
134
135     return 0;
136 }
137
138 int render_text_shaded(SDL_Renderer *renderer,
139                        TTF_Font *font,
140                        vec_t position,
141                        color_t color,
142                        color_t bg,
143                        const char *text)
144 {
145     assert(renderer);
146     assert(font);
147     assert(text);
148
149     lt_t * const lt = create_lt();
150     if (lt == NULL) {
151         return -1;
152     }
153
154     SDL_Surface * const surface = PUSH_LT(
155         lt,
156         TTF_RenderText_Shaded(font, text, color_for_sdl(color), color_for_sdl(bg)),
157         SDL_FreeSurface);
158     if (surface == NULL) {
159         throw_error(ERROR_TYPE_SDL2_TTF);
160         RETURN_LT(lt, -1);
161     }
162
163     SDL_Texture * const texture = PUSH_LT(
164         lt,
165         SDL_CreateTextureFromSurface(renderer, surface),
166         SDL_DestroyTexture);
167     if (texture == NULL) {
168         throw_error(ERROR_TYPE_SDL2);
169         RETURN_LT(lt, -1);
170     }
171
172     int texW = 0;
173     int texH = 0;
174
175     if (SDL_QueryTexture(texture, NULL, NULL, &texW, &texH) < 0) {
176         throw_error(ERROR_TYPE_SDL2);
177         RETURN_LT(lt, -1);
178     }
179
180     const SDL_Rect dstrect = { (int) position.x, (int) position.y, texW, texH };
181
182     if (SDL_RenderCopy(renderer, texture, NULL, &dstrect) < 0) {
183         throw_error(ERROR_TYPE_SDL2);
184         RETURN_LT(lt, -1);
185     }
186
187     RETURN_LT(lt, 0);
188 }