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

Last change on this file since 10657856 was 9e240c1, checked in by Jiri Svoboda <jiri@…>, 22 months ago

GFX Demo 'ui' should fall back to console by default

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