Added support for cross-compiling to mingw (#5)
[full-beans.git] / renderer.c
blob02c8e073883ea44ae9378fd97a05411952e62bf3
1 #include "fenster.h"
2 #include <assert.h>
3 #include <stdbool.h>
4 #include "renderer.h"
5 #include "atlas.inl"
7 #define BUFFER_SIZE 16384
9 typedef uint8_t byte;
11 static mu_Rect tex_buf[BUFFER_SIZE];
12 static mu_Rect src_buf[BUFFER_SIZE];
13 static mu_Color color_buf[BUFFER_SIZE];
15 static int buf_idx;
17 static struct fenster window = {.title="A window", .width=800, .height=600};
19 static mu_Rect clip_rect;
21 void r_init(void) {
22 /* init SDL window */
23 window.buf = malloc(window.width * window.height * sizeof(*window.buf));
24 r_clear(mu_color(0, 0, 0, 255));
25 fenster_open(&window);
27 /* init texture */
28 clip_rect = mu_rect(0, 0, window.width, window.height);
31 static inline bool within(int c, int lo, int hi) {
32 return c >= lo && c < hi;
35 static inline bool within_rect(mu_Rect rect, int x, int y) {
36 return within(x, rect.x, rect.x+rect.w)
37 && within(y, rect.y, rect.y+rect.h);
40 static inline bool same_size(const mu_Rect* a, const mu_Rect* b) {
41 return a->w == b->w && a->h == b->h;
44 static inline byte texture_color(const mu_Rect* tex, int x, int y) {
45 assert(x < tex->w);
46 x = x + tex->x;
47 assert(y < tex->h);
48 y = y + tex->y;
49 return atlas_texture[y*ATLAS_WIDTH + x];
52 static inline uint32_t r_color(mu_Color clr) {
53 return ((uint32_t)clr.a << 24) | ((uint32_t)clr.r << 16) | ((uint32_t)clr.g << 8) | clr.b;
56 mu_Color mu_color_argb(uint32_t clr) {
57 return mu_color((clr >> 16) & 0xff, (clr >> 8) & 0xff, clr & 0xff, (clr >> 24) & 0xff);
60 static inline int greyscale(byte c) {
61 return r_color(mu_color(c, c, c, 255));
65 static inline mu_Color blend_pixel(mu_Color dst, mu_Color src) {
66 int ia = 0xff - src.a;
67 dst.r = ((src.r * src.a) + (dst.r * ia)) >> 8;
68 dst.g = ((src.g * src.a) + (dst.g * ia)) >> 8;
69 dst.b = ((src.b * src.a) + (dst.b * ia)) >> 8;
70 return dst;
73 static void flush(void) {
74 // draw things based on texture, vertex, color
75 for (int i = 0; i < buf_idx; i++) {
76 mu_Rect* src = &src_buf[i];
77 mu_Rect* tex = &tex_buf[i];
78 // draw
79 int ystart = mu_max(src->y, clip_rect.y);
80 int yend = mu_min(src->y+src->h, clip_rect.y+clip_rect.h);
81 int xstart = mu_max(src->x, clip_rect.x);
82 int xend = mu_min(src->x+src->w, clip_rect.x+clip_rect.w);
83 // hacky but sufficient for us
84 if (same_size(src, tex)) {
85 for (int y = ystart; y < yend; y++) {
86 for (int x = xstart; x < xend; x++) {
87 assert(within_rect(*src, x, y));
88 assert(within_rect(clip_rect, x, y));
89 // read color from texture
90 byte tc = texture_color(tex, x-src->x, y-src->y);
91 fenster_pixel(&window, x, y) |= greyscale(tc);
94 } else {
95 mu_Color new_color = color_buf[i];
96 for (int y = ystart; y < yend; y++) {
97 for (int x = xstart; x < xend; x++) {
98 assert(within_rect(*src, x, y));
99 assert(within_rect(clip_rect, x, y));
100 // blend color from operation
101 mu_Color existing_color = mu_color_argb(fenster_pixel(&window, x, y));
102 mu_Color result = blend_pixel(existing_color, new_color);
103 fenster_pixel(&window, x, y) = r_color(result);
109 buf_idx = 0;
113 static void push_quad(mu_Rect src, mu_Rect tex, mu_Color color) {
114 if (buf_idx == BUFFER_SIZE) { flush(); }
116 tex_buf[buf_idx] = tex;
117 src_buf[buf_idx] = src;
118 color_buf[buf_idx] = color;
120 buf_idx++;
124 void r_draw_rect(mu_Rect rect, mu_Color color) {
125 push_quad(rect, atlas[ATLAS_WHITE], color);
129 void r_draw_text(const char *text, mu_Vec2 pos, mu_Color color) {
130 mu_Rect dst = { pos.x, pos.y, 0, 0 };
131 for (const char *p = text; *p; p++) {
132 if ((*p & 0xc0) == 0x80) { continue; }
133 int chr = mu_min((unsigned char) *p, 127);
134 mu_Rect src = atlas[ATLAS_FONT + chr];
135 dst.w = src.w;
136 dst.h = src.h;
137 push_quad(dst, src, color);
138 dst.x += dst.w;
143 void r_draw_icon(int id, mu_Rect rect, mu_Color color) {
144 mu_Rect src = atlas[id];
145 int x = rect.x + (rect.w - src.w) / 2;
146 int y = rect.y + (rect.h - src.h) / 2;
147 push_quad(mu_rect(x, y, src.w, src.h), src, color);
151 int r_get_text_width(const char *text, int len) {
152 int res = 0;
153 for (const char *p = text; *p && len--; p++) {
154 if ((*p & 0xc0) == 0x80) { continue; }
155 int chr = mu_min((unsigned char) *p, 127);
156 res += atlas[ATLAS_FONT + chr].w;
158 return res;
162 int r_get_text_height(void) {
163 return 18;
167 void r_set_clip_rect(mu_Rect rect) {
168 flush();
169 int ystart = mu_max(0, rect.y);
170 int yend = mu_min(window.height, rect.y+rect.h);
171 int xstart = mu_max(0, rect.x);
172 int xend = mu_min(window.width, rect.x+rect.w);
173 clip_rect = mu_rect(xstart, ystart, xend-xstart, yend-ystart);
176 void r_clear(mu_Color clr) {
177 flush();
178 for (int i = 0; i < window.width * window.height; i++) {
179 window.buf[i] = r_color(clr);
184 void r_present(void) {
185 flush();
186 fenster_loop(&window);
189 int mouse_down = 0;
191 int r_mouse_down(void) {
192 if (window.mouse && !mouse_down) {
193 mouse_down = 1;
194 return 1;
196 return 0;
199 int r_mouse_up(void) {
200 if (!window.mouse && mouse_down) {
201 mouse_down = 0;
202 return 1;
204 return 0;
207 int r_mouse_moved(int *mousex, int *mousey) {
208 if (window.x != *mousex || window.y != *mousey) {
209 *mousex = window.x;
210 *mousey = window.y;
211 return 1;
213 return 0;
216 int r_ctrl_pressed(void) { return window.mod & 1; }
218 int r_shift_pressed(void) { return window.mod & 2; }
220 int r_alt_pressed(void) { return window.mod & 4; }
222 int r_key_down(int key) {
223 if (window.keys[key] == 1) {
224 window.keys[key]++;
225 return 1;
227 return 0;
230 int r_key_up(int key) {
231 if (window.keys[key] < 1) {
232 return 1;
234 return 0;
237 int64_t r_get_time(void) {
238 return fenster_time();
241 void r_sleep(int64_t ms) {
242 fenster_sleep(ms);