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 return renderer->impl->set_target(renderer, back_buffer);
103}
104
105EXPORT
106void
107wld_fill_rectangle(struct wld_renderer *renderer, uint32_t color,
108 int32_t x, int32_t y, uint32_t width, uint32_t height)
109{
110 renderer->impl->fill_rectangle(renderer, color, x, y, width, height);
111}
112
113EXPORT
114void
115wld_fill_region(struct wld_renderer *renderer, uint32_t color, pixman_region32_t *region)
116{
117 renderer->impl->fill_region(renderer, color, region);
118}
119
120EXPORT
121void
122wld_copy_rectangle(struct wld_renderer *renderer,
123 struct wld_buffer *buffer,
124 int32_t dst_x, int32_t dst_y,
125 int32_t src_x, int32_t src_y,
126 uint32_t width, uint32_t height)
127{
128 renderer->impl->copy_rectangle(renderer, (struct buffer *)buffer,
129 dst_x, dst_y, src_x, src_y, width, height);
130}
131
132EXPORT
133void
134wld_copy_region(struct wld_renderer *renderer,
135 struct wld_buffer *buffer,
136 int32_t dst_x, int32_t dst_y, pixman_region32_t *region)
137{
138 renderer->impl->copy_region(renderer, (struct buffer *)buffer,
139 dst_x, dst_y, region);
140}
141
142
143/* https://en.wikipedia.org/wiki/Midpoint_circle_algorithm */
144static void
145circle_points(struct wld_renderer *renderer, uint32_t color,
146 int32_t x1, int32_t y1, int32_t x2, int32_t y2, bool fill)
147{
148 /* hacky */
149 if (fill) {
150 renderer->impl->fill_rectangle(renderer, color, x1-x2, y1+y2, 2*x2 + 1, 1);
151 renderer->impl->fill_rectangle(renderer, color, x1-x2, y1-y2, 2*x2 + 1, 1);
152 renderer->impl->fill_rectangle(renderer, color, x1-y2, y1+x2, 2*y2 + 1, 1);
153 renderer->impl->fill_rectangle(renderer, color, x1-y2, y1-x2, 2*y2 + 1, 1);
154 }
155
156 else {
157 renderer->impl->fill_rectangle(renderer, color, x1+x2, y1+y2, 1, 1);
158 renderer->impl->fill_rectangle(renderer, color, x1-x2, y1+y2, 1, 1);
159 renderer->impl->fill_rectangle(renderer, color, x1+x2, y1-y2, 1, 1);
160 renderer->impl->fill_rectangle(renderer, color, x1-x2, y1-y2, 1, 1);
161 renderer->impl->fill_rectangle(renderer, color, x1+y2, y1+x2, 1, 1);
162 renderer->impl->fill_rectangle(renderer, color, x1-y2, y1+x2, 1, 1);
163 renderer->impl->fill_rectangle(renderer, color, x1+y2, y1-x2, 1, 1);
164 renderer->impl->fill_rectangle(renderer, color, x1-y2, y1-x2, 1, 1);
165 }
166}
167
168EXPORT
169void
170wld_draw_circle(struct wld_renderer *renderer, uint32_t color,
171 int32_t x, int32_t y, uint32_t r, bool fill)
172{
173 int32_t x1 = 0, y1 = r;
174 int32_t d = 3 - 2 * r;
175 circle_points(renderer, color, x, y, x1, y1, fill);
176
177 while (y1 >= x1) {
178 if (d > 0) {
179 y1--;
180 d = d + 4 * (x1 - y1) + 10;
181 }
182 else
183 d = d + 4 * x1 + 6;
184
185 x1++;
186
187 circle_points(renderer, color, x, y, x1, y1, fill);
188 }
189}
190
191EXPORT
192void
193wld_draw_line(struct wld_renderer *renderer, uint32_t color,
194 int32_t x1, int32_t y1, int32_t x2, int32_t y2)
195{
196 int32_t dx = abs(x2-x1), sx = x1<x2 ? 1 : -1;
197 int32_t dy = -abs(y2-y1), sy = y1<y2 ? 1 : -1;
198 int32_t err = dx+dy, e2;
199
200 while(true) {
201 renderer->impl->fill_rectangle(renderer, color, x1, y1, 1, 1);
202
203 if (x1==x2 && y1==y2)
204 break;
205
206 e2 = 2*err;
207
208 if (e2 >= dy) {
209 err += dy;
210 x1 += sx;
211 }
212
213 if (e2 <= dx) {
214 err += dx;
215 y1 += sy;
216 }
217 }
218}
219
220EXPORT
221void
222wld_draw_text(struct wld_renderer *renderer,
223 struct wld_font *font_base, uint32_t color,
224 int32_t x, int32_t y, const char *text, uint32_t length,
225 struct wld_extents *extents)
226{
227 struct font *font = (void *)font_base;
228
229 renderer->impl->draw_text(renderer, font, color, x, y, text, length,
230 extents);
231}
232
233EXPORT
234void
235wld_flush(struct wld_renderer *renderer)
236{
237 renderer->impl->flush(renderer);
238 renderer->impl->set_target(renderer, NULL);
239}