source: mainline/uspace/app/gfxdemo/gfxdemo.c

Last change on this file was 8165a7a, checked in by Jiri Svoboda <jiri@…>, 3 months ago

GFX Demo should default to UI interface

  • Property mode set to 100644
File size: 26.7 KB
Line 
1/*
2 * Copyright (c) 2025 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 gfxdemo
30 * @{
31 */
32/** @file Graphic demo
33 */
34
35#include <congfx/console.h>
36#include <display.h>
37#include <fibril.h>
38#include <gfx/bitmap.h>
39#include <gfx/color.h>
40#include <gfx/render.h>
41#include <gfx/font.h>
42#include <gfx/text.h>
43#include <gfx/typeface.h>
44#include <io/console.h>
45#include <io/pixelmap.h>
46#include <stdbool.h>
47#include <stdlib.h>
48#include <str.h>
49#include <task.h>
50#include <ui/ui.h>
51#include <ui/window.h>
52#include <ui/wdecor.h>
53#include "gfxdemo.h"
54
55static void wnd_close_event(void *);
56static void wnd_kbd_event(void *, kbd_event_t *);
57
58static display_wnd_cb_t wnd_cb = {
59 .close_event = wnd_close_event,
60 .kbd_event = wnd_kbd_event
61};
62
63static void uiwnd_close_event(ui_window_t *, void *);
64static void uiwnd_kbd_event(ui_window_t *, void *, kbd_event_t *);
65
66static ui_window_cb_t ui_window_cb = {
67 .close = uiwnd_close_event,
68 .kbd = uiwnd_kbd_event
69};
70
71static void demo_kbd_event(kbd_event_t *);
72
73static bool quit = false;
74static FIBRIL_MUTEX_INITIALIZE(quit_lock);
75static FIBRIL_CONDVAR_INITIALIZE(quit_cv);
76static gfx_typeface_t *tface;
77static gfx_font_t *font;
78static gfx_coord_t vpad;
79static console_ctrl_t *con = NULL;
80static bool textmode;
81static ui_t *ui;
82
83/** Determine if we are running in text mode.
84 *
85 * @return @c true iff we are running in text mode
86 */
87static bool demo_is_text(void)
88{
89 return textmode;
90}
91
92/** Sleep until timeout or quit request.
93 *
94 * @param msec Number of microseconds to sleep for
95 */
96static void demo_msleep(unsigned msec)
97{
98 errno_t rc;
99 usec_t usec;
100 cons_event_t cevent;
101
102 if (ui != NULL)
103 ui_unlock(ui);
104 fibril_mutex_lock(&quit_lock);
105 if (!quit) {
106 if (con != NULL) {
107 usec = (usec_t)msec * 1000;
108 while (usec > 0 && !quit) {
109 rc = console_get_event_timeout(con, &cevent, &usec);
110 if (rc == EOK) {
111 if (cevent.type == CEV_KEY) {
112 fibril_mutex_unlock(&quit_lock);
113 demo_kbd_event(&cevent.ev.key);
114 fibril_mutex_lock(&quit_lock);
115 }
116 }
117 }
118 } else {
119 (void) fibril_condvar_wait_timeout(&quit_cv, &quit_lock,
120 (usec_t)msec * 1000);
121 }
122 }
123 fibril_mutex_unlock(&quit_lock);
124 if (ui != NULL)
125 ui_lock(ui);
126}
127
128/** Clear screen.
129 *
130 * @param gc Graphic context
131 * @param w Screen width
132 * @param h Screen height
133 */
134static errno_t clear_scr(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
135{
136 gfx_color_t *color = NULL;
137 gfx_rect_t rect;
138 errno_t rc;
139
140 rc = gfx_color_new_rgb_i16(0, 0, 0, &color);
141 if (rc != EOK)
142 goto error;
143
144 rc = gfx_set_color(gc, color);
145 if (rc != EOK)
146 goto error;
147
148 rect.p0.x = 0;
149 rect.p0.y = 0;
150 rect.p1.x = w;
151 rect.p1.y = h;
152
153 rc = gfx_fill_rect(gc, &rect);
154 if (rc != EOK)
155 goto error;
156
157 gfx_color_delete(color);
158 return EOK;
159error:
160 if (color != NULL)
161 gfx_color_delete(color);
162 return rc;
163}
164
165/** Initialize demo font.
166 *
167 * @param gc Graphic context
168 * @param w Width
169 * @param h Height
170 * @return EOK on success or an error code
171 */
172static errno_t demo_font_init(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
173{
174 gfx_font_info_t *finfo;
175 errno_t rc;
176
177 if (quit)
178 return EOK;
179
180 /* XXX Crude way of detecting text mode */
181 if (demo_is_text()) {
182 /* Create dummy font for text mode */
183 rc = gfx_typeface_create(gc, &tface);
184 if (rc != EOK) {
185 printf("Error creating typeface\n");
186 goto error;
187 }
188
189 rc = gfx_font_create_textmode(tface, &font);
190 if (rc != EOK) {
191 printf("Error creating font\n");
192 goto error;
193 }
194
195 vpad = 0;
196 } else {
197 /* Load font */
198 rc = gfx_typeface_open(gc, "/data/font/helena.tpf", &tface);
199 if (rc != EOK) {
200 printf("Error opening typeface\n");
201 goto error;
202 }
203
204 finfo = gfx_typeface_first_font(tface);
205 if (finfo == NULL) {
206 printf("Typeface contains no font.\n");
207 rc = ENOENT;
208 goto error;
209 }
210
211 rc = gfx_font_open(finfo, &font);
212 if (rc != EOK) {
213 printf("Error opening font.\n");
214 goto error;
215 }
216
217 vpad = 5;
218 }
219
220 return EOK;
221error:
222 if (tface != NULL)
223 gfx_typeface_destroy(tface);
224 return rc;
225}
226
227/** Finalize demo font. */
228static void demo_font_fini(void)
229{
230 if (font == NULL)
231 return;
232
233 gfx_font_close(font);
234 font = NULL;
235
236 gfx_typeface_destroy(tface);
237 tface = NULL;
238}
239
240/** Start a new demo screen.
241 *
242 * Clear the screen, display a status line and set up clipping.
243 *
244 * @param gc Graphic context
245 * @param w Width
246 * @param h Height
247 * @param text Demo screen description
248 * @return EOK on success or an error code
249 */
250static errno_t demo_begin(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h,
251 const char *text)
252{
253 gfx_text_fmt_t fmt;
254 gfx_font_metrics_t metrics;
255 gfx_coord2_t pos;
256 gfx_color_t *color;
257 gfx_rect_t rect;
258 gfx_coord_t height;
259 errno_t rc;
260
261 rc = gfx_set_clip_rect(gc, NULL);
262 if (rc != EOK)
263 return rc;
264
265 rc = clear_scr(gc, w, h);
266 if (rc != EOK)
267 return rc;
268
269 if (font != NULL) {
270 if (demo_is_text()) {
271 rc = gfx_color_new_ega(0x1e, &color);
272 if (rc != EOK)
273 goto error;
274 } else {
275 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &color);
276 if (rc != EOK)
277 goto error;
278 }
279
280 gfx_text_fmt_init(&fmt);
281 fmt.font = font;
282 fmt.color = color;
283 fmt.halign = gfx_halign_center;
284 fmt.valign = gfx_valign_bottom;
285
286 pos.x = w / 2;
287 pos.y = h;
288 rc = gfx_puttext(&pos, &fmt, text);
289 if (rc != EOK) {
290 printf("Error rendering text.\n");
291 gfx_color_delete(color);
292 goto error;
293 }
294
295 gfx_color_delete(color);
296
297 gfx_font_get_metrics(font, &metrics);
298 height = metrics.ascent + metrics.descent + 1;
299 } else {
300 height = 0;
301 }
302
303 rect.p0.x = 0;
304 rect.p0.y = 0;
305 rect.p1.x = w;
306 rect.p1.y = h - height - vpad;
307 rc = gfx_set_clip_rect(gc, &rect);
308 if (rc != EOK)
309 return rc;
310
311 return EOK;
312error:
313 return rc;
314}
315
316/** Run rectangle demo on a graphic context.
317 *
318 * @param gc Graphic context
319 * @param w Width
320 * @param h Height
321 */
322static errno_t demo_rects(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
323{
324 gfx_color_t *color = NULL;
325 gfx_rect_t rect;
326 int i, j;
327 errno_t rc;
328
329 if (quit)
330 return EOK;
331
332 rc = demo_begin(gc, w, h, "Rectangle rendering");
333 if (rc != EOK)
334 return rc;
335
336 for (j = 0; j < 10; j++) {
337 rc = gfx_color_new_rgb_i16(rand() % 0x10000, rand() % 0x10000,
338 rand() % 0x10000, &color);
339 if (rc != EOK)
340 return rc;
341
342 rc = gfx_set_color(gc, color);
343 if (rc != EOK)
344 return rc;
345
346 for (i = 0; i < 10; i++) {
347 rect.p0.x = rand() % (w - 1);
348 rect.p0.y = rand() % (h - 1);
349 rect.p1.x = rect.p0.x + rand() % (w - 1 - rect.p0.x);
350 rect.p1.y = rect.p0.y + rand() % (h - 1 - rect.p0.y);
351
352 rc = gfx_fill_rect(gc, &rect);
353 if (rc != EOK)
354 return rc;
355 }
356
357 gfx_color_delete(color);
358
359 demo_msleep(500);
360 if (quit)
361 break;
362 }
363
364 return EOK;
365}
366
367/** Fill bitmap with tartan pattern.
368 *
369 * @param bitmap Bitmap
370 * @param w Bitmap width
371 * @param h Bitmap height
372 * @return EOK on success or an error code
373 */
374static errno_t bitmap_tartan(gfx_bitmap_t *bitmap, gfx_coord_t w, gfx_coord_t h)
375{
376 int i, j;
377 pixelmap_t pixelmap;
378 gfx_bitmap_alloc_t alloc;
379 errno_t rc;
380
381 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
382 if (rc != EOK)
383 return rc;
384
385 /* In absence of anything else, use pixelmap */
386 pixelmap.width = w;
387 pixelmap.height = h;
388 pixelmap.data = alloc.pixels;
389
390 for (i = 0; i < w; i++) {
391 for (j = 0; j < h; j++) {
392 pixelmap_put_pixel(&pixelmap, i, j,
393 PIXEL(255, (i % 30) < 3 ? 255 : 0,
394 (j % 30) < 3 ? 255 : 0, i / 2));
395 }
396 }
397
398 return EOK;
399}
400
401/** Fill bitmap with moire pattern.
402 *
403 * @param bitmap Bitmap
404 * @param w Bitmap width
405 * @param h Bitmap height
406 * @return EOK on success or an error code
407 */
408static errno_t bitmap_moire(gfx_bitmap_t *bitmap, gfx_coord_t w, gfx_coord_t h)
409{
410 int i, j;
411 int k;
412 pixelmap_t pixelmap;
413 gfx_bitmap_alloc_t alloc;
414 errno_t rc;
415
416 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
417 if (rc != EOK)
418 return rc;
419
420 /* In absence of anything else, use pixelmap */
421 pixelmap.width = w;
422 pixelmap.height = h;
423 pixelmap.data = alloc.pixels;
424
425 for (i = 0; i < w; i++) {
426 for (j = 0; j < h; j++) {
427 k = i * i + j * j;
428 pixelmap_put_pixel(&pixelmap, i, j,
429 PIXEL(255, k, k, k));
430 }
431 }
432
433 return EOK;
434}
435
436/** Render circle to a bitmap.
437 *
438 * @param bitmap Bitmap
439 * @param w Bitmap width
440 * @param h Bitmap height
441 * @return EOK on success or an error code
442 */
443static errno_t bitmap_circle(gfx_bitmap_t *bitmap, gfx_coord_t w, gfx_coord_t h)
444{
445 int i, j;
446 int k;
447 pixelmap_t pixelmap;
448 gfx_bitmap_alloc_t alloc;
449 errno_t rc;
450
451 rc = gfx_bitmap_get_alloc(bitmap, &alloc);
452 if (rc != EOK)
453 return rc;
454
455 /* In absence of anything else, use pixelmap */
456 pixelmap.width = w;
457 pixelmap.height = h;
458 pixelmap.data = alloc.pixels;
459
460 for (i = 0; i < w; i++) {
461 for (j = 0; j < h; j++) {
462 k = i * i + j * j;
463 pixelmap_put_pixel(&pixelmap, i, j,
464 k < w * w / 2 ? PIXEL(255, 0, 255, 0) :
465 PIXEL(255, 255, 0, 255));
466 }
467 }
468
469 return EOK;
470}
471
472/** Run bitmap demo on a graphic context.
473 *
474 * @param gc Graphic context
475 * @param w Width
476 * @param h Height
477 */
478static errno_t demo_bitmap(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
479{
480 gfx_bitmap_t *bitmap;
481 gfx_bitmap_params_t params;
482 int i, j;
483 gfx_coord2_t offs;
484 gfx_rect_t srect;
485 errno_t rc;
486
487 if (quit)
488 return EOK;
489
490 rc = demo_begin(gc, w, h, "Bitmap rendering without offset");
491 if (rc != EOK)
492 return rc;
493
494 gfx_bitmap_params_init(&params);
495 params.rect.p0.x = 0;
496 params.rect.p0.y = 0;
497 params.rect.p1.x = w;
498 params.rect.p1.y = h;
499
500 rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
501 if (rc != EOK)
502 return rc;
503
504 rc = bitmap_tartan(bitmap, w, h);
505 if (rc != EOK)
506 goto error;
507
508 for (j = 0; j < 10; j++) {
509 for (i = 0; i < 5; i++) {
510 srect.p0.x = rand() % (w - 40);
511 srect.p0.y = rand() % (h - 20);
512 srect.p1.x = srect.p0.x + rand() % (w - srect.p0.x);
513 srect.p1.y = srect.p0.y + rand() % (h - srect.p0.y);
514 offs.x = 0;
515 offs.y = 0;
516
517 rc = gfx_bitmap_render(bitmap, &srect, &offs);
518 if (rc != EOK)
519 goto error;
520
521 demo_msleep(250);
522 if (quit)
523 goto out;
524 }
525 }
526
527out:
528 gfx_bitmap_destroy(bitmap);
529
530 return EOK;
531error:
532 gfx_bitmap_destroy(bitmap);
533 return rc;
534}
535
536/** Run second bitmap demo on a graphic context.
537 *
538 * @param gc Graphic context
539 * @param w Width
540 * @param h Height
541 */
542static errno_t demo_bitmap2(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
543{
544 gfx_bitmap_t *bitmap;
545 gfx_bitmap_params_t params;
546 int i, j;
547 gfx_coord2_t offs;
548 errno_t rc;
549
550 if (quit)
551 return EOK;
552
553 rc = demo_begin(gc, w, h, "Bitmap rendering with offset");
554 if (rc != EOK)
555 return rc;
556
557 gfx_bitmap_params_init(&params);
558 params.rect.p0.x = 0;
559 params.rect.p0.y = 0;
560 params.rect.p1.x = 40;
561 params.rect.p1.y = 20;
562
563 rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
564 if (rc != EOK)
565 return rc;
566
567 rc = bitmap_moire(bitmap, 40, 20);
568 if (rc != EOK)
569 goto error;
570
571 for (j = 0; j < 10; j++) {
572 for (i = 0; i < 10; i++) {
573 offs.x = rand() % (w - 40);
574 offs.y = rand() % (h - 20);
575
576 rc = gfx_bitmap_render(bitmap, NULL, &offs);
577 if (rc != EOK)
578 goto error;
579 }
580
581 demo_msleep(500);
582 if (quit)
583 break;
584 }
585
586 gfx_bitmap_destroy(bitmap);
587
588 return EOK;
589error:
590 gfx_bitmap_destroy(bitmap);
591 return rc;
592}
593
594/** Run bitmap color key demo on a graphic context.
595 *
596 * @param gc Graphic context
597 * @param w Width
598 * @param h Height
599 */
600static errno_t demo_bitmap_kc(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
601{
602 gfx_bitmap_t *bitmap;
603 gfx_bitmap_params_t params;
604 int i, j;
605 gfx_coord2_t offs;
606 errno_t rc;
607
608 if (quit)
609 return EOK;
610
611 rc = demo_begin(gc, w, h, "Bitmap rendering with color key");
612 if (rc != EOK)
613 return rc;
614
615 gfx_bitmap_params_init(&params);
616 params.rect.p0.x = 0;
617 params.rect.p0.y = 0;
618 params.rect.p1.x = 40;
619 params.rect.p1.y = 40;
620 params.flags = bmpf_color_key;
621 params.key_color = PIXEL(255, 255, 0, 255);
622
623 rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
624 if (rc != EOK)
625 return rc;
626
627 rc = bitmap_circle(bitmap, 40, 40);
628 if (rc != EOK)
629 goto error;
630
631 for (j = 0; j < 10; j++) {
632 for (i = 0; i < 10; i++) {
633 offs.x = j * 20 + i * 20;
634 offs.y = i * 20;
635
636 rc = gfx_bitmap_render(bitmap, NULL, &offs);
637 if (rc != EOK)
638 goto error;
639 }
640
641 demo_msleep(500);
642 if (quit)
643 break;
644 }
645
646 gfx_bitmap_destroy(bitmap);
647
648 return EOK;
649error:
650 gfx_bitmap_destroy(bitmap);
651 return rc;
652}
653
654/** Run text demo on a graphic context.
655 *
656 * @param gc Graphic context
657 * @param w Width
658 * @param h Height
659 */
660static errno_t demo_text(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
661{
662 gfx_color_t *color = NULL;
663 gfx_rect_t rect;
664 gfx_coord2_t pos;
665 gfx_text_fmt_t fmt;
666 int i;
667 errno_t rc;
668
669 if (quit)
670 return EOK;
671
672 rc = demo_begin(gc, w, h, "Text rendering");
673 if (rc != EOK)
674 goto error;
675
676 /* Vertical bars */
677
678 for (i = 0; i < 20; i++) {
679 rc = gfx_color_new_rgb_i16(0, 0x8000 * i / 20,
680 0x8000 * i / 20, &color);
681 if (rc != EOK)
682 goto error;
683
684 rc = gfx_set_color(gc, color);
685 if (rc != EOK)
686 goto error;
687
688 rect.p0.x = w * i / 20;
689 rect.p0.y = 0;
690 rect.p1.x = w * (i + 1) / 20;
691 rect.p1.y = h;
692
693 rc = gfx_fill_rect(gc, &rect);
694 if (rc != EOK)
695 goto error;
696
697 gfx_color_delete(color);
698 }
699
700 rc = gfx_color_new_rgb_i16(0, 0, 0x8000, &color);
701 if (rc != EOK)
702 goto error;
703
704 rc = gfx_set_color(gc, color);
705 if (rc != EOK)
706 goto error;
707
708 rect.p0.x = w / 20;
709 rect.p0.y = 1 * h / 15;
710 rect.p1.x = w - w / 20;
711 rect.p1.y = 4 * h / 15;
712
713 rc = gfx_fill_rect(gc, &rect);
714 if (rc != EOK)
715 goto error;
716
717 gfx_color_delete(color);
718
719 if (demo_is_text()) {
720 rc = gfx_color_new_ega(0x1f, &color);
721 if (rc != EOK)
722 goto error;
723 } else {
724 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff, &color);
725 if (rc != EOK)
726 goto error;
727 }
728
729 gfx_text_fmt_init(&fmt);
730 fmt.font = font;
731 fmt.color = color;
732
733 pos.x = rect.p0.x;
734 pos.y = rect.p0.y;
735 rc = gfx_puttext(&pos, &fmt, "Top left");
736 if (rc != EOK) {
737 printf("Error rendering text.\n");
738 goto error;
739 }
740
741 pos.x = (rect.p0.x + rect.p1.x - 1) / 2;
742 pos.y = rect.p0.y;
743 fmt.halign = gfx_halign_center;
744 rc = gfx_puttext(&pos, &fmt, "Top center");
745 if (rc != EOK)
746 goto error;
747
748 pos.x = rect.p1.x;
749 pos.y = rect.p0.y;
750 fmt.halign = gfx_halign_right;
751 rc = gfx_puttext(&pos, &fmt, "Top right");
752 if (rc != EOK)
753 goto error;
754
755 fmt.valign = gfx_valign_center;
756
757 pos.x = rect.p0.x;
758 pos.y = (rect.p0.y + rect.p1.y - 1) / 2;
759 fmt.halign = gfx_halign_left;
760 rc = gfx_puttext(&pos, &fmt, "Center left");
761 if (rc != EOK)
762 goto error;
763
764 pos.x = (rect.p0.x + rect.p1.x - 1) / 2;
765 pos.y = (rect.p0.y + rect.p1.y - 1) / 2;
766 fmt.halign = gfx_halign_center;
767 rc = gfx_puttext(&pos, &fmt, "Center");
768 if (rc != EOK)
769 goto error;
770
771 pos.x = rect.p1.x;
772 pos.y = (rect.p0.y + rect.p1.y - 1) / 2;
773 fmt.halign = gfx_halign_right;
774 rc = gfx_puttext(&pos, &fmt, "Center right");
775 if (rc != EOK)
776 goto error;
777
778 fmt.valign = gfx_valign_bottom;
779
780 pos.x = rect.p0.x;
781 pos.y = rect.p1.y - 1;
782 fmt.halign = gfx_halign_left;
783 rc = gfx_puttext(&pos, &fmt, "Bottom left");
784 if (rc != EOK)
785 goto error;
786
787 pos.x = (rect.p0.x + rect.p1.x - 1) / 2;
788 pos.y = rect.p1.y;
789 fmt.halign = gfx_halign_center;
790 rc = gfx_puttext(&pos, &fmt, "Bottom center");
791 if (rc != EOK)
792 goto error;
793
794 pos.x = rect.p1.x;
795 pos.y = rect.p1.y;
796 fmt.halign = gfx_halign_right;
797 rc = gfx_puttext(&pos, &fmt, "Bottom right");
798 if (rc != EOK)
799 goto error;
800
801 gfx_color_delete(color);
802
803 gfx_text_fmt_init(&fmt);
804 fmt.font = font;
805
806 for (i = 0; i < 8; i++) {
807 if (demo_is_text()) {
808 rc = gfx_color_new_ega(i != 0 ? i : 0x10, &color);
809 if (rc != EOK)
810 goto error;
811 } else {
812 rc = gfx_color_new_rgb_i16((i & 4) ? 0xffff : 0,
813 (i & 2) ? 0xffff : 0, (i & 1) ? 0xffff : 0, &color);
814 if (rc != EOK)
815 goto error;
816 }
817
818 fmt.color = color;
819 fmt.underline = !fmt.underline;
820
821 pos.x = w / 20;
822 pos.y = (6 + i) * h / 15;
823 rc = gfx_puttext(&pos, &fmt, "The quick brown fox jumps over the lazy dog.");
824 if (rc != EOK)
825 goto error;
826
827 gfx_color_delete(color);
828 }
829
830 for (i = 0; i < 10; i++) {
831 demo_msleep(500);
832 if (quit)
833 break;
834 }
835
836 return EOK;
837error:
838 return rc;
839}
840
841/** Run text abbreviation demo on a graphic context.
842 *
843 * @param gc Graphic context
844 * @param w Width
845 * @param h Height
846 */
847static errno_t demo_text_abbr(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
848{
849 gfx_color_t *color = NULL;
850 gfx_rect_t rect;
851 gfx_coord2_t pos;
852 gfx_text_fmt_t fmt;
853 int i;
854 errno_t rc;
855
856 if (quit)
857 return EOK;
858
859 rc = demo_begin(gc, w, h, "Text abbreviation");
860 if (rc != EOK)
861 goto error;
862
863 for (i = 0; i < 11; i++) {
864
865 rc = gfx_color_new_rgb_i16(0, 0, 0x8000, &color);
866 if (rc != EOK)
867 goto error;
868
869 rc = gfx_set_color(gc, color);
870 if (rc != EOK)
871 goto error;
872
873 rect.p0.x = w / 20;
874 rect.p0.y = (2 + 2 * i) * h / 25;
875 rect.p1.x = w - w / 20 - w * i / 12;
876 rect.p1.y = (3 + 2 * i) * h / 25;
877
878 rc = gfx_fill_rect(gc, &rect);
879 if (rc != EOK)
880 goto error;
881
882 gfx_color_delete(color);
883
884 if (demo_is_text()) {
885 rc = gfx_color_new_ega(0x1f, &color);
886 if (rc != EOK)
887 goto error;
888 } else {
889 rc = gfx_color_new_rgb_i16(0xffff, 0xffff, 0xffff,
890 &color);
891 if (rc != EOK)
892 goto error;
893 }
894
895 gfx_text_fmt_init(&fmt);
896 fmt.font = font;
897 fmt.color = color;
898 fmt.abbreviate = true;
899 fmt.width = rect.p1.x - rect.p0.x;
900
901 pos.x = rect.p0.x;
902 pos.y = rect.p0.y;
903 rc = gfx_puttext(&pos, &fmt,
904 "The quick brow fox jumps over the lazy dog!");
905 if (rc != EOK) {
906 printf("Error rendering text.\n");
907 goto error;
908 }
909 }
910
911 for (i = 0; i < 10; i++) {
912 demo_msleep(500);
913 if (quit)
914 break;
915 }
916
917 return EOK;
918error:
919 return rc;
920}
921
922/** Run clipping demo on a graphic context.
923 *
924 * @param gc Graphic context
925 * @param w Width
926 * @param h Height
927 */
928static errno_t demo_clip(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
929{
930 gfx_bitmap_t *bitmap;
931 gfx_color_t *color;
932 gfx_bitmap_params_t params;
933 int i, j;
934 gfx_coord2_t offs;
935 gfx_rect_t rect;
936 errno_t rc;
937
938 if (quit)
939 return EOK;
940
941 rc = demo_begin(gc, w, h, "Clipping demonstration");
942 if (rc != EOK)
943 return rc;
944
945 gfx_bitmap_params_init(&params);
946 params.rect.p0.x = 0;
947 params.rect.p0.y = 0;
948 params.rect.p1.x = 40;
949 params.rect.p1.y = 20;
950
951 rc = gfx_bitmap_create(gc, &params, NULL, &bitmap);
952 if (rc != EOK)
953 return rc;
954
955 rc = bitmap_moire(bitmap, 40, 20);
956 if (rc != EOK)
957 goto error;
958
959 for (j = 0; j < 10; j++) {
960 rect.p0.x = w / 8;
961 rect.p0.y = h / 8;
962 rect.p1.x = w * 7 / 8;
963 rect.p1.y = h * 3 / 8;
964
965 rc = gfx_set_clip_rect(gc, &rect);
966 if (rc != EOK)
967 return rc;
968
969 rc = gfx_color_new_rgb_i16(rand() % 0x10000, rand() % 0x10000,
970 rand() % 0x10000, &color);
971 if (rc != EOK)
972 return rc;
973
974 rc = gfx_set_color(gc, color);
975 if (rc != EOK)
976 return rc;
977
978 for (i = 0; i < 10; i++) {
979 rect.p0.x = rand() % (w - 1);
980 rect.p0.y = rand() % (h - 1);
981 rect.p1.x = rect.p0.x + rand() % (w - 1 - rect.p0.x);
982 rect.p1.y = rect.p0.y + rand() % (h - 1 - rect.p0.y);
983
984 rc = gfx_fill_rect(gc, &rect);
985 if (rc != EOK)
986 return rc;
987 }
988
989 gfx_color_delete(color);
990
991 rect.p0.x = w / 8;
992 rect.p0.y = h * 5 / 8;
993 rect.p1.x = w * 7 / 8;
994 rect.p1.y = h * 7 / 8;
995
996 rc = gfx_set_clip_rect(gc, &rect);
997 if (rc != EOK)
998 return rc;
999
1000 for (i = 0; i < 10; i++) {
1001 offs.x = rand() % (w - 40);
1002 offs.y = rand() % (h - 20);
1003
1004 rc = gfx_bitmap_render(bitmap, NULL, &offs);
1005 if (rc != EOK)
1006 goto error;
1007 }
1008
1009 demo_msleep(500);
1010 if (quit)
1011 break;
1012 }
1013
1014 (void) gfx_set_clip_rect(gc, NULL);
1015 gfx_bitmap_destroy(bitmap);
1016 return EOK;
1017error:
1018 (void) gfx_set_clip_rect(gc, NULL);
1019 gfx_bitmap_destroy(bitmap);
1020 return rc;
1021}
1022
1023/** Run demo loop on a graphic context.
1024 *
1025 * @param gc Graphic context
1026 * @param w Width
1027 * @param h Height
1028 */
1029static errno_t demo_loop(gfx_context_t *gc, gfx_coord_t w, gfx_coord_t h)
1030{
1031 errno_t rc;
1032
1033 (void) demo_font_init(gc, w, h);
1034
1035 while (!quit) {
1036 rc = demo_rects(gc, w, h);
1037 if (rc != EOK)
1038 goto error;
1039
1040 rc = demo_bitmap(gc, w, h);
1041 if (rc != EOK)
1042 goto error;
1043
1044 rc = demo_bitmap2(gc, w, h);
1045 if (rc != EOK)
1046 goto error;
1047
1048 rc = demo_bitmap_kc(gc, w, h);
1049 if (rc != EOK)
1050 goto error;
1051
1052 rc = demo_text(gc, w, h);
1053 if (rc != EOK)
1054 goto error;
1055
1056 rc = demo_text_abbr(gc, w, h);
1057 if (rc != EOK)
1058 goto error;
1059
1060 rc = demo_clip(gc, w, h);
1061 if (rc != EOK)
1062 goto error;
1063 }
1064
1065 demo_font_fini();
1066 return EOK;
1067error:
1068 demo_font_fini();
1069 return rc;
1070}
1071
1072/** Run demo on console. */
1073static errno_t demo_console(void)
1074{
1075 console_gc_t *cgc = NULL;
1076 gfx_context_t *gc;
1077 sysarg_t cols, rows;
1078 errno_t rc;
1079
1080 con = console_init(stdin, stdout);
1081 if (con == NULL)
1082 return EIO;
1083
1084 rc = console_get_size(con, &cols, &rows);
1085 if (rc != EOK)
1086 return rc;
1087
1088 rc = console_gc_create(con, stdout, &cgc);
1089 if (rc != EOK)
1090 return rc;
1091
1092 gc = console_gc_get_ctx(cgc);
1093
1094 /* Currently console is always text. */
1095 textmode = true;
1096
1097 rc = demo_loop(gc, cols, rows);
1098 if (rc != EOK)
1099 return rc;
1100
1101 rc = console_gc_delete(cgc);
1102 if (rc != EOK)
1103 return rc;
1104
1105 return EOK;
1106}
1107
1108static errno_t demo_ui_fibril(void *arg)
1109{
1110 demo_ui_args_t *args = (demo_ui_args_t *)arg;
1111 errno_t rc;
1112
1113 ui_lock(args->ui);
1114 rc = demo_loop(args->gc, args->dims.x, args->dims.y);
1115 ui_unlock(args->ui);
1116 ui_quit(args->ui);
1117 return rc;
1118}
1119
1120/** Run demo on UI. */
1121static errno_t demo_ui(const char *display_spec)
1122{
1123 ui_wnd_params_t params;
1124 ui_window_t *window = NULL;
1125 gfx_context_t *gc;
1126 gfx_rect_t rect;
1127 gfx_rect_t wrect;
1128 gfx_coord2_t off;
1129 gfx_rect_t ui_rect;
1130 gfx_coord2_t dims;
1131 demo_ui_args_t args;
1132 fid_t fid;
1133 errno_t rc;
1134
1135 rc = ui_create(display_spec, &ui);
1136 if (rc != EOK) {
1137 printf("Error initializing UI (%s)\n", display_spec);
1138 goto error;
1139 }
1140
1141 rc = ui_get_rect(ui, &ui_rect);
1142 if (rc != EOK) {
1143 printf("Error getting display size.\n");
1144 goto error;
1145 }
1146
1147 rect.p0.x = 0;
1148 rect.p0.y = 0;
1149 rect.p1.x = 400;
1150 rect.p1.y = 300;
1151
1152 ui_wnd_params_init(&params);
1153 params.caption = "GFX Demo";
1154
1155 /* Do not decorate the window in fullscreen mode */
1156 if (ui_is_fullscreen(ui))
1157 params.style &= ~ui_wds_decorated;
1158
1159 /*
1160 * Compute window rectangle such that application area corresponds
1161 * to rect
1162 */
1163 ui_wdecor_rect_from_app(ui, params.style, &rect, &wrect);
1164 off = wrect.p0;
1165 gfx_rect_rtranslate(&off, &wrect, &params.rect);
1166
1167 gfx_rect_dims(&ui_rect, &dims);
1168
1169 /* Make sure window is not larger than the entire screen */
1170 if (params.rect.p1.x > dims.x)
1171 params.rect.p1.x = dims.x;
1172 if (params.rect.p1.y > dims.y)
1173 params.rect.p1.y = dims.y;
1174
1175 rc = ui_window_create(ui, &params, &window);
1176 if (rc != EOK) {
1177 printf("Error creating window.\n");
1178 goto error;
1179 }
1180
1181 ui_window_set_cb(window, &ui_window_cb, NULL);
1182
1183 rc = ui_window_get_app_gc(window, &gc);
1184 if (rc != EOK) {
1185 printf("Error creating graphic context.\n");
1186 goto error;
1187 }
1188
1189 ui_window_get_app_rect(window, &rect);
1190 gfx_rect_dims(&rect, &dims);
1191
1192 if (!ui_is_fullscreen(ui))
1193 task_retval(0);
1194
1195 textmode = ui_is_textmode(ui);
1196
1197 args.gc = gc;
1198 args.dims = dims;
1199 args.ui = ui;
1200
1201 fid = fibril_create(demo_ui_fibril, (void *)&args);
1202 if (fid == 0) {
1203 rc = ENOMEM;
1204 goto error;
1205 }
1206
1207 fibril_add_ready(fid);
1208
1209 ui_run(ui);
1210 ui_window_destroy(window);
1211 ui_destroy(ui);
1212
1213 return EOK;
1214error:
1215 if (window != NULL)
1216 ui_window_destroy(window);
1217 if (ui != NULL)
1218 ui_destroy(ui);
1219 return rc;
1220}
1221
1222/** Run demo on display server. */
1223static errno_t demo_display(const char *display_svc)
1224{
1225 display_t *display = NULL;
1226 gfx_context_t *gc;
1227 display_wnd_params_t params;
1228 display_window_t *window = NULL;
1229 errno_t rc;
1230
1231 rc = display_open(display_svc, &display);
1232 if (rc != EOK) {
1233 printf("Error opening display.\n");
1234 return rc;
1235 }
1236
1237 display_wnd_params_init(&params);
1238 params.rect.p0.x = 0;
1239 params.rect.p0.y = 0;
1240 params.rect.p1.x = 400;
1241 params.rect.p1.y = 300;
1242 params.caption = "GFX Demo";
1243
1244 rc = display_window_create(display, &params, &wnd_cb, NULL, &window);
1245 if (rc != EOK) {
1246 printf("Error creating window.\n");
1247 return rc;
1248 }
1249
1250 rc = display_window_get_gc(window, &gc);
1251 if (rc != EOK) {
1252 printf("Error getting graphics context.\n");
1253 return rc;
1254 }
1255
1256 task_retval(0);
1257
1258 /* FIXME Assuming display service is not text mode. */
1259 textmode = false;
1260
1261 rc = demo_loop(gc, 400, 300);
1262 if (rc != EOK)
1263 return rc;
1264
1265 rc = gfx_context_delete(gc);
1266 if (rc != EOK)
1267 return rc;
1268
1269 display_window_destroy(window);
1270 display_close(display);
1271
1272 return EOK;
1273}
1274
1275static void demo_quit(void)
1276{
1277 fibril_mutex_lock(&quit_lock);
1278 quit = true;
1279 fibril_mutex_unlock(&quit_lock);
1280 fibril_condvar_broadcast(&quit_cv);
1281}
1282
1283static void wnd_close_event(void *arg)
1284{
1285 demo_quit();
1286}
1287
1288static void demo_kbd_event(kbd_event_t *event)
1289{
1290 if (event->type == KEY_PRESS) {
1291 /* Ctrl-Q */
1292 if ((event->mods & KM_CTRL) != 0 &&
1293 (event->mods & KM_ALT) == 0 &&
1294 (event->mods & KM_SHIFT) == 0 &&
1295 event->key == KC_Q) {
1296 demo_quit();
1297 }
1298
1299 /* Escape */
1300 if ((event->mods & KM_CTRL) == 0 &&
1301 (event->mods & KM_ALT) == 0 &&
1302 (event->mods & KM_SHIFT) == 0 &&
1303 event->key == KC_ESCAPE) {
1304 demo_quit();
1305 }
1306 }
1307}
1308
1309static void wnd_kbd_event(void *arg, kbd_event_t *event)
1310{
1311 (void)arg;
1312 demo_kbd_event(event);
1313}
1314
1315static void uiwnd_close_event(ui_window_t *window, void *arg)
1316{
1317 demo_quit();
1318}
1319
1320static void uiwnd_kbd_event(ui_window_t *window, void *arg, kbd_event_t *event)
1321{
1322 (void)window;
1323 (void)arg;
1324 demo_kbd_event(event);
1325}
1326
1327static void print_syntax(void)
1328{
1329 printf("Syntax: gfxdemo [-d <display>] {console|display|ui}\n");
1330}
1331
1332int main(int argc, char *argv[])
1333{
1334 errno_t rc;
1335 const char *display_svc = DISPLAY_DEFAULT;
1336 const char *ui_display_spec = UI_ANY_DEFAULT;
1337 int i;
1338
1339 i = 1;
1340 while (i < argc && argv[i][0] == '-') {
1341 if (str_cmp(argv[i], "-d") == 0) {
1342 ++i;
1343 if (i >= argc) {
1344 printf("Argument missing.\n");
1345 print_syntax();
1346 return 1;
1347 }
1348
1349 display_svc = ui_display_spec = argv[i++];
1350 } else {
1351 printf("Invalid option '%s'.\n", argv[i]);
1352 print_syntax();
1353 return 1;
1354 }
1355 }
1356
1357 if (i >= argc || str_cmp(argv[i], "ui") == 0) {
1358 rc = demo_ui(ui_display_spec);
1359 if (rc != EOK)
1360 return 1;
1361 } else if (str_cmp(argv[i], "console") == 0) {
1362 rc = demo_console();
1363 if (rc != EOK)
1364 return 1;
1365 } else if (str_cmp(argv[i], "display") == 0) {
1366 rc = demo_display(display_svc);
1367 if (rc != EOK)
1368 return 1;
1369 } else {
1370 print_syntax();
1371 return 1;
1372 }
1373}
1374
1375/** @}
1376 */
Note: See TracBrowser for help on using the repository browser.