source: mainline/uspace/lib/guigfx/src/canvas.c@ bea947f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since bea947f was bea947f, checked in by Jiri Svoboda <jiri@…>, 5 years ago

Implement bitmap color key to allow transparent cursor background

This seems to be the simplest solution of them all. It will work
on any bit depth except 1 bit per pixel (monochrome), where we would
need to extend the bitmap with a bit mask instead.

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/*
2 * Copyright (c) 2019 Jiri Svoboda
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 libguigfx
30 * @{
31 */
32/**
33 * @file GFX canvas backend
34 *
35 * This implements a graphics context over a libgui canvas.
36 * This is just for experimentation purposes and its kind of backwards.
37 */
38
39#include <draw/drawctx.h>
40#include <draw/source.h>
41#include <gfx/color.h>
42#include <gfx/context.h>
43#include <gfx/render.h>
44#include <guigfx/canvas.h>
45#include <io/pixel.h>
46#include <stdlib.h>
47#include <transform.h>
48#include "../private/canvas.h"
49//#include "../../private/color.h"
50
51static errno_t canvas_gc_set_color(void *, gfx_color_t *);
52static errno_t canvas_gc_fill_rect(void *, gfx_rect_t *);
53static errno_t canvas_gc_bitmap_create(void *, gfx_bitmap_params_t *,
54 gfx_bitmap_alloc_t *, void **);
55static errno_t canvas_gc_bitmap_destroy(void *);
56static errno_t canvas_gc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
57static errno_t canvas_gc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
58
59gfx_context_ops_t canvas_gc_ops = {
60 .set_color = canvas_gc_set_color,
61 .fill_rect = canvas_gc_fill_rect,
62 .bitmap_create = canvas_gc_bitmap_create,
63 .bitmap_destroy = canvas_gc_bitmap_destroy,
64 .bitmap_render = canvas_gc_bitmap_render,
65 .bitmap_get_alloc = canvas_gc_bitmap_get_alloc
66};
67
68/** Set color on canvas GC.
69 *
70 * Set drawing color on canvas GC.
71 *
72 * @param arg Canvas GC
73 * @param color Color
74 *
75 * @return EOK on success or an error code
76 */
77static errno_t canvas_gc_set_color(void *arg, gfx_color_t *color)
78{
79 canvas_gc_t *cgc = (canvas_gc_t *) arg;
80 uint16_t r, g, b;
81
82 gfx_color_get_rgb_i16(color, &r, &g, &b);
83 cgc->color = PIXEL(0, r >> 8, g >> 8, b >> 8);
84 return EOK;
85}
86
87/** Fill rectangle on canvas GC.
88 *
89 * @param arg Canvas GC
90 * @param rect Rectangle
91 *
92 * @return EOK on success or an error code
93 */
94static errno_t canvas_gc_fill_rect(void *arg, gfx_rect_t *rect)
95{
96 canvas_gc_t *cgc = (canvas_gc_t *) arg;
97 gfx_coord_t x, y;
98
99 // XXX We should handle p0.x > p1.x and p0.y > p1.y
100
101 for (y = rect->p0.y; y < rect->p1.y; y++) {
102 for (x = rect->p0.x; x < rect->p1.x; x++) {
103 surface_put_pixel(cgc->surface, x, y, cgc->color);
104 }
105 }
106
107 update_canvas(cgc->canvas, cgc->surface);
108
109 return EOK;
110}
111
112/** Create canvas GC.
113 *
114 * Create graphics context for rendering into a canvas.
115 *
116 * @param con Canvas object
117 * @param fout File to which characters are written (canvas)
118 * @param rgc Place to store pointer to new GC.
119 *
120 * @return EOK on success or an error code
121 */
122errno_t canvas_gc_create(canvas_t *canvas, surface_t *surface,
123 canvas_gc_t **rgc)
124{
125 canvas_gc_t *cgc = NULL;
126 gfx_context_t *gc = NULL;
127 errno_t rc;
128
129 cgc = calloc(1, sizeof(canvas_gc_t));
130 if (cgc == NULL) {
131 rc = ENOMEM;
132 goto error;
133 }
134
135 rc = gfx_context_new(&canvas_gc_ops, cgc, &gc);
136 if (rc != EOK)
137 goto error;
138
139 cgc->gc = gc;
140 cgc->canvas = canvas;
141 cgc->surface = surface;
142 *rgc = cgc;
143 return EOK;
144error:
145 if (cgc != NULL)
146 free(cgc);
147 gfx_context_delete(gc);
148 return rc;
149}
150
151/** Delete canvas GC.
152 *
153 * @param cgc Canvas GC
154 */
155errno_t canvas_gc_delete(canvas_gc_t *cgc)
156{
157 errno_t rc;
158
159 rc = gfx_context_delete(cgc->gc);
160 if (rc != EOK)
161 return rc;
162
163 free(cgc);
164 return EOK;
165}
166
167/** Get generic graphic context from canvas GC.
168 *
169 * @param cgc Canvas GC
170 * @return Graphic context
171 */
172gfx_context_t *canvas_gc_get_ctx(canvas_gc_t *cgc)
173{
174 return cgc->gc;
175}
176
177/** Create bitmap in canvas GC.
178 *
179 * @param arg Canvas GC
180 * @param params Bitmap params
181 * @param alloc Bitmap allocation info or @c NULL
182 * @param rbm Place to store pointer to new bitmap
183 * @return EOK on success or an error code
184 */
185errno_t canvas_gc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
186 gfx_bitmap_alloc_t *alloc, void **rbm)
187{
188 canvas_gc_t *cgc = (canvas_gc_t *) arg;
189 canvas_gc_bitmap_t *cbm = NULL;
190 gfx_coord2_t dim;
191 errno_t rc;
192
193 cbm = calloc(1, sizeof(canvas_gc_bitmap_t));
194 if (cbm == NULL)
195 return ENOMEM;
196
197 gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
198 cbm->rect = params->rect;
199 cbm->flags = params->flags;
200 cbm->key_color = params->key_color;
201
202 if (alloc == NULL) {
203 cbm->surface = surface_create(dim.x, dim.y, NULL, 0);
204 if (cbm->surface == NULL) {
205 rc = ENOMEM;
206 goto error;
207 }
208
209 cbm->alloc.pitch = dim.x * sizeof(uint32_t);
210 cbm->alloc.off0 = 0;
211 cbm->alloc.pixels = surface_direct_access(cbm->surface);
212 cbm->myalloc = true;
213 } else {
214 cbm->surface = surface_create(dim.x, dim.y, alloc->pixels, 0);
215 if (cbm->surface == NULL) {
216 rc = ENOMEM;
217 goto error;
218 }
219
220 cbm->alloc = *alloc;
221 }
222
223 cbm->cgc = cgc;
224 *rbm = (void *)cbm;
225 return EOK;
226error:
227 if (cbm != NULL)
228 free(cbm);
229 return rc;
230}
231
232/** Destroy bitmap in canvas GC.
233 *
234 * @param bm Bitmap
235 * @return EOK on success or an error code
236 */
237static errno_t canvas_gc_bitmap_destroy(void *bm)
238{
239 canvas_gc_bitmap_t *cbm = (canvas_gc_bitmap_t *)bm;
240 if (cbm->myalloc)
241 surface_destroy(cbm->surface);
242 // XXX if !cbm->myalloc, surface is leaked - no way to destroy it
243 // without destroying the pixel buffer
244 free(cbm);
245 return EOK;
246}
247
248/** Render bitmap in canvas GC.
249 *
250 * @param bm Bitmap
251 * @param srect0 Source rectangle or @c NULL
252 * @param offs0 Offset or @c NULL
253 * @return EOK on success or an error code
254 */
255static errno_t canvas_gc_bitmap_render(void *bm, gfx_rect_t *srect0,
256 gfx_coord2_t *offs0)
257{
258 canvas_gc_bitmap_t *cbm = (canvas_gc_bitmap_t *)bm;
259 gfx_rect_t srect;
260 gfx_rect_t drect;
261 gfx_coord2_t offs;
262 gfx_coord2_t dim;
263 gfx_coord_t x, y;
264 pixel_t pixel;
265
266 if (srect0 != NULL)
267 srect = *srect0;
268 else
269 srect = cbm->rect;
270
271 if (offs0 != NULL) {
272 offs = *offs0;
273 } else {
274 offs.x = 0;
275 offs.y = 0;
276 }
277
278 /* Destination rectangle */
279 gfx_rect_translate(&offs, &srect, &drect);
280
281 gfx_coord2_subtract(&drect.p1, &drect.p0, &dim);
282
283 transform_t transform;
284 transform_identity(&transform);
285 transform_translate(&transform, offs.x - cbm->rect.p0.x,
286 offs.y - cbm->rect.p0.y);
287
288 source_t source;
289 source_init(&source);
290 source_set_transform(&source, transform);
291 source_set_texture(&source, cbm->surface,
292 PIXELMAP_EXTEND_TRANSPARENT_BLACK);
293
294 if ((cbm->flags & bmpf_color_key) == 0) {
295 drawctx_t drawctx;
296 drawctx_init(&drawctx, cbm->cgc->surface);
297
298 drawctx_set_source(&drawctx, &source);
299 drawctx_transfer(&drawctx, drect.p0.x, drect.p0.y, dim.x, dim.y);
300 } else {
301 for (y = drect.p0.y; y < drect.p1.y; y++) {
302 for (x = drect.p0.x; x < drect.p1.x; x++) {
303 pixel = source_determine_pixel(&source, x, y);
304 if (pixel != cbm->key_color) {
305 surface_put_pixel(cbm->cgc->surface,
306 x, y, pixel);
307 }
308 }
309 }
310 }
311
312 update_canvas(cbm->cgc->canvas, cbm->cgc->surface);
313 return EOK;
314}
315
316/** Get allocation info for bitmap in canvas GC.
317 *
318 * @param bm Bitmap
319 * @param alloc Place to store allocation info
320 * @return EOK on success or an error code
321 */
322static errno_t canvas_gc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
323{
324 canvas_gc_bitmap_t *cbm = (canvas_gc_bitmap_t *)bm;
325 *alloc = cbm->alloc;
326 return EOK;
327}
328
329/** @}
330 */
Note: See TracBrowser for help on using the repository browser.