7 #define BUFFER_SIZE 16384
11 static mu_Rect tex_buf
[BUFFER_SIZE
];
12 static mu_Rect src_buf
[BUFFER_SIZE
];
13 static mu_Color color_buf
[BUFFER_SIZE
];
17 static struct fenster window
= {.title
="A window", .width
=800, .height
=600};
19 static mu_Rect clip_rect
;
23 window
.buf
= malloc(window
.width
* window
.height
* sizeof(*window
.buf
));
24 r_clear(mu_color(0, 0, 0, 255));
25 fenster_open(&window
);
30 static inline bool within(int c
, int lo
, int hi
) {
31 return c
>= lo
&& c
< hi
;
34 static inline bool within_rect(mu_Rect rect
, int x
, int y
) {
35 return within(x
, rect
.x
, rect
.x
+rect
.w
)
36 && within(y
, rect
.y
, rect
.y
+rect
.h
);
39 static inline bool same_size(const mu_Rect
* a
, const mu_Rect
* b
) {
40 return a
->w
== b
->w
&& a
->h
== b
->h
;
43 static inline byte
texture_color(const mu_Rect
* tex
, int x
, int y
) {
48 return atlas_texture
[y
*ATLAS_WIDTH
+ x
];
51 static inline uint32_t r_color(mu_Color clr
) {
52 return ((uint32_t)clr
.a
<< 24) | ((uint32_t)clr
.r
<< 16) | ((uint32_t)clr
.g
<< 8) | clr
.b
;
55 mu_Color
mu_color_argb(uint32_t clr
) {
56 return mu_color((clr
>> 16) & 0xff, (clr
>> 8) & 0xff, clr
& 0xff, (clr
>> 24) & 0xff);
59 static inline int greyscale(byte c
) {
60 return r_color(mu_color(c
, c
, c
, 255));
64 static inline mu_Color
blend_pixel(mu_Color dst
, mu_Color src
) {
65 int ia
= 0xff - src
.a
;
66 dst
.r
= ((src
.r
* src
.a
) + (dst
.r
* ia
)) >> 8;
67 dst
.g
= ((src
.g
* src
.a
) + (dst
.g
* ia
)) >> 8;
68 dst
.b
= ((src
.b
* src
.a
) + (dst
.b
* ia
)) >> 8;
72 static void flush(void) {
73 // draw things based on texture, vertex, color
74 for (int i
= 0; i
< buf_idx
; i
++) {
75 mu_Rect
* src
= &src_buf
[i
];
76 mu_Rect
* tex
= &tex_buf
[i
];
78 int ystart
= mu_max(src
->y
, clip_rect
.y
);
79 int yend
= mu_min(src
->y
+src
->h
, clip_rect
.y
+clip_rect
.h
);
80 int xstart
= mu_max(src
->x
, clip_rect
.x
);
81 int xend
= mu_min(src
->x
+src
->w
, clip_rect
.x
+clip_rect
.w
);
82 // hacky but sufficient for us
83 if (same_size(src
, tex
)) {
84 for (int y
= ystart
; y
< yend
; y
++) {
85 for (int x
= xstart
; x
< xend
; x
++) {
86 assert(within_rect(*src
, x
, y
));
87 assert(within_rect(clip_rect
, x
, y
));
88 // read color from texture
89 byte tc
= texture_color(tex
, x
-src
->x
, y
-src
->y
);
90 fenster_pixel(&window
, x
, y
) |= greyscale(tc
);
94 mu_Color new_color
= color_buf
[i
];
95 for (int y
= ystart
; y
< yend
; y
++) {
96 for (int x
= xstart
; x
< xend
; x
++) {
97 assert(within_rect(*src
, x
, y
));
98 assert(within_rect(clip_rect
, x
, y
));
99 // blend color from operation
100 mu_Color existing_color
= mu_color_argb(fenster_pixel(&window
, x
, y
));
101 mu_Color result
= blend_pixel(existing_color
, new_color
);
102 fenster_pixel(&window
, x
, y
) = r_color(result
);
112 static void push_quad(mu_Rect src
, mu_Rect tex
, mu_Color color
) {
113 if (buf_idx
== BUFFER_SIZE
) { flush(); }
115 tex_buf
[buf_idx
] = tex
;
116 src_buf
[buf_idx
] = src
;
117 color_buf
[buf_idx
] = color
;
123 void r_draw_rect(mu_Rect rect
, mu_Color color
) {
124 push_quad(rect
, atlas
[ATLAS_WHITE
], color
);
128 void r_draw_text(const char *text
, mu_Vec2 pos
, mu_Color color
) {
129 mu_Rect dst
= { pos
.x
, pos
.y
, 0, 0 };
130 for (const char *p
= text
; *p
; p
++) {
131 if ((*p
& 0xc0) == 0x80) { continue; }
132 int chr
= mu_min((unsigned char) *p
, 127);
133 mu_Rect src
= atlas
[ATLAS_FONT
+ chr
];
136 push_quad(dst
, src
, color
);
142 void r_draw_icon(int id
, mu_Rect rect
, mu_Color color
) {
143 mu_Rect src
= atlas
[id
];
144 int x
= rect
.x
+ (rect
.w
- src
.w
) / 2;
145 int y
= rect
.y
+ (rect
.h
- src
.h
) / 2;
146 push_quad(mu_rect(x
, y
, src
.w
, src
.h
), src
, color
);
150 int r_get_text_width(const char *text
, int len
) {
152 for (const char *p
= text
; *p
&& len
--; p
++) {
153 if ((*p
& 0xc0) == 0x80) { continue; }
154 int chr
= mu_min((unsigned char) *p
, 127);
155 res
+= atlas
[ATLAS_FONT
+ chr
].w
;
161 int r_get_text_height(void) {
166 void r_set_clip_rect(mu_Rect rect
) {
168 int ystart
= mu_max(0, rect
.y
);
169 int yend
= mu_min(window
.height
, rect
.y
+rect
.h
);
170 int xstart
= mu_max(0, rect
.x
);
171 int xend
= mu_min(window
.width
, rect
.x
+rect
.w
);
172 clip_rect
= mu_rect(xstart
, ystart
, xend
-xstart
, yend
-ystart
);
175 void r_clear(mu_Color clr
) {
177 for (int i
= 0; i
< window
.width
* window
.height
; i
++) {
178 window
.buf
[i
] = r_color(clr
);
183 void r_present(void) {
185 fenster_loop(&window
);
189 int r_mouse_down(void) {
190 if (window
.mouse
== 1) {
197 int r_mouse_up(void) {
198 if (window
.mouse
< 1) {
204 int r_mouse_moved(int *mousex
, int *mousey
) {
205 if (window
.x
!= *mousex
|| window
.y
!= *mousey
) {
213 int r_ctrl_pressed(void) { return window
.mod
& 1; }
215 int r_shift_pressed(void) { return window
.mod
& 2; }
217 int r_alt_pressed(void) { return window
.mod
& 4; }
219 int r_key_down(int key
) {
220 if (window
.keys
[key
] == 1) {
227 int r_key_up(int key
) {
228 if (window
.keys
[key
] < 1) {
234 int64_t r_get_time(void) {
235 return fenster_time();
238 void r_sleep(int64_t ms
) {