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
);
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
) {
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;
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
];
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
);
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
);
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
;
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
];
137 push_quad(dst
, src
, color
);
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
) {
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
;
162 int r_get_text_height(void) {
167 void r_set_clip_rect(mu_Rect rect
) {
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
) {
178 for (int i
= 0; i
< window
.width
* window
.height
; i
++) {
179 window
.buf
[i
] = r_color(clr
);
184 void r_present(void) {
186 fenster_loop(&window
);
191 int r_mouse_down(void) {
192 if (window
.mouse
&& !mouse_down
) {
199 int r_mouse_up(void) {
200 if (!window
.mouse
&& mouse_down
) {
207 int r_mouse_moved(int *mousex
, int *mousey
) {
208 if (window
.x
!= *mousex
|| window
.y
!= *mousey
) {
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) {
230 int r_key_up(int key
) {
231 if (window
.keys
[key
] < 1) {
237 int64_t r_get_time(void) {
238 return fenster_time();
241 void r_sleep(int64_t ms
) {