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}