demos: Fix and cleanup GP_BackendInit() + docs.
[gfxprim/pasky.git] / demos / c_simple / shapetest.c
blobdb329388f644cab31ace93afde92926540a47ae3
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2010 Jiri "BlueBear" Dluhos *
20 * <jiri.bluebear.dluhos@gmail.com> *
21 * *
22 * Copyright (C) 2009-2013 Cyril Hrubis <metan@ucw.cz> *
23 * *
24 *****************************************************************************/
26 #include <stdio.h>
27 #include <stdlib.h>
29 #include <GP.h>
31 static GP_Context *win;
32 static GP_Backend *backend;
34 /* Basic colors in display-specific format. */
35 static GP_Pixel black, white, yellow, green, red, gray, darkgray;
37 /* Radius of the shape being drawn */
38 static int xradius = 5;
39 static int yradius = 5;
41 /* Draw outline? 0=none, 1=before filling, 2=after filling */
42 static int outline = 0;
44 /* Fill the shape? */
45 static int fill = 1;
47 /* Show axes? */
48 static int show_axes = 1;
50 /* Shape to be drawn */
51 #define SHAPE_FIRST 1
52 #define SHAPE_TRIANGLE 1
53 #define SHAPE_CIRCLE 2
54 #define SHAPE_RING 3
55 #define SHAPE_ELLIPSE 4
56 #define SHAPE_RECTANGLE 5
57 #define SHAPE_TETRAGON 6
58 #define SHAPE_POLYGON 7
59 #define SHAPE_ARC 8
60 #define SHAPE_LAST 8
61 static int shape = SHAPE_FIRST;
63 /* Variants in coordinates, if applicable */
64 static int variant = 1;
66 /* center of drawing */
67 static int center_x;
68 static int center_y;
70 void draw_testing_triangle(int x, int y, int xradius, int yradius)
72 int x0, y0, x1, y1, x2, y2;
73 switch (variant) {
74 case 1:
75 x0 = x;
76 y0 = y - yradius;
77 x1 = x - xradius;
78 y1 = y;
79 x2 = x + xradius;
80 y2 = y + yradius;
81 break;
82 case 2:
83 x0 = x - xradius;
84 y0 = y - yradius;
85 x1 = x + xradius;
86 y1 = y;
87 x2 = x + xradius;
88 y2 = y + yradius;
89 break;
90 case 3:
91 x0 = x - xradius;
92 y0 = y - yradius;
93 x1 = x + xradius;
94 y1 = y + yradius;
95 x2 = x - xradius + xradius/8;
96 y2 = y;
97 break;
98 case 4:
99 default:
100 x0 = x;
101 y0 = y - yradius;
102 x1 = x + xradius;
103 y1 = y + yradius;
104 x2 = x - xradius;
105 y2 = y + yradius;
106 break;
109 /* draw the three vertices green; they should never be visible
110 * because the red triangle should cover them; if they are visible,
111 * it means we don't draw to the end */
112 GP_PutPixel(win, x0, y0, green);
113 GP_PutPixel(win, x1, y1, green);
114 GP_PutPixel(win, x2, y2, green);
116 if (outline == 1)
117 GP_Triangle(win, x0, y0, x1, y1, x2, y2, yellow);
119 if (fill)
120 GP_FillTriangle(win, x0, y0, x1, y1, x2, y2, red);
122 if (outline == 2)
123 GP_Triangle(win, x0, y0, x1, y1, x2, y2, white);
126 void draw_testing_circle(int x, int y, int xradius,
127 __attribute__((unused)) int yradius)
129 if (outline == 1)
130 GP_Circle(win, x, y, xradius, yellow);
132 if (fill)
133 GP_FillCircle(win, x, y, xradius, red);
135 if (outline == 2)
136 GP_Circle(win, x, y, xradius, white);
139 void draw_testing_ring(int x, int y, int xradius,
140 __attribute__((unused)) int yradius)
142 if (outline == 1)
143 GP_Ring(win, x, y, xradius, yradius, yellow);
145 if (fill)
146 GP_FillRing(win, x, y, xradius, yradius, red);
148 if (outline == 2)
149 GP_Ring(win, x, y, xradius, yradius, white);
152 void draw_testing_ellipse(int x, int y, int xradius, int yradius)
154 if (outline == 1)
155 GP_Ellipse(win, x, y, xradius, yradius, yellow);
157 if (fill)
158 GP_FillEllipse(win, x, y, xradius, yradius, red);
160 if (outline == 2)
161 GP_Ellipse(win, x, y, xradius, yradius, white);
164 void draw_testing_arc(int x, int y, int xradius, int yradius)
166 GP_ArcSegment(win, x, y, xradius, yradius, -1,
167 M_PI - M_PI/8.0, M_PI/4.0, red);
170 void draw_testing_rectangle(int x, int y, int xradius, int yradius)
172 int x0 = x - xradius, y0 = y - yradius;
173 int x1 = x + xradius, y1 = y + yradius;
175 if (outline == 1)
176 GP_Rect(win, x0, y0, x1, y1, yellow);
178 if (fill)
179 GP_FillRect(win, x0, y0, x1, y1, red);
181 if (outline == 2)
182 GP_Rect(win, x0, y0, x1, y1, white);
185 void draw_testing_tetragon(int x, int y, int xradius, int yradius)
187 int x0 = x - xradius, y0 = y - yradius;
188 int x1 = x + xradius, y1 = y;
189 int x2 = x + xradius, y2 = y + yradius/2;
190 int x3 = x, y3 = y + yradius;
192 if (outline == 1)
193 GP_Tetragon(win, x0, y0, x1, y1, x2, y2, x3, y3, yellow);
195 if (fill)
196 GP_FillTetragon(win, x0, y0, x1, y1, x2, y2, x3, y3, red);
198 if (outline == 2)
199 GP_Tetragon(win, x0, y0, x1, y1, x2, y2, x3, y3, white);
202 void draw_testing_polygon(int x, int y, int xradius, int yradius)
204 GP_Coord xy[14];
205 unsigned int edges = 7;
207 xy[0] = x + xradius;
208 xy[1] = y;
210 xy[2] = x + 3 * xradius / 4;
211 xy[3] = y + yradius / 4;
213 xy[4] = x + 3 * xradius / 4;
214 xy[5] = y + 3 * yradius / 4;
216 xy[6] = x + xradius / 4;
217 xy[7] = y + 3 * yradius / 4;
219 xy[8] = x;
220 xy[9] = y;
222 xy[10] = x - xradius;
223 xy[11] = y;
225 xy[12] = x - 3 * xradius / 4;
226 xy[13] = y - yradius / 4;
228 if (outline == 1)
229 GP_Polygon(win, edges, xy, yellow);
231 if (fill)
232 GP_FillPolygon(win, edges, xy, red);
234 if (outline == 2)
235 GP_Polygon(win, edges, xy, white);
238 void redraw_screen(void)
241 /* text style for the label */
242 GP_TextStyle style = {
243 .font = &GP_DefaultConsoleFont,
244 .pixel_xmul = 2,
245 .pixel_ymul = 1,
246 .pixel_xspace = 0,
247 .pixel_yspace = 1,
250 GP_Fill(win, black);
252 /* axes */
253 if (show_axes) {
254 GP_HLine(win, 0, win->w, center_y, gray);
255 GP_HLine(win, 0, win->w, center_y-yradius, darkgray);
256 GP_HLine(win, 0, win->w, center_y+yradius, darkgray);
257 GP_VLine(win, center_x, 0, win->h, gray);
258 GP_VLine(win, center_x-xradius, 0, win->h, darkgray);
259 GP_VLine(win, center_x+xradius, 0, win->h, darkgray);
262 /* the shape */
263 const char *title = NULL;
264 switch (shape) {
265 case SHAPE_TRIANGLE:
266 draw_testing_triangle(center_x, center_y, xradius, yradius);
267 title = "TRIANGLE";
268 break;
269 case SHAPE_CIRCLE:
270 draw_testing_circle(center_x, center_y, xradius, yradius);
271 title = "CIRCLE";
272 break;
273 case SHAPE_RING:
274 draw_testing_ring(center_x, center_y, xradius, yradius);
275 title = "RING";
276 break;
277 case SHAPE_ELLIPSE:
278 draw_testing_ellipse(center_x, center_y, xradius, yradius);
279 title = "ELLIPSE";
280 break;
281 case SHAPE_RECTANGLE:
282 draw_testing_rectangle(center_x, center_y, xradius, yradius);
283 title = "RECTANGLE";
284 break;
285 case SHAPE_TETRAGON:
286 draw_testing_tetragon(center_x, center_y, xradius, yradius);
287 title = "TETRAGON";
288 break;
289 case SHAPE_POLYGON:
290 draw_testing_polygon(center_x, center_y, xradius, yradius);
291 title = "POLYGON";
292 break;
293 case SHAPE_ARC:
294 draw_testing_arc(center_x, center_y, xradius, yradius);
295 title = "ARC";
296 break;
299 GP_Text(win, &style, 16, 16, GP_ALIGN_RIGHT|GP_VALIGN_BELOW,
300 white, black, title);
302 GP_BackendFlip(backend);
305 static void xradius_add(int xradius_add)
307 if (xradius + xradius_add > 1 &&
308 xradius + xradius_add < (int)win->w)
309 xradius += xradius_add;
313 static void yradius_add(int yradius_add)
315 if (yradius + yradius_add > 1 &&
316 yradius + yradius_add < (int)win->h)
317 yradius += yradius_add;
320 static void xcenter_add(int xcenter_add)
322 if (center_x + xcenter_add > 1 &&
323 center_x + xcenter_add < (int)win->w/2)
324 center_x += xcenter_add;
327 static void ycenter_add(int ycenter_add)
329 if (center_y + ycenter_add > 1 &&
330 center_y + ycenter_add < (int)win->h/2)
331 center_y += ycenter_add;
334 void event_loop(void)
336 int shift_pressed;
338 GP_Event ev;
340 for (;;) {
341 GP_BackendWaitEvent(backend, &ev);
343 //GP_EventDump(&ev);
345 shift_pressed = GP_EventGetKey(&ev, GP_KEY_LEFT_SHIFT) ||
346 GP_EventGetKey(&ev, GP_KEY_RIGHT_SHIFT);
348 switch (ev.type) {
349 case GP_EV_KEY:
350 if (ev.code != GP_EV_KEY_DOWN)
351 continue;
353 switch (ev.val.key.key) {
354 case GP_KEY_X:
355 win->x_swap = !win->x_swap;
356 break;
357 case GP_KEY_Y:
358 win->y_swap = !win->y_swap;
359 break;
360 case GP_KEY_R:
361 win->axes_swap = !win->axes_swap;
362 GP_SWAP(win->w, win->h);
363 break;
364 case GP_KEY_F:
365 fill = !fill;
366 if (!fill && !outline)
367 outline = 1;
368 break;
369 case GP_KEY_O:
370 outline++;
371 if (outline == 3)
372 outline = 0;
373 if (!fill && outline == 0)
374 fill = 1;
375 break;
376 case GP_KEY_A:
377 show_axes = !show_axes;
378 break;
379 case GP_KEY_LEFT:
380 if (shift_pressed)
381 xcenter_add(-1);
382 else
383 xradius_add(-1);
384 break;
385 case GP_KEY_RIGHT:
386 if (shift_pressed)
387 xcenter_add(1);
388 else
389 xradius_add(1);
390 break;
391 case GP_KEY_UP:
392 if (shift_pressed)
393 ycenter_add(-1);
394 else
395 yradius_add(1);
396 break;
397 case GP_KEY_DOWN:
398 if (shift_pressed)
399 ycenter_add(1);
400 else
401 yradius_add(-1);
402 break;
403 case GP_KEY_SPACE:
404 shape++;
405 if (shape > SHAPE_LAST)
406 shape = SHAPE_FIRST;
407 break;
408 case GP_KEY_EQUAL:
409 if (xradius > yradius)
410 yradius = xradius;
411 else
412 xradius = yradius;
413 break;
414 case GP_KEY_1:
415 variant = 1;
416 break;
417 case GP_KEY_2:
418 variant = 2;
419 break;
420 case GP_KEY_3:
421 variant = 3;
422 break;
423 case GP_KEY_4:
424 variant = 4;
425 break;
426 case GP_KEY_PAGE_UP:
427 xradius_add(1);
428 yradius_add(1);
429 break;
430 case GP_KEY_PAGE_DOWN:
431 xradius_add(-1);
432 yradius_add(-1);
433 break;
434 case GP_KEY_ESC:
435 GP_BackendExit(backend);
436 exit(0);
437 break;
439 break;
440 case GP_EV_SYS:
441 switch(ev.code) {
442 case GP_EV_SYS_QUIT:
443 GP_BackendExit(backend);
444 exit(0);
445 break;
446 case GP_EV_SYS_RESIZE:
447 GP_BackendResizeAck(backend);
448 center_x = backend->context->w / 2;
449 center_y = backend->context->h / 2;
450 break;
452 break;
455 redraw_screen();
459 void print_instructions(void)
461 printf("Use the following keys to control the test:\n");
462 printf(" Esc ................. exit\n");
463 printf(" Space ............... change shapes\n");
464 printf(" O ................... draw outlines (none/before/after fill)\n");
465 printf(" F ................... toggle filling\n");
466 printf(" A ................... show/hide axes\n");
467 printf(" X ................... mirror X\n");
468 printf(" Y ................... mirror Y\n");
469 printf(" R ................... reverse X and Y\n");
470 printf(" left/right .......... increase/decrease horizontal radius\n");
471 printf(" up/down ............. increase/decrease vertical radius\n");
472 printf(" shift + left/right .. increase/decrease horizontal center\n");
473 printf(" shift + up/down ..... increase/decrease vertical center\n");
474 printf(" PgUp/PgDn ........... increase/decrease both radii\n");
475 printf(" = ................... reset radii to the same value\n");
476 printf(" 1/2/3 ............... choose shape variant (if applicable)\n");
479 int main(int argc, char *argv[])
481 const char *backend_opts = "X11";
482 int opt;
484 while ((opt = getopt(argc, argv, "b:")) != -1) {
485 switch (opt) {
486 case 'b':
487 backend_opts = optarg;
488 break;
489 default:
490 fprintf(stderr, "Invalid paramter '%c'\n", opt);
494 backend = GP_BackendInit(backend_opts, "Shapetest");
496 if (backend == NULL) {
497 fprintf(stderr, "Failed to initalize backend '%s'\n",
498 backend_opts);
499 return 1;
502 win = backend->context;
504 center_x = win->w / 2;
505 center_y = win->h / 2;
507 /* Load colors compatible with the display */
508 black = GP_ColorToContextPixel(GP_COL_BLACK, win);
509 white = GP_ColorToContextPixel(GP_COL_WHITE, win);
510 yellow = GP_ColorToContextPixel(GP_COL_YELLOW, win);
511 green = GP_ColorToContextPixel(GP_COL_GREEN, win);
512 red = GP_ColorToContextPixel(GP_COL_RED, win);
513 gray = GP_ColorToContextPixel(GP_COL_GRAY_LIGHT, win);
514 darkgray = GP_ColorToContextPixel(GP_COL_GRAY_DARK, win);
516 print_instructions();
517 redraw_screen();
518 event_loop();
520 return 0;