source: mainline/uspace/lib/congfx/src/console.c@ 68632b4

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

Allow the use of EGA attributes/24-bit characters alongside RGB

In a big hack (since we cannot have different pixel formats yet) we
use a pixel format that allows both 24-bit RGB (without character)
or 24-bit character with 8-bit attributes. Thus in GFX we cannot
currently have characters with any RGB color, but we can set
foreground and background individually (and it even works in EGA mode).

  • Property mode set to 100644
File size: 12.7 KB
Line 
1/*
2 * Copyright (c) 2021 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 libcongfx
30 * @{
31 */
32/**
33 * @file GFX console backend
34 *
35 * This implements a graphics context over a classic console interface.
36 * This is just for experimentation purposes. In the end we want the
37 * console to actually directly suport GFX interface.
38 */
39
40#include <congfx/console.h>
41#include <gfx/context.h>
42#include <gfx/coord.h>
43#include <gfx/render.h>
44#include <io/pixel.h>
45#include <io/pixelmap.h>
46#include <stdlib.h>
47#include "../private/console.h"
48#include "../private/color.h"
49
50static errno_t console_gc_set_clip_rect(void *, gfx_rect_t *);
51static errno_t console_gc_set_color(void *, gfx_color_t *);
52static errno_t console_gc_fill_rect(void *, gfx_rect_t *);
53static errno_t console_gc_update(void *);
54static errno_t console_gc_bitmap_create(void *, gfx_bitmap_params_t *,
55 gfx_bitmap_alloc_t *, void **);
56static errno_t console_gc_bitmap_destroy(void *);
57static errno_t console_gc_bitmap_render(void *, gfx_rect_t *, gfx_coord2_t *);
58static errno_t console_gc_bitmap_get_alloc(void *, gfx_bitmap_alloc_t *);
59static errno_t console_gc_cursor_get_pos(void *, gfx_coord2_t *);
60static errno_t console_gc_cursor_set_pos(void *, gfx_coord2_t *);
61static errno_t console_gc_cursor_set_visible(void *, bool);
62
63gfx_context_ops_t console_gc_ops = {
64 .set_clip_rect = console_gc_set_clip_rect,
65 .set_color = console_gc_set_color,
66 .fill_rect = console_gc_fill_rect,
67 .update = console_gc_update,
68 .bitmap_create = console_gc_bitmap_create,
69 .bitmap_destroy = console_gc_bitmap_destroy,
70 .bitmap_render = console_gc_bitmap_render,
71 .bitmap_get_alloc = console_gc_bitmap_get_alloc,
72 .cursor_get_pos = console_gc_cursor_get_pos,
73 .cursor_set_pos = console_gc_cursor_set_pos,
74 .cursor_set_visible = console_gc_cursor_set_visible
75};
76
77/** Convert pixel value to charfield.
78 *
79 * On the bottom of this function lies a big big hack. In the absence
80 * of support for different color formats (FIX ME!), here's a single
81 * format that can represent both 3x8bit RGB and 24-bit characters
82 * with 8-bit EGA attributes (i.e. we can specify the foreground and
83 * background colors individually).
84 *
85 * A R G B
86 * 0 red grn blu 24-bit color
87 * attr c2 c1 c0 attribute + 24-bit character
88 */
89static void console_gc_pix_to_charfield(pixel_t clr, charfield_t *ch)
90{
91 uint8_t attr;
92
93 if ((clr >> 24) == 0) {
94 /* RGB (no text) */
95 ch->ch = 0;
96 ch->flags = CHAR_FLAG_DIRTY;
97 ch->attrs.type = CHAR_ATTR_RGB;
98 ch->attrs.val.rgb.fgcolor = clr ^ 0xffffff;
99 ch->attrs.val.rgb.bgcolor = clr;
100 } else {
101 /* EGA attributes (with text) */
102 attr = clr >> 24;
103 ch->ch = clr & 0xffffff;
104 ch->flags = CHAR_FLAG_DIRTY;
105 ch->attrs.type = CHAR_ATTR_INDEX;
106 ch->attrs.val.index.fgcolor = attr & 0x7;
107 ch->attrs.val.index.bgcolor = (attr >> 4) & 0x7;
108 ch->attrs.val.index.attr =
109 ((attr & 0x8) ? CATTR_BRIGHT : 0) +
110 ((attr & 0x80) ? CATTR_BLINK : 0);
111 }
112}
113
114/** Set clipping rectangle on console GC.
115 *
116 * @param arg Console GC
117 * @param rect Rectangle
118 *
119 * @return EOK on success or an error code
120 */
121static errno_t console_gc_set_clip_rect(void *arg, gfx_rect_t *rect)
122{
123 console_gc_t *cgc = (console_gc_t *) arg;
124
125 if (rect != NULL)
126 gfx_rect_clip(rect, &cgc->rect, &cgc->clip_rect);
127 else
128 cgc->clip_rect = cgc->rect;
129
130 return EOK;
131}
132
133/** Set color on console GC.
134 *
135 * Set drawing color on console GC.
136 *
137 * @param arg Console GC
138 * @param color Color
139 *
140 * @return EOK on success or an error code
141 */
142static errno_t console_gc_set_color(void *arg, gfx_color_t *color)
143{
144 console_gc_t *cgc = (console_gc_t *) arg;
145
146 cgc->clr = PIXEL(color->attr, color->r >> 8, color->g >> 8, color->b >> 8);
147 return EOK;
148}
149
150/** Fill rectangle on console GC.
151 *
152 * @param arg Console GC
153 * @param rect Rectangle
154 *
155 * @return EOK on success or an error code
156 */
157static errno_t console_gc_fill_rect(void *arg, gfx_rect_t *rect)
158{
159 console_gc_t *cgc = (console_gc_t *) arg;
160 gfx_coord_t x, y;
161 gfx_coord_t cols;
162 gfx_rect_t crect;
163 charfield_t ch;
164
165 /* Make sure rectangle is clipped and sorted */
166 gfx_rect_clip(rect, &cgc->clip_rect, &crect);
167
168 cols = cgc->rect.p1.x - cgc->rect.p0.x;
169
170 console_gc_pix_to_charfield(cgc->clr, &ch);
171
172 for (y = crect.p0.y; y < crect.p1.y; y++) {
173 for (x = crect.p0.x; x < crect.p1.x; x++) {
174 cgc->buf[y * cols + x] = ch;
175 }
176 }
177
178 console_update(cgc->con, crect.p0.x, crect.p0.y,
179 crect.p1.x, crect.p1.y);
180
181 return EOK;
182}
183
184/** Update console GC.
185 *
186 * @param arg Console GC
187 *
188 * @return EOK on success or an error code
189 */
190static errno_t console_gc_update(void *arg)
191{
192 console_gc_t *cgc = (console_gc_t *) arg;
193
194 /*
195 * XXX Before actually deferring update to here (and similarly other
196 * GC implementations) need to make sure all consumers properly
197 * call update.
198 */
199 (void) cgc;
200 return EOK;
201}
202
203/** Create console GC.
204 *
205 * Create graphics context for rendering into a console.
206 *
207 * @param con Console object
208 * @param fout File to which characters are written (console)
209 * @param rgc Place to store pointer to new GC.
210 *
211 * @return EOK on success or an error code
212 */
213errno_t console_gc_create(console_ctrl_t *con, FILE *fout,
214 console_gc_t **rgc)
215{
216 console_gc_t *cgc = NULL;
217 gfx_context_t *gc = NULL;
218 sysarg_t rows;
219 sysarg_t cols;
220 charfield_t *buf = NULL;
221 errno_t rc;
222
223 cgc = calloc(1, sizeof(console_gc_t));
224 if (cgc == NULL) {
225 rc = ENOMEM;
226 goto error;
227 }
228
229 rc = console_get_size(con, &cols, &rows);
230 if (rc != EOK)
231 goto error;
232
233 console_clear(con);
234
235 rc = console_map(con, cols, rows, &buf);
236 if (rc != EOK)
237 goto error;
238
239 rc = gfx_context_new(&console_gc_ops, cgc, &gc);
240 if (rc != EOK)
241 goto error;
242
243 cgc->gc = gc;
244 cgc->con = con;
245 cgc->fout = fout;
246 cgc->rect.p0.x = 0;
247 cgc->rect.p0.y = 0;
248 cgc->rect.p1.x = cols;
249 cgc->rect.p1.y = rows;
250 cgc->clip_rect = cgc->rect;
251 cgc->buf = buf;
252
253 *rgc = cgc;
254 return EOK;
255error:
256 if (buf != NULL)
257 console_unmap(cgc->con, buf);
258 if (cgc != NULL)
259 free(cgc);
260 gfx_context_delete(gc);
261 return rc;
262}
263
264/** Delete console GC.
265 *
266 * @param cgc Console GC
267 */
268errno_t console_gc_delete(console_gc_t *cgc)
269{
270 errno_t rc;
271
272 rc = gfx_context_delete(cgc->gc);
273 if (rc != EOK)
274 return rc;
275
276 console_clear(cgc->con);
277 console_unmap(cgc->con, cgc->buf);
278
279 free(cgc);
280 return EOK;
281}
282
283/** Get generic graphic context from console GC.
284 *
285 * @param cgc Console GC
286 * @return Graphic context
287 */
288gfx_context_t *console_gc_get_ctx(console_gc_t *cgc)
289{
290 return cgc->gc;
291}
292
293/** Create bitmap in console GC.
294 *
295 * @param arg console GC
296 * @param params Bitmap params
297 * @param alloc Bitmap allocation info or @c NULL
298 * @param rbm Place to store pointer to new bitmap
299 * @return EOK on success or an error code
300 */
301errno_t console_gc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
302 gfx_bitmap_alloc_t *alloc, void **rbm)
303{
304 console_gc_t *cgc = (console_gc_t *) arg;
305 console_gc_bitmap_t *cbm = NULL;
306 gfx_coord2_t dim;
307 errno_t rc;
308
309 /* Check that we support all requested flags */
310 if ((params->flags & ~(bmpf_color_key | bmpf_colorize)) != 0)
311 return ENOTSUP;
312
313 cbm = calloc(1, sizeof(console_gc_bitmap_t));
314 if (cbm == NULL)
315 return ENOMEM;
316
317 gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
318 cbm->rect = params->rect;
319 cbm->flags = params->flags;
320 cbm->key_color = params->key_color;
321
322 if (alloc == NULL) {
323 cbm->alloc.pitch = dim.x * sizeof(uint32_t);
324 cbm->alloc.off0 = 0;
325 cbm->alloc.pixels = calloc(dim.x * dim.y, sizeof(uint32_t));
326 if (cbm->alloc.pixels == NULL) {
327 rc = ENOMEM;
328 goto error;
329 }
330
331 cbm->myalloc = true;
332 } else {
333 cbm->alloc = *alloc;
334 }
335
336 cbm->cgc = cgc;
337 *rbm = (void *)cbm;
338 return EOK;
339error:
340 if (cbm != NULL)
341 free(cbm);
342 return rc;
343}
344
345/** Destroy bitmap in console GC.
346 *
347 * @param bm Bitmap
348 * @return EOK on success or an error code
349 */
350static errno_t console_gc_bitmap_destroy(void *bm)
351{
352 console_gc_bitmap_t *cbm = (console_gc_bitmap_t *)bm;
353 if (cbm->myalloc)
354 free(cbm->alloc.pixels);
355 free(cbm);
356 return EOK;
357}
358
359/** Render bitmap in console GC.
360 *
361 * @param bm Bitmap
362 * @param srect0 Source rectangle or @c NULL
363 * @param offs0 Offset or @c NULL
364 * @return EOK on success or an error code
365 */
366static errno_t console_gc_bitmap_render(void *bm, gfx_rect_t *srect0,
367 gfx_coord2_t *offs0)
368{
369 console_gc_bitmap_t *cbm = (console_gc_bitmap_t *)bm;
370 gfx_coord_t x, y;
371 pixel_t clr;
372 charfield_t ch;
373 pixelmap_t pixelmap;
374 gfx_rect_t srect;
375 gfx_rect_t drect;
376 gfx_rect_t crect;
377 gfx_coord2_t offs;
378 gfx_coord_t cols;
379
380 if (srect0 != NULL)
381 srect = *srect0;
382 else
383 srect = cbm->rect;
384
385 if (offs0 != NULL) {
386 offs = *offs0;
387 } else {
388 offs.x = 0;
389 offs.y = 0;
390 }
391
392 gfx_rect_translate(&offs, &srect, &drect);
393 gfx_rect_clip(&drect, &cbm->cgc->clip_rect, &crect);
394
395 pixelmap.width = cbm->rect.p1.x - cbm->rect.p0.x;
396 pixelmap.height = cbm->rect.p1.y = cbm->rect.p1.y;
397 pixelmap.data = cbm->alloc.pixels;
398
399 cols = cbm->cgc->rect.p1.x - cbm->cgc->rect.p0.x;
400
401 if ((cbm->flags & bmpf_color_key) == 0) {
402 /* Simple copy */
403 for (y = crect.p0.y; y < crect.p1.y; y++) {
404 for (x = crect.p0.x; x < crect.p1.x; x++) {
405 clr = pixelmap_get_pixel(&pixelmap,
406 x - offs.x - cbm->rect.p0.x,
407 y - offs.y - cbm->rect.p0.y);
408
409 console_gc_pix_to_charfield(clr, &ch);
410 cbm->cgc->buf[y * cols + x] = ch;
411 }
412 }
413 } else if ((cbm->flags & bmpf_colorize) == 0) {
414 /* Color key */
415 for (y = crect.p0.y; y < crect.p1.y; y++) {
416 for (x = crect.p0.x; x < crect.p1.x; x++) {
417
418 clr = pixelmap_get_pixel(&pixelmap,
419 x - offs.x - cbm->rect.p0.x,
420 y - offs.y - cbm->rect.p0.y);
421
422 console_gc_pix_to_charfield(clr, &ch);
423
424 if (clr != cbm->key_color)
425 cbm->cgc->buf[y * cols + x] = ch;
426 }
427 }
428 } else {
429 /* Color key & colorize */
430 console_gc_pix_to_charfield(cbm->cgc->clr, &ch);
431
432 for (y = crect.p0.y; y < crect.p1.y; y++) {
433 for (x = crect.p0.x; x < crect.p1.x; x++) {
434 clr = pixelmap_get_pixel(&pixelmap,
435 x - offs.x - cbm->rect.p0.x,
436 y - offs.y - cbm->rect.p0.y);
437
438 if (clr != cbm->key_color)
439 cbm->cgc->buf[y * cols + x] = ch;
440 }
441 }
442 }
443
444 console_update(cbm->cgc->con, crect.p0.x, crect.p0.y, crect.p1.x,
445 crect.p1.y);
446
447 return EOK;
448}
449
450/** Get allocation info for bitmap in console GC.
451 *
452 * @param bm Bitmap
453 * @param alloc Place to store allocation info
454 * @return EOK on success or an error code
455 */
456static errno_t console_gc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
457{
458 console_gc_bitmap_t *cbm = (console_gc_bitmap_t *)bm;
459 *alloc = cbm->alloc;
460 return EOK;
461}
462
463/** Get cursor position on console GC.
464 *
465 * @param arg Console GC
466 * @param pos Place to store position
467 *
468 * @return EOK on success or an error code
469 */
470static errno_t console_gc_cursor_get_pos(void *arg, gfx_coord2_t *pos)
471{
472 console_gc_t *cgc = (console_gc_t *) arg;
473 sysarg_t col;
474 sysarg_t row;
475 errno_t rc;
476
477 rc = console_get_pos(cgc->con, &col, &row);
478 if (rc != EOK)
479 return rc;
480
481 pos->x = col;
482 pos->y = row;
483 return EOK;
484}
485
486/** Set cursor position on console GC.
487 *
488 * @param arg Console GC
489 * @param pos New cursor position
490 *
491 * @return EOK on success or an error code
492 */
493static errno_t console_gc_cursor_set_pos(void *arg, gfx_coord2_t *pos)
494{
495 console_gc_t *cgc = (console_gc_t *) arg;
496
497 console_set_pos(cgc->con, pos->x, pos->y);
498 return EOK;
499}
500
501/** Set cursor visibility on console GC.
502 *
503 * @param arg Console GC
504 * @param visible @c true iff cursor should be made visible
505 *
506 * @return EOK on success or an error code
507 */
508static errno_t console_gc_cursor_set_visible(void *arg, bool visible)
509{
510 console_gc_t *cgc = (console_gc_t *) arg;
511
512 console_cursor_visibility(cgc->con, visible);
513 return EOK;
514}
515
516/** @}
517 */
Note: See TracBrowser for help on using the repository browser.