1 | /*
|
---|
2 | * Copyright (c) 2012 Petr Koupy
|
---|
3 | * All rights reserved.
|
---|
4 | *
|
---|
5 | * Redistribution and use in source and binary forms, with or without
|
---|
6 | * modification, are permitted provided that the following conditions
|
---|
7 | * are met:
|
---|
8 | *
|
---|
9 | * - Redistributions of source code must retain the above copyright
|
---|
10 | * notice, this list of conditions and the following disclaimer.
|
---|
11 | * - Redistributions in binary form must reproduce the above copyright
|
---|
12 | * notice, this list of conditions and the following disclaimer in the
|
---|
13 | * documentation and/or other materials provided with the distribution.
|
---|
14 | * - The name of the author may not be used to endorse or promote products
|
---|
15 | * derived from this software without specific prior written permission.
|
---|
16 | *
|
---|
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
---|
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
---|
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
---|
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
---|
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
---|
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
---|
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
---|
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
---|
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
27 | */
|
---|
28 |
|
---|
29 | /** @addtogroup draw
|
---|
30 | * @{
|
---|
31 | */
|
---|
32 | /**
|
---|
33 | * @file
|
---|
34 | */
|
---|
35 |
|
---|
36 | #include <assert.h>
|
---|
37 | #include <adt/list.h>
|
---|
38 | #include <malloc.h>
|
---|
39 |
|
---|
40 | #include "drawctx.h"
|
---|
41 |
|
---|
42 | void drawctx_init(drawctx_t *context, surface_t *surface)
|
---|
43 | {
|
---|
44 | assert(surface);
|
---|
45 | list_initialize(&context->list);
|
---|
46 | context->surface = surface;
|
---|
47 | context->compose = compose_src;
|
---|
48 | context->mask = NULL;
|
---|
49 | context->source = NULL;
|
---|
50 | context->shall_clip = false;
|
---|
51 | context->clip_x = 0;
|
---|
52 | context->clip_y = 0;
|
---|
53 | surface_get_resolution(surface, &context->clip_width, &context->clip_height);
|
---|
54 | }
|
---|
55 |
|
---|
56 | void drawctx_save(drawctx_t *context)
|
---|
57 | {
|
---|
58 | drawctx_t *to_save = (drawctx_t *) malloc(sizeof(drawctx_t));
|
---|
59 | if (to_save) {
|
---|
60 | link_initialize(&to_save->link);
|
---|
61 | to_save->compose = context->compose;
|
---|
62 | to_save->mask = context->mask;
|
---|
63 | to_save->source = context->source;
|
---|
64 | to_save->shall_clip = context->shall_clip;
|
---|
65 | to_save->clip_x = context->clip_x;
|
---|
66 | to_save->clip_y = context->clip_y;
|
---|
67 | to_save->clip_width = context->clip_width;
|
---|
68 | to_save->clip_height = context->clip_height;
|
---|
69 | list_append(&to_save->link, &context->list);
|
---|
70 | }
|
---|
71 | }
|
---|
72 |
|
---|
73 | void drawctx_restore(drawctx_t *context)
|
---|
74 | {
|
---|
75 | drawctx_t *to_load = (drawctx_t *) list_last(&context->list);
|
---|
76 | if (to_load) {
|
---|
77 | list_remove(&to_load->link);
|
---|
78 | context->compose = to_load->compose;
|
---|
79 | context->mask = to_load->mask;
|
---|
80 | context->source = to_load->source;
|
---|
81 | context->shall_clip = to_load->shall_clip;
|
---|
82 | context->clip_x = to_load->clip_x;
|
---|
83 | context->clip_y = to_load->clip_y;
|
---|
84 | context->clip_width = to_load->clip_width;
|
---|
85 | context->clip_height = to_load->clip_height;
|
---|
86 | free(to_load);
|
---|
87 | }
|
---|
88 | }
|
---|
89 |
|
---|
90 | void drawctx_set_compose(drawctx_t *context, compose_t compose)
|
---|
91 | {
|
---|
92 | context->compose = compose;
|
---|
93 | }
|
---|
94 |
|
---|
95 | void drawctx_set_clip(drawctx_t *context,
|
---|
96 | sysarg_t x, sysarg_t y, sysarg_t width, sysarg_t height)
|
---|
97 | {
|
---|
98 | surface_get_resolution(context->surface,
|
---|
99 | &context->clip_width, &context->clip_height);
|
---|
100 | context->shall_clip = (x > 0) || (y > 0) ||
|
---|
101 | (width < context->clip_width) || (height < context->clip_height);
|
---|
102 |
|
---|
103 | context->clip_x = x;
|
---|
104 | context->clip_y = y;
|
---|
105 | context->clip_width = width;
|
---|
106 | context->clip_height = height;
|
---|
107 | }
|
---|
108 |
|
---|
109 | void drawctx_set_mask(drawctx_t *context, surface_t *mask)
|
---|
110 | {
|
---|
111 | context->mask = mask;
|
---|
112 | }
|
---|
113 |
|
---|
114 | void drawctx_set_source(drawctx_t *context, source_t *source)
|
---|
115 | {
|
---|
116 | context->source = source;
|
---|
117 | }
|
---|
118 |
|
---|
119 | void drawctx_set_font(drawctx_t *context, font_t *font)
|
---|
120 | {
|
---|
121 | context->font = font;
|
---|
122 | }
|
---|
123 |
|
---|
124 | void drawctx_transfer(drawctx_t *context,
|
---|
125 | sysarg_t x, sysarg_t y, sysarg_t width, sysarg_t height)
|
---|
126 | {
|
---|
127 | if (!context->source) {
|
---|
128 | return;
|
---|
129 | }
|
---|
130 |
|
---|
131 | bool transfer_fast = source_is_fast(context->source) &&
|
---|
132 | (context->shall_clip == false) &&
|
---|
133 | (context->mask == NULL) &&
|
---|
134 | (context->compose == compose_src || context->compose == compose_over);
|
---|
135 |
|
---|
136 | if (transfer_fast) {
|
---|
137 |
|
---|
138 | for (sysarg_t _y = y; _y < y + height; ++_y) {
|
---|
139 | pixel_t *src = source_direct_access(context->source, x, _y);
|
---|
140 | pixel_t *dst = pixelmap_pixel_at(surface_pixmap_access(context->surface), x, _y);
|
---|
141 | if (src && dst) {
|
---|
142 | sysarg_t count = width;
|
---|
143 | while (count-- != 0) {
|
---|
144 | *dst++ = *src++;
|
---|
145 | }
|
---|
146 | }
|
---|
147 | }
|
---|
148 | surface_add_damaged_region(context->surface, x, y, width, height);
|
---|
149 |
|
---|
150 | } else {
|
---|
151 |
|
---|
152 | bool clipped = false;
|
---|
153 | bool masked = false;
|
---|
154 | for (sysarg_t _y = y; _y < y + height; ++_y) {
|
---|
155 | for (sysarg_t _x = x; _x < x + width; ++_x) {
|
---|
156 | if (context->shall_clip) {
|
---|
157 | clipped = _x < context->clip_x && _x >= context->clip_width
|
---|
158 | && _y < context->clip_y && _y >= context->clip_height;
|
---|
159 | }
|
---|
160 |
|
---|
161 | if (context->mask) {
|
---|
162 | pixel_t p = surface_get_pixel(context->mask, _x, _y);
|
---|
163 | masked = p > 0 ? false : true;
|
---|
164 | }
|
---|
165 |
|
---|
166 | if (!clipped && !masked) {
|
---|
167 | pixel_t p_src = source_determine_pixel(context->source, _x, _y);
|
---|
168 | pixel_t p_dst = surface_get_pixel(context->surface, _x, _y);
|
---|
169 | pixel_t p_res = context->compose(p_src, p_dst);
|
---|
170 | surface_put_pixel(context->surface, _x, _y, p_res);
|
---|
171 | }
|
---|
172 | }
|
---|
173 | }
|
---|
174 |
|
---|
175 | }
|
---|
176 | }
|
---|
177 |
|
---|
178 | void drawctx_stroke(drawctx_t *context, path_t *path)
|
---|
179 | {
|
---|
180 | if (!context->source || !path) {
|
---|
181 | return;
|
---|
182 | }
|
---|
183 |
|
---|
184 | /* Note:
|
---|
185 | * Antialiasing could be achieved by up-scaling path coordinates and
|
---|
186 | * rendering into temporary higher-resolution surface. Then, the temporary
|
---|
187 | * surface would be set as a source and its damaged region would be
|
---|
188 | * transferred to the original surface. */
|
---|
189 |
|
---|
190 | list_foreach(*((list_t *) path), link, path_step_t, step) {
|
---|
191 | switch (step->type) {
|
---|
192 | case PATH_STEP_MOVETO:
|
---|
193 | // TODO
|
---|
194 | break;
|
---|
195 | case PATH_STEP_LINETO:
|
---|
196 | // TODO
|
---|
197 | break;
|
---|
198 | default:
|
---|
199 | break;
|
---|
200 | }
|
---|
201 | }
|
---|
202 | }
|
---|
203 |
|
---|
204 | void drawctx_fill(drawctx_t *context, path_t *path)
|
---|
205 | {
|
---|
206 | if (!context->source || !path) {
|
---|
207 | return;
|
---|
208 | }
|
---|
209 |
|
---|
210 | // TODO
|
---|
211 | }
|
---|
212 |
|
---|
213 | void drawctx_print(drawctx_t *context, const char *text, sysarg_t x, sysarg_t y)
|
---|
214 | {
|
---|
215 | if (context->font && context->source) {
|
---|
216 | font_draw_text(context->font, context, context->source, text, x, y);
|
---|
217 | }
|
---|
218 | }
|
---|
219 |
|
---|
220 | /** @}
|
---|
221 | */
|
---|