main
renderer.c
1/* wld: renderer.c
2 *
3 * Copyright (c) 2013, 2014 Michael Forney
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "wld-private.h"
25
26void
27default_fill_region(struct wld_renderer *renderer, uint32_t color, pixman_region32_t *region)
28{
29 pixman_box32_t *box;
30 int num_boxes;
31
32 box = pixman_region32_rectangles(region, &num_boxes);
33
34 while (num_boxes--) {
35 renderer->impl->fill_rectangle(renderer, color, box->x1, box->y1,
36 box->x2 - box->x1, box->y2 - box->y1);
37 ++box;
38 }
39}
40
41void
42default_copy_region(struct wld_renderer *renderer, struct buffer *buffer,
43 int32_t dst_x, int32_t dst_y,
44 pixman_region32_t *region)
45{
46 pixman_box32_t *box;
47 int num_boxes;
48
49 box = pixman_region32_rectangles(region, &num_boxes);
50
51 while (num_boxes--) {
52 renderer->impl->copy_rectangle(renderer, buffer,
53 dst_x + box->x1, dst_y + box->y1,
54 box->x1, box->y1,
55 box->x2 - box->x1, box->y2 - box->y1);
56 ++box;
57 }
58}
59
60void
61renderer_initialize(struct wld_renderer *renderer, const struct wld_renderer_impl *impl)
62{
63 *((const struct wld_renderer_impl **)&renderer->impl) = impl;
64 renderer->target = NULL;
65}
66
67EXPORT
68void
69wld_destroy_renderer(struct wld_renderer *renderer)
70{
71 renderer->impl->destroy(renderer);
72}
73
74EXPORT
75uint32_t
76wld_capabilities(struct wld_renderer *renderer, struct wld_buffer *buffer)
77{
78 return renderer->impl->capabilities(renderer, (struct buffer *)buffer);
79}
80
81EXPORT
82bool
83wld_set_target_buffer(struct wld_renderer *renderer, struct wld_buffer *buffer)
84{
85 if (!renderer->impl->set_target(renderer, (struct buffer *)buffer))
86 return false;
87
88 renderer->target = buffer;
89
90 return true;
91}
92
93EXPORT
94bool
95wld_set_target_surface(struct wld_renderer *renderer, struct wld_surface *surface)
96{
97 struct buffer *back_buffer;
98
99 if (!(back_buffer = surface->impl->back(surface)))
100 return false;
101
102 if (!renderer->impl->set_target(renderer, back_buffer))
103 return false;
104
105 renderer->target = &back_buffer->base;
106 return true;
107}
108
109EXPORT
110void
111wld_fill_rectangle(struct wld_renderer *renderer, uint32_t color,
112 int32_t x, int32_t y, uint32_t width, uint32_t height)
113{
114 renderer->impl->fill_rectangle(renderer, color, x, y, width, height);
115}
116
117EXPORT
118void
119wld_fill_region(struct wld_renderer *renderer, uint32_t color, pixman_region32_t *region)
120{
121 renderer->impl->fill_region(renderer, color, region);
122}
123
124EXPORT
125void
126wld_copy_rectangle(struct wld_renderer *renderer,
127 struct wld_buffer *buffer,
128 int32_t dst_x, int32_t dst_y,
129 int32_t src_x, int32_t src_y,
130 uint32_t width, uint32_t height)
131{
132 renderer->impl->copy_rectangle(renderer, (struct buffer *)buffer,
133 dst_x, dst_y, src_x, src_y, width, height);
134}
135
136EXPORT
137void
138wld_copy_region(struct wld_renderer *renderer,
139 struct wld_buffer *buffer,
140 int32_t dst_x, int32_t dst_y, pixman_region32_t *region)
141{
142 renderer->impl->copy_region(renderer, (struct buffer *)buffer,
143 dst_x, dst_y, region);
144}
145
146EXPORT
147void
148wld_blend_region(struct wld_renderer *renderer, struct wld_buffer *buffer,
149 int32_t dst_x, int32_t dst_y, pixman_region32_t *region)
150{
151 pixman_image_t *src = NULL, *dst = NULL;
152 pixman_region32_t clip;
153 pixman_box32_t *extents;
154
155 if (!renderer->target || !pixman_region32_not_empty(region))
156 return;
157
158 /* Complete accelerator writes before accessing the buffers on the CPU. */
159 renderer->impl->flush(renderer);
160 if (!wld_map(buffer))
161 return;
162 if (!wld_map(renderer->target))
163 goto unmap_src;
164
165 src = pixman_image_create_bits(format_wld_to_pixman(buffer->format),
166 buffer->width, buffer->height,
167 buffer->map, buffer->pitch);
168 dst = pixman_image_create_bits(format_wld_to_pixman(renderer->target->format),
169 renderer->target->width,
170 renderer->target->height,
171 renderer->target->map,
172 renderer->target->pitch);
173 if (!src || !dst)
174 goto destroy;
175
176 pixman_region32_init(&clip);
177 pixman_region32_copy(&clip, region);
178 pixman_region32_translate(&clip, dst_x, dst_y);
179 extents = pixman_region32_extents(region);
180 pixman_image_set_clip_region32(dst, &clip);
181 pixman_image_composite32(PIXMAN_OP_OVER, src, NULL, dst,
182 extents->x1, extents->y1, 0, 0,
183 extents->x1 + dst_x, extents->y1 + dst_y,
184 extents->x2 - extents->x1,
185 extents->y2 - extents->y1);
186 pixman_region32_fini(&clip);
187
188destroy:
189 if (src)
190 pixman_image_unref(src);
191 if (dst)
192 pixman_image_unref(dst);
193 wld_unmap(renderer->target);
194unmap_src:
195 wld_unmap(buffer);
196}
197
198
199/* https://en.wikipedia.org/wiki/Midpoint_circle_algorithm */
200static void
201circle_points(struct wld_renderer *renderer, uint32_t color,
202 int32_t x1, int32_t y1, int32_t x2, int32_t y2, bool fill)
203{
204 /* hacky */
205 if (fill) {
206 renderer->impl->fill_rectangle(renderer, color, x1-x2, y1+y2, 2*x2 + 1, 1);
207 renderer->impl->fill_rectangle(renderer, color, x1-x2, y1-y2, 2*x2 + 1, 1);
208 renderer->impl->fill_rectangle(renderer, color, x1-y2, y1+x2, 2*y2 + 1, 1);
209 renderer->impl->fill_rectangle(renderer, color, x1-y2, y1-x2, 2*y2 + 1, 1);
210 }
211
212 else {
213 renderer->impl->fill_rectangle(renderer, color, x1+x2, y1+y2, 1, 1);
214 renderer->impl->fill_rectangle(renderer, color, x1-x2, y1+y2, 1, 1);
215 renderer->impl->fill_rectangle(renderer, color, x1+x2, y1-y2, 1, 1);
216 renderer->impl->fill_rectangle(renderer, color, x1-x2, y1-y2, 1, 1);
217 renderer->impl->fill_rectangle(renderer, color, x1+y2, y1+x2, 1, 1);
218 renderer->impl->fill_rectangle(renderer, color, x1-y2, y1+x2, 1, 1);
219 renderer->impl->fill_rectangle(renderer, color, x1+y2, y1-x2, 1, 1);
220 renderer->impl->fill_rectangle(renderer, color, x1-y2, y1-x2, 1, 1);
221 }
222}
223
224EXPORT
225void
226wld_draw_circle(struct wld_renderer *renderer, uint32_t color,
227 int32_t x, int32_t y, uint32_t r, bool fill)
228{
229 int32_t x1 = 0, y1 = r;
230 int32_t d = 3 - 2 * r;
231 circle_points(renderer, color, x, y, x1, y1, fill);
232
233 while (y1 >= x1) {
234 if (d > 0) {
235 y1--;
236 d = d + 4 * (x1 - y1) + 10;
237 }
238 else
239 d = d + 4 * x1 + 6;
240
241 x1++;
242
243 circle_points(renderer, color, x, y, x1, y1, fill);
244 }
245}
246
247EXPORT
248void
249wld_draw_line(struct wld_renderer *renderer, uint32_t color,
250 int32_t x1, int32_t y1, int32_t x2, int32_t y2)
251{
252 int32_t dx = abs(x2-x1), sx = x1<x2 ? 1 : -1;
253 int32_t dy = -abs(y2-y1), sy = y1<y2 ? 1 : -1;
254 int32_t err = dx+dy, e2;
255
256 while(true) {
257 renderer->impl->fill_rectangle(renderer, color, x1, y1, 1, 1);
258
259 if (x1==x2 && y1==y2)
260 break;
261
262 e2 = 2*err;
263
264 if (e2 >= dy) {
265 err += dy;
266 x1 += sx;
267 }
268
269 if (e2 <= dx) {
270 err += dx;
271 y1 += sy;
272 }
273 }
274}
275
276EXPORT
277void
278wld_draw_text(struct wld_renderer *renderer,
279 struct wld_font *font_base, uint32_t color,
280 int32_t x, int32_t y, const char *text, uint32_t length,
281 struct wld_extents *extents)
282{
283 struct font *font = (void *)font_base;
284
285 renderer->impl->draw_text(renderer, font, color, x, y, text, length,
286 extents);
287}
288
289EXPORT
290void
291wld_flush(struct wld_renderer *renderer)
292{
293 renderer->impl->flush(renderer);
294 if (renderer->target && ((struct buffer *)renderer->target)->base.impl->flush)
295 ((struct buffer *)renderer->target)->base.impl->flush(
296 (struct buffer *)renderer->target);
297 renderer->impl->set_target(renderer, NULL);
298 renderer->target = NULL;
299}