source: mainline/uspace/lib/congfx/src/console.c

Last change on this file was 211fd68, checked in by Jiri Svoboda <jiri@…>, 16 months ago

Add text mode support to Barber

  • Property mode set to 100644
File size: 13.3 KB
Line 
1/*
2 * Copyright (c) 2024 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) == 0xff) {
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;
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/** Free up console for other users, suspending GC operation.
284 *
285 * @param cgc Console GC
286 * @return EOK on success or an error code
287 */
288errno_t console_gc_suspend(console_gc_t *cgc)
289{
290 console_unmap(cgc->con, cgc->buf);
291 cgc->buf = NULL;
292
293 console_clear(cgc->con);
294 console_cursor_visibility(cgc->con, true);
295 return EOK;
296}
297
298/** Resume GC operation after suspend.
299 *
300 * @param cgc Console GC
301 * @return EOK on success or an error code
302 */
303errno_t console_gc_resume(console_gc_t *cgc)
304{
305 errno_t rc;
306
307 console_clear(cgc->con);
308
309 rc = console_map(cgc->con, cgc->rect.p1.x, cgc->rect.p1.y, &cgc->buf);
310 if (rc != EOK)
311 return rc;
312
313 return EOK;
314}
315
316/** Get generic graphic context from console GC.
317 *
318 * @param cgc Console GC
319 * @return Graphic context
320 */
321gfx_context_t *console_gc_get_ctx(console_gc_t *cgc)
322{
323 return cgc->gc;
324}
325
326/** Create bitmap in console GC.
327 *
328 * @param arg console GC
329 * @param params Bitmap params
330 * @param alloc Bitmap allocation info or @c NULL
331 * @param rbm Place to store pointer to new bitmap
332 * @return EOK on success or an error code
333 */
334errno_t console_gc_bitmap_create(void *arg, gfx_bitmap_params_t *params,
335 gfx_bitmap_alloc_t *alloc, void **rbm)
336{
337 console_gc_t *cgc = (console_gc_t *) arg;
338 console_gc_bitmap_t *cbm = NULL;
339 gfx_coord2_t dim;
340 errno_t rc;
341
342 /* Check that we support all requested flags */
343 if ((params->flags & ~(bmpf_color_key | bmpf_colorize)) != 0)
344 return ENOTSUP;
345
346 cbm = calloc(1, sizeof(console_gc_bitmap_t));
347 if (cbm == NULL)
348 return ENOMEM;
349
350 gfx_coord2_subtract(&params->rect.p1, &params->rect.p0, &dim);
351 cbm->rect = params->rect;
352 cbm->flags = params->flags;
353 cbm->key_color = params->key_color;
354
355 if (alloc == NULL) {
356 cbm->alloc.pitch = dim.x * sizeof(uint32_t);
357 cbm->alloc.off0 = 0;
358 cbm->alloc.pixels = calloc(dim.x * dim.y, sizeof(uint32_t));
359 if (cbm->alloc.pixels == NULL) {
360 rc = ENOMEM;
361 goto error;
362 }
363
364 cbm->myalloc = true;
365 } else {
366 cbm->alloc = *alloc;
367 }
368
369 cbm->cgc = cgc;
370 *rbm = (void *)cbm;
371 return EOK;
372error:
373 if (cbm != NULL)
374 free(cbm);
375 return rc;
376}
377
378/** Destroy bitmap in console GC.
379 *
380 * @param bm Bitmap
381 * @return EOK on success or an error code
382 */
383static errno_t console_gc_bitmap_destroy(void *bm)
384{
385 console_gc_bitmap_t *cbm = (console_gc_bitmap_t *)bm;
386 if (cbm->myalloc)
387 free(cbm->alloc.pixels);
388 free(cbm);
389 return EOK;
390}
391
392/** Render bitmap in console GC.
393 *
394 * @param bm Bitmap
395 * @param srect0 Source rectangle or @c NULL
396 * @param offs0 Offset or @c NULL
397 * @return EOK on success or an error code
398 */
399static errno_t console_gc_bitmap_render(void *bm, gfx_rect_t *srect0,
400 gfx_coord2_t *offs0)
401{
402 console_gc_bitmap_t *cbm = (console_gc_bitmap_t *)bm;
403 gfx_coord_t x, y;
404 pixel_t clr;
405 charfield_t ch;
406 pixelmap_t pixelmap;
407 gfx_rect_t srect;
408 gfx_rect_t drect;
409 gfx_rect_t crect;
410 gfx_coord2_t offs;
411 gfx_coord_t cols;
412
413 if (srect0 != NULL)
414 srect = *srect0;
415 else
416 srect = cbm->rect;
417
418 if (offs0 != NULL) {
419 offs = *offs0;
420 } else {
421 offs.x = 0;
422 offs.y = 0;
423 }
424
425 gfx_rect_translate(&offs, &srect, &drect);
426 gfx_rect_clip(&drect, &cbm->cgc->clip_rect, &crect);
427
428 pixelmap.width = cbm->rect.p1.x - cbm->rect.p0.x;
429 pixelmap.height = cbm->rect.p1.y = cbm->rect.p1.y;
430 pixelmap.data = cbm->alloc.pixels;
431
432 cols = cbm->cgc->rect.p1.x - cbm->cgc->rect.p0.x;
433
434 if ((cbm->flags & bmpf_color_key) == 0) {
435 /* Simple copy */
436 for (y = crect.p0.y; y < crect.p1.y; y++) {
437 for (x = crect.p0.x; x < crect.p1.x; x++) {
438 clr = pixelmap_get_pixel(&pixelmap,
439 x - offs.x - cbm->rect.p0.x,
440 y - offs.y - cbm->rect.p0.y);
441
442 console_gc_pix_to_charfield(clr, &ch);
443 cbm->cgc->buf[y * cols + x] = ch;
444 }
445 }
446 } else if ((cbm->flags & bmpf_colorize) == 0) {
447 /* Color key */
448 for (y = crect.p0.y; y < crect.p1.y; y++) {
449 for (x = crect.p0.x; x < crect.p1.x; x++) {
450
451 clr = pixelmap_get_pixel(&pixelmap,
452 x - offs.x - cbm->rect.p0.x,
453 y - offs.y - cbm->rect.p0.y);
454
455 console_gc_pix_to_charfield(clr, &ch);
456
457 if (clr != cbm->key_color)
458 cbm->cgc->buf[y * cols + x] = ch;
459 }
460 }
461 } else {
462 /* Color key & colorize */
463 console_gc_pix_to_charfield(cbm->cgc->clr, &ch);
464
465 for (y = crect.p0.y; y < crect.p1.y; y++) {
466 for (x = crect.p0.x; x < crect.p1.x; x++) {
467 clr = pixelmap_get_pixel(&pixelmap,
468 x - offs.x - cbm->rect.p0.x,
469 y - offs.y - cbm->rect.p0.y);
470
471 if (clr != cbm->key_color)
472 cbm->cgc->buf[y * cols + x] = ch;
473 }
474 }
475 }
476
477 console_update(cbm->cgc->con, crect.p0.x, crect.p0.y, crect.p1.x,
478 crect.p1.y);
479
480 return EOK;
481}
482
483/** Get allocation info for bitmap in console GC.
484 *
485 * @param bm Bitmap
486 * @param alloc Place to store allocation info
487 * @return EOK on success or an error code
488 */
489static errno_t console_gc_bitmap_get_alloc(void *bm, gfx_bitmap_alloc_t *alloc)
490{
491 console_gc_bitmap_t *cbm = (console_gc_bitmap_t *)bm;
492 *alloc = cbm->alloc;
493 return EOK;
494}
495
496/** Get cursor position on console GC.
497 *
498 * @param arg Console GC
499 * @param pos Place to store position
500 *
501 * @return EOK on success or an error code
502 */
503static errno_t console_gc_cursor_get_pos(void *arg, gfx_coord2_t *pos)
504{
505 console_gc_t *cgc = (console_gc_t *) arg;
506 sysarg_t col;
507 sysarg_t row;
508 errno_t rc;
509
510 rc = console_get_pos(cgc->con, &col, &row);
511 if (rc != EOK)
512 return rc;
513
514 pos->x = col;
515 pos->y = row;
516 return EOK;
517}
518
519/** Set cursor position on console GC.
520 *
521 * @param arg Console GC
522 * @param pos New cursor position
523 *
524 * @return EOK on success or an error code
525 */
526static errno_t console_gc_cursor_set_pos(void *arg, gfx_coord2_t *pos)
527{
528 console_gc_t *cgc = (console_gc_t *) arg;
529
530 console_set_pos(cgc->con, pos->x, pos->y);
531 return EOK;
532}
533
534/** Set cursor visibility on console GC.
535 *
536 * @param arg Console GC
537 * @param visible @c true iff cursor should be made visible
538 *
539 * @return EOK on success or an error code
540 */
541static errno_t console_gc_cursor_set_visible(void *arg, bool visible)
542{
543 console_gc_t *cgc = (console_gc_t *) arg;
544
545 console_cursor_visibility(cgc->con, visible);
546 return EOK;
547}
548
549/** @}
550 */
Note: See TracBrowser for help on using the repository browser.