]> git.lizzy.rs Git - nothing.git/blob - src/sdl/renderer.c
Merge pull request #1089 from tsoding/vec
[nothing.git] / src / sdl / renderer.c
1 #include <SDL.h>
2 #include "system/stacktrace.h"
3
4 #include "renderer.h"
5 #include "system/lt.h"
6 #include "system/log.h"
7
8 int draw_triangle(SDL_Renderer *render,
9                   Triangle t)
10 {
11     trace_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         log_fail("SDL_RenderDrawLine: %s\n", SDL_GetError());
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         log_fail("SDL_RenderDrawLine: %s\n", SDL_GetError());
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         log_fail("SDL_RenderDrawLine: %s\n", SDL_GetError());
37         return -1;
38     }
39
40     return 0;
41 }
42
43 static int fill_bottom_flat_triangle(SDL_Renderer *render,
44                                      Triangle t)
45 {
46     trace_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)
74 {
75     trace_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)
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 Vec2f 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 fill_rect(SDL_Renderer *render, Rect r, Color c)
139 {
140     const SDL_Rect sdl_rect = rect_for_sdl(r);
141     const SDL_Color sdl_color = color_for_sdl(c);
142
143     if (SDL_SetRenderDrawColor(
144             render,
145             sdl_color.r, sdl_color.g,
146             sdl_color.b, sdl_color.a) < 0) {
147         log_fail("SDL_SetRenderDrawColor: %s\n", SDL_GetError());
148         return -1;
149     }
150
151     if (SDL_RenderFillRect(render, &sdl_rect) < 0) {
152         log_fail("SDL_RenderFillRect: %s\n");
153         return -1;
154     }
155
156     return 0;
157 }
158
159 /*
160  * Return the pixel value at (x, y)
161  * NOTE: The surface must be locked before calling this!
162  */
163 Uint32 getpixel(SDL_Surface *surface, int x, int y)
164 {
165     int bpp = surface->format->BytesPerPixel;
166     /* Here p is the address to the pixel we want to retrieve */
167     Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
168
169     switch(bpp) {
170     case 1:
171         return *p;
172
173     case 2:
174         return *(Uint16 *)p;
175
176     case 3:
177         if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
178             return (Uint32) p[0] << 16 | (Uint32) p[1] << 8 | (Uint32) p[2];
179         else
180             return (Uint32) p[0] | (Uint32) p[1] << 8 | (Uint32) p[2] << 16;
181
182     case 4:
183         return *(Uint32 *)p;
184
185     default:
186         return 0;       /* shouldn't happen, but avoids warnings */
187     }
188 }
189
190 /*
191  * Set the pixel at (x, y) to the given value
192  * NOTE: The surface must be locked before calling this!
193  */
194 void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
195 {
196     int bpp = surface->format->BytesPerPixel;
197     /* Here p is the address to the pixel we want to set */
198     Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
199
200     switch(bpp) {
201     case 1:
202         *(Uint32*) p = pixel;
203         break;
204
205     case 2:
206         *(Uint16 *)p = (Uint16) pixel;
207         break;
208
209     case 3:
210         if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
211             p[0] = (pixel >> 16) & 0xff;
212             p[1] = (pixel >> 8) & 0xff;
213             p[2] = pixel & 0xff;
214         } else {
215             p[0] = pixel & 0xff;
216             p[1] = (pixel >> 8) & 0xff;
217             p[2] = (pixel >> 16) & 0xff;
218         }
219         break;
220
221     case 4:
222         *(Uint32 *)p = pixel;
223         break;
224     }
225 }