1 /* The Ace of Penguins - table.c
2 Copyright (C) 1998, 2001 DJ Delorie
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program 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
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <assert.h>
22
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #include <X11/keysym.h>
26 #include <X11/Xatom.h>
27 #include <X11/xpm.h>
28
29 #include "xwin.h"
30
31 #define CD printf("%d: %d %d %d %d\n", __LINE__, ex, ey, ew, eh)
32 #undef CD
33 #define CD
34
35 #include "imagelib.h"
36 #include "cards.h"
37 #include "xwin.h"
38 #include "funcs.h"
39
40 #define TRACE_EVENTS 0
41 #define TRACE_PICTURES 0
42 #define TRACE_INVALIDATE 0
43
44 #define DBLCLICK_TIME 800
45 #define DBLCLICK_MOVE 5
46
47
48 int table_width=0, table_height=0, table_type;
49 int display_width, display_height;
50
51 extern int stack_fan_down, stack_fan_right, stack_fan_tbdown, stack_fan_tbright;
52
53 static Picture *centered_pic = 0;
54
55 static int ex=0, ey=0, ew=0, eh=0;
56
57 static int graphics_disabled = 1;
58
59 OptionDesc *app_options;
60 extern OptionDesc *xwin_options;
61 static OptionDesc *options[5];
62
63 static OptionDesc ace_options[] = {
64 { "-width", OPTION_INTEGER, &table_width },
65 { "-height", OPTION_INTEGER, &table_height },
66 { 0, 0, 0 }
67 };
68
69 static FunctionMapping flist[] = {
70 { "click", &click_cb },
71 { "drag", &drag_cb },
72 { "redraw", &redraw_cb },
73 { "init", &init_cb },
74 { "drop", &drop_cb },
75 { "key", &key_cb },
76 { "resize", &resize_cb },
77 { "double_click", &double_click_cb },
78 { 0, 0 }
79 };
80
81 extern image_list cards_imagelib[];
82 static image_list card_images[];
83
84 void
init_ace(int argc,char ** argv,FunctionMapping * funcs)85 init_ace(int argc, char **argv, FunctionMapping *funcs)
86 {
87 int i = 0, o, a, errors=0;
88
89 register_imagelib(cards_imagelib);
90 register_imagelib(card_images);
91
92 if (app_options)
93 options[i++] = app_options;
94 if (xwin_options)
95 options[i++] = xwin_options;
96 options[i++] = ace_options;
97 options[i++] = 0;
98
99 for (i=0; funcs[i].name; i++)
100 for (a=0; flist[a].name; a++)
101 if (strcmp(funcs[i].name, flist[a].name) == 0)
102 *(void **)flist[a].function = funcs[i].function;
103
104 for (a=1; a<argc; a++)
105 {
106 int found = 0;
107 if (argv[a][0] != '-')
108 break;
109 for (i=0; options[i]; i++)
110 for (o=0; options[i][o].option; o++)
111 if (strcmp (options[i][o].option, argv[a]) == 0)
112 {
113 found = 1;
114 if (options[i][o].type != OPTION_BOOLEAN && a == argc-1)
115 {
116 fprintf(stderr, "Option `%s' takes an argument\n", argv[a]);
117 errors++;
118 continue;
119 }
120 switch (options[i][o].type)
121 {
122 case OPTION_BOOLEAN:
123 *(int *)(options[i][o].ptr) = 1;
124 break;
125 case OPTION_STRING:
126 *(char **)(options[i][o].ptr) = argv[a+1];
127 a++;
128 break;
129 case OPTION_INTEGER:
130 *(int *)(options[i][o].ptr) = strtol(argv[a+1], 0, 0);
131 a++;
132 break;
133 }
134 }
135 if (!found)
136 {
137 fprintf(stderr, "Unrecognized option `%s'\n", argv[a]);
138 errors++;
139 }
140 }
141 if (errors)
142 exit(errors);
143
144 i = 1;
145 while (a < argc)
146 argv[i++] = argv[a++];
147 argv[i] = 0;
148
149 if (xwin_init(argc, argv))
150 exit(1);
151 }
152
153 void
init_table(int width,int height)154 init_table(int width, int height)
155 {
156
157 if (width > display_width)
158 width = display_width;
159 if (height > display_height)
160 height = display_height;
161
162 ew = width;
163 eh = height;
164
165 table_width = width;
166 table_height = height;
167
168 xwin_create (width, height);
169 }
170
171 typedef struct PicRec {
172 Pixmap pixmap;
173 Pixmap mask;
174 char **xpm_data;
175 int image_table_index;
176 } PicRec;
177
178 int get_picture_default_width = CARD_WIDTH;
179 int get_picture_default_height = CARD_HEIGHT;
180
181 Picture *
get_picture(char * name)182 get_picture(char *name)
183 {
184 image *img;
185 img = get_image(name, get_picture_default_width, get_picture_default_height, 0);
186 return (Picture *)img;
187 }
188
189 static int put_picture_flags = 0;
190
191 void
put_picture(Picture * picture,int dx,int dy,int x,int y,int w,int h)192 put_picture(Picture *picture, int dx, int dy,
193 int x, int y, int w, int h)
194 {
195 if (!picture) return;
196 if (graphics_disabled) return;
197 #if TRACE_PICTURES
198 /*printf("copy bef: x=%3d y=%3d w=%3d h=%3d\n", dx+x, dy+y, w, h);*/
199 #endif
200
201 if (dx+x < ex)
202 {
203 w -= ex-(dx+x);
204 x += ex-(dx+x);
205 }
206 if (dx+x+w > ex+ew)
207 w = ex+ew - (dx+x);
208 if (dy+y < ey)
209 {
210 h -= ey-(dy+y);
211 y += ey-(dy+y);
212 }
213 if (dy+y+h > ey+eh)
214 h = ey+eh - (dy+y);
215 #if TRACE_PICTURES
216 printf("copy clip: x=%3d y=%3d w=%3d h=%3d (ex=%d ey=%d ew=%d eh=%d)\n",
217 dx+x, dy+y, w, h, ex, ey, ew, eh);
218 #endif
219 if (w>0 && h>0)
220 {
221 #if TRACE_PICTURES
222 printf("copy aft: x=%3d y=%3d w=%3d h=%3d\n", dx+x, dy+y, w, h);
223 #endif
224 put_image ((image *)picture, x, y, w, h, display_image, dx, dy, put_picture_flags);
225 }
226 }
227
228 void
put_picture_inverted(Picture * picture,int dx,int dy,int x,int y,int w,int h)229 put_picture_inverted(Picture *picture, int dx, int dy,
230 int x, int y, int w, int h)
231 {
232 put_picture_flags = PUT_INVERTED;
233 put_picture (picture, dx, dy, x, y, w, h);
234 put_picture_flags = 0;
235 }
236
237 void
set_centered_pic(Picture * picture)238 set_centered_pic(Picture *picture)
239 {
240 int x, y, w=0, h=0;
241 if (centered_pic)
242 {
243 x = table_width/2-centered_pic->w/2;
244 y = table_height/2-centered_pic->h/2;
245 w = centered_pic->w;
246 h = centered_pic->h;
247 }
248 centered_pic = picture;
249 if (centered_pic)
250 {
251 if (centered_pic->w > w)
252 {
253 x = table_width/2-centered_pic->w/2;
254 w = centered_pic->w;
255 }
256 if (centered_pic->h > h)
257 {
258 y = table_height/2-centered_pic->h/2;
259 h = centered_pic->h;
260 }
261 }
262 if (! graphics_disabled)
263 invalidate(x, y, w, h);
264 }
265
266 Picture *
get_centered_pic()267 get_centered_pic()
268 {
269 return centered_pic;
270 }
271
272 static void
redraw_centered_pic()273 redraw_centered_pic()
274 {
275 if (centered_pic)
276 put_picture(centered_pic, table_width/2-centered_pic->w/2,
277 table_height/2-centered_pic->h/2,
278 0, 0, centered_pic->w, centered_pic->h);
279 }
280
281 #define CLEAR_CLIP ex = 0; ey = 0; ew = table_width; eh = table_height; xwin_noclip();
282
283 static int dcx, dcy, dct=0; /* double click memory */
284 static int drag_enabled=0;
285
286 static void
check_dclick(int x,int y,int t)287 check_dclick(int x, int y, int t)
288 {
289 if (t>dct+DBLCLICK_TIME)
290 dct = t-2*DBLCLICK_TIME;
291 if (x < dcx-DBLCLICK_MOVE || x>dcx+DBLCLICK_MOVE
292 || y < dcy-DBLCLICK_MOVE || y > dcy+DBLCLICK_MOVE)
293 {
294 dct = t-2*DBLCLICK_TIME;
295 drag_enabled = 1;
296 }
297 }
298
299 int help_is_showing = 0;
help_nothing()300 static void help_nothing() { help_is_showing = 0; }
301 void (*help_redraw)(void) = help_nothing;
302 void (*help_click)(int x, int y, int b) = help_nothing;
303 void (*help_key)(int c, int x, int y) = help_nothing;
304
305 static int no_resize = 0;
306 void
table_no_resize()307 table_no_resize()
308 {
309 no_resize = 1;
310 }
311
312 static int initted = 0;
313
314 static void
maybe_init()315 maybe_init()
316 {
317 if (! initted)
318 {
319 initted = 1;
320 flush();
321 graphics_disabled = 1;
322 init_cb();
323 graphics_disabled = 0;
324 #if TRACE_EVENTS
325 printf(" - done init\n");
326 #endif
327 }
328 }
329
330 void
table_loop()331 table_loop()
332 {
333 int first_expose = 0;
334 int click_button;
335
336 while (1)
337 {
338 XWin_Event event;
339 xwin_nextevent(&event);
340
341 if (!initted && (event.type != ev_expose && event.type != ev_resize))
342 continue;
343
344 switch (event.type)
345 {
346 case ev_resize:
347 #if TRACE_EVENTS
348 printf("resize: x=%3d y=%3d w=%3d h=%3d, no=%d\n",
349 event.x, event.y, event.w, event.h, no_resize);
350 #endif
351
352 maybe_init();
353
354 if (no_resize)
355 xwin_fixed_size(table_width, table_height);
356 else
357 {
358 graphics_disabled = 1;
359 resize_cb(event.w, event.h);
360 graphics_disabled = 0;
361 if (no_resize)
362 xwin_fixed_size(table_width, table_height);
363 else
364 {
365 table_width = event.w;
366 table_height = event.h;
367 if (first_expose)
368 {
369 clear (0, 0, table_width, table_height);
370 redraw_cb();
371 }
372 }
373 }
374 break;
375
376 case ev_expose:
377 first_expose = 1;
378 ex = event.x;
379 ey = event.y;
380 ew = event.w;
381 eh = event.h;
382 #if TRACE_EVENTS
383 printf("expose: x=%3d y=%3d w=%3d h=%3d\n",
384 ex, ey, ew, eh);
385 #endif
386 CD;
387 xwin_clip (ex, ey, ew, eh);
388 clear(ex, ey, ew, eh);
389
390 maybe_init();
391
392 ex = event.x;
393 ey = event.y;
394 ew = event.w;
395 eh = event.h;
396 CD;
397 if (help_is_showing)
398 help_redraw();
399 else
400 redraw_cb();
401 redraw_centered_pic();
402 xwin_noclip();
403 #if TRACE_EVENTS
404 printf(" - done expose\n");
405 #endif
406 break;
407
408 case ev_buttondown:
409 CLEAR_CLIP;
410 CD;
411 #if TRACE_EVENTS
412 printf("click: %d,%d %d\n",
413 event.x, event.y, event.button);
414 #endif
415 click_button = event.button;
416 check_dclick(event.x, event.y, event.time);
417 if (help_is_showing)
418 {
419 help_click(event.x, event.y, click_button);
420 }
421 else if (event.time - dct < DBLCLICK_TIME)
422 {
423 double_click_cb(event.x, event.y, event.button);
424 dct -= DBLCLICK_TIME;
425 }
426 else
427 {
428 click_cb(event.x, event.y, click_button);
429 dcx = event.x;
430 dcy = event.y;
431 dct = event.time;
432 }
433 drag_enabled = 0;
434 break;
435
436 case ev_motion:
437 CLEAR_CLIP;
438 CD;
439 check_dclick(event.x, event.y, event.time);
440 if (drag_enabled && !help_is_showing)
441 {
442 #if TRACE_EVENTS
443 printf("drag: %d,%d %d\n", event.x, event.y, click_button);
444 #endif
445 drag_cb(event.x, event.y, click_button);
446 }
447 break;
448
449 case ev_buttonup:
450 CLEAR_CLIP;
451 check_dclick(event.x, event.y, event.time);
452 CD;
453 #if TRACE_EVENTS
454 printf("drop: %d,%d\n", event.x, event.y);
455 #endif
456 if (!help_is_showing)
457 drop_cb(event.x, event.y, click_button);
458 break;
459
460 case ev_keypress:
461 CLEAR_CLIP;
462 CD;
463 if (help_is_showing)
464 help_key(event.key, event.x, event.y);
465 else
466 key_cb(event.key, event.x, event.y);
467 break;
468
469 case ev_quit:
470 exit(0);
471 }
472 }
473 }
474
475 static void
reset_clip()476 reset_clip()
477 {
478 xwin_clip (ex, ey, ew, eh);
479 }
480
481 void
clip(int x,int y,int w,int h)482 clip(int x, int y, int w, int h)
483 {
484 if (graphics_disabled) return;
485 ex = x;
486 ey = y;
487 ew = w;
488 eh = h;
489
490 if (ew < 0) ew = 0;
491 if (eh < 0) eh = 0;
492 if (ex < 0)
493 {
494 ew += ex;
495 ex = 0;
496 }
497 if (ey < 0)
498 {
499 eh += ey;
500 ey = 0;
501 }
502 if (ex+ew > table_width)
503 ew = table_width - ex;
504 if (ey+eh > table_height)
505 eh = table_height - ey;
506 reset_clip();
507 }
508
509 static int *clip_saves = 0;
510
511 void
clip_more(int x,int y,int w,int h)512 clip_more(int x, int y, int w, int h)
513 {
514 int *save = (int *)malloc (5*sizeof(int));
515 save[0] = (int)clip_saves;
516 save[1] = ex;
517 save[2] = ey;
518 save[3] = ew;
519 save[4] = eh;
520 clip_saves = save;
521
522 if (x+w > ex+ew)
523 w = ex+ew - x;
524 if (y+h > ey+eh)
525 h = ey+eh - y;
526 if (x < ex)
527 {
528 w -= ex-x;
529 x = ex;
530 }
531 if (y < ey)
532 {
533 h -= ey-y;
534 y = ey;
535 }
536 clip (x, y, w, h);
537 }
538
539 void
unclip()540 unclip()
541 {
542 int *ptr = clip_saves;
543 if (!ptr) return;
544 ex = clip_saves[1];
545 ey = clip_saves[1];
546 ew = clip_saves[1];
547 eh = clip_saves[1];
548 clip_saves = (int *)clip_saves[0];
549 free (clip_saves);
550 xwin_noclip();
551 reset_clip();
552 }
553
554 static void
invalidate_sub(int x,int y,int w,int h)555 invalidate_sub(int x, int y, int w, int h)
556 {
557 #if TRACE_INVALIDATE
558 printf("inv_sub(%d, %d, %d, %d)\n", x, y, w, h);
559 #endif
560 ex = x;
561 ey = y;
562 ew = w;
563 eh = h;
564 CD;
565 reset_clip();
566 clear(ex, ey, ew, eh);
567 if (help_is_showing)
568 help_redraw();
569 else
570 redraw_cb();
571 redraw_centered_pic();
572 xwin_noclip();
573 }
574
575 void
invalidate(int x,int y,int w,int h)576 invalidate(int x, int y, int w, int h)
577 {
578 int ox = ex;
579 int oy = ey;
580 int ow = ew;
581 int oh = eh;
582 if (graphics_disabled) return;
583 #if TRACE_INVALIDATE
584 printf("invalidate(%d, %d, %d, %d)\n", x, y, w, h);
585 #endif
586 invalidate_sub(x, y, w, h);
587 #if TRACE_INVALIDATE
588 printf(" - done invalidate\n");
589 #endif
590 ex = ox;
591 ey = oy;
592 ew = ow;
593 eh = oh;
594 reset_clip();
595 CD;
596 }
597
598 void
invalidate_nc(int x,int y,int w,int h)599 invalidate_nc(int x, int y, int w, int h)
600 {
601 int ox = ex;
602 int oy = ey;
603 int ow = ew;
604 int oh = eh;
605 if (graphics_disabled) return;
606 #if TRACE_INVALIDATE
607 printf("invalidate_nc(%d, %d, %d, %d)\n", x, y, w, h);
608 #endif
609 ex = x;
610 ey = y;
611 ew = w;
612 eh = h;
613 CD;
614 reset_clip();
615 if (help_is_showing)
616 help_redraw();
617 else
618 redraw_cb();
619 redraw_centered_pic();
620 #if TRACE_INVALIDATE
621 printf(" - done invalidate\n");
622 #endif
623 ex = ox;
624 ey = oy;
625 ew = ow;
626 eh = oh;
627 reset_clip();
628 CD;
629 }
630
631 /* Invalidate the results of moving a picture and "exposing" what
632 it used to cover. */
633 void
invalidate_exposure(int ox,int oy,int ow,int oh,int nx,int ny,int nw,int nh)634 invalidate_exposure(int ox, int oy, int ow, int oh,
635 int nx, int ny, int nw, int nh)
636 {
637 int oex = ex;
638 int oey = ey;
639 int oew = ew;
640 int oeh = eh;
641 if (graphics_disabled) return;
642
643 #if TRACE_INVALIDATE
644 printf("invalidate_exposure(%d, %d, %d, %d - %d, %d, %d, %d)\n",
645 ox, oy, ow, oh, nx, ny, nw, nh);
646 #endif
647
648 /* check for the non-overlapping case */
649 if (ox+ow <= nx || ox >= nx+nw || oy+oh <= ny || oy >= ny+nh)
650 {
651 #if TRACE_INVALIDATE
652 printf("- not overlapping\n");
653 #endif
654 invalidate_sub(ox, oy, ow, oh);
655 ex = oex;
656 ey = oey;
657 ew = oew;
658 eh = oeh;
659 CD;
660 return;
661 }
662
663 /* now we know that they *do* overlap */
664
665 if (nx+nw < ox+ow) /* exposure on the right */
666 {
667 #if TRACE_INVALIDATE
668 printf("- exposed on right\n");
669 #endif
670 invalidate_sub(nx+nw, oy, (ox+ow)-(nx+nw), oh);
671 ow = (nx+nw) - ox;
672 }
673
674 if (ox < nx) /* exposure on the left */
675 {
676 #if TRACE_INVALIDATE
677 printf("- exposed on left\n");
678 #endif
679 invalidate_sub(ox, oy, (nx-ox), oh);
680 ow = (ox+ow) - nx;
681 ox = nx;
682 }
683
684 if (ny+nh < oy+oh) /* exposure on the bottom */
685 {
686 #if TRACE_INVALIDATE
687 printf("- exposed on bottom\n");
688 #endif
689 invalidate_sub(ox, ny+nh, ow, (oy+oh)-(ny+nh));
690 oh = (ny+nh) - oy;
691 }
692
693 if (oy < ny) /* exposure on the top */
694 {
695 #if TRACE_INVALIDATE
696 printf("- exposed on top\n");
697 #endif
698 invalidate_sub(ox, oy, ow, (ny-oy));
699 /* Not needed */
700 /* oh = (oy+oh) - ny; */
701 /* oy = ny; */
702 }
703 ex = oex;
704 ey = oey;
705 ew = oew;
706 eh = oeh;
707 CD;
708
709 #if TRACE_INVALIDATE
710 printf("- done invalidate_exposure\n");
711 #endif
712 }
713
714
715 static int
snap_one(int x,int step,int origin,int m,int * did_it)716 snap_one(int x, int step, int origin, int m, int *did_it)
717 {
718 int offset, dx;
719
720 x -= origin;
721 dx = ((x+step/2) % step) - step/2;
722 if (-m <= dx && dx <= m)
723 {
724 x -= dx;
725 *did_it = 1;
726 }
727
728 x += origin;
729 return x;
730 }
731
732 void
snap_to_grid(int * x,int * y,int step_x,int step_y,int origin_x,int origin_y,int max_distance)733 snap_to_grid(int *x, int *y,
734 int step_x, int step_y,
735 int origin_x, int origin_y,
736 int max_distance)
737 {
738 int sx, sy, snapx=0, snapy=0;
739 sx = snap_one(*x, step_x, origin_x, max_distance, &snapx);
740 sy = snap_one(*y, step_y, origin_y, max_distance, &snapy);
741 if (snapx && snapy)
742 {
743 *x = sx;
744 *y = sy;
745 }
746 }
747
748 char *suit_spots[] = {
749 "15",
750 "101:",
751 "10151:",
752 "00200:2:",
753 "0020150:2:",
754 "002005250:2:",
755 "00201205250:2:",
756 "0020032307270:2:",
757 "002003231507270:2:",
758 "00201104240626190:2:"
759 };
760
761 int spot_xx[] = { 0, 50, 100 };
762 int spot_yy[] = { 0, 16, 25, 33, 36, 50, 63, 66, 75, 83, 100 };
763
764 static void
card_synth2(image * rv)765 card_synth2(image *rv)
766 {
767 image *face_img, *img;
768 int face, suit, color;
769 static char face_chars[] = "a234567890jqk";
770 static char suit_chars[] = "cdsh";
771 int subw, subh, face_w, w;
772 int width = rv->width, height = rv->height;
773 image_list *list = rv->list;
774
775 fill_image (rv, 0, 0, width, height, 255, 255, 255);
776
777 face = strchr(face_chars, list->name[0]) - face_chars;
778 suit = strchr(suit_chars, list->name[1]) - suit_chars;
779 color = suit & 1;
780
781 face_w = width*2/11;
782 face_img = get_image("a-k", face_w*2, face_w*13, 0);
783 face_w = face_img->width / face_img->list->across;
784
785 if (face < 10 && width > 3*face_w)
786 {
787 char *spots = suit_spots[face];
788 int sw, sh;
789 if (face == 0)
790 {
791 sw = width;
792 sh = height;
793 }
794 else
795 {
796 sw = (width - 2*face_w) / 3;
797 sh = (height - 2*face_w) / 4;
798 }
799 if (face == 0 && suit == 2)
800 img = get_image("penguin", sw, sh, GI_NOT_BIGGER);
801 else
802 img = get_image("suits", sw, sh*4, GI_NOT_BIGGER);
803 if (img)
804 {
805 int spw, sph, spoh, spow;
806 sw = img->width / img->list->across;
807 sh = img->height / img->list->down;
808 spow = face_w + 2;
809 spoh = face_w*3/4 + 2;
810 spw = width - 2*spow - sw;
811 sph = height - 2*spoh - sh;
812 while (*spots)
813 {
814 int sx = spot_xx[spots[0]-'0'] * spw / 100 + spow;
815 int sy = spot_yy[spots[1]-'0'] * sph / 100 + spoh;
816 put_subimage (img, 0, suit, rv, sx, sy,
817 spot_yy[spots[1]-'0'] > 51 ? PUT_ROTATED : 0);
818 spots += 2;
819 }
820 }
821 }
822
823 if (face >= 10 && width > 3*face_w)
824 {
825 int wm = face_w+2;
826 int hm = face_w*3/4+2;
827 int w2 = width-2*wm;
828 int h2 = height-2*hm;
829 image *kqj, *simg;
830 static char *portrait[] = {"jack", "queen", "king"};
831
832 fill_image (rv, wm, hm, w2, 1, 0, 0, 0);
833 fill_image (rv, wm, hm, 1, h2, 0, 0, 0);
834 fill_image (rv, wm, height-hm, w2, 1, 0, 0, 0);
835 fill_image (rv, width-wm, hm, 1, h2, 0, 0, 0);
836
837 simg = get_image("suits", w2/3, w2*4/3, 0);
838
839 kqj = get_image(portrait[face-10], w2, h2/2, GI_NOT_BIGGER);
840 if (!kqj)
841 kqj = get_image(portrait[face-10], w2, h2, GI_NOT_BIGGER);
842
843 if (simg)
844 {
845 put_subimage (simg, 0, suit, rv, wm+2, hm+2, 0);
846 put_subimage (simg, 0, suit, rv, width-wm-1-simg->width, height-hm-1-simg->height/4, PUT_ROTATED);
847 }
848
849 if (kqj && kqj->height <= h2/2)
850 {
851 put_subimage (kqj, 0, 0, rv, width-wm-kqj->width, height/2-kqj->height, 0);
852 put_subimage (kqj, 0, 0, rv, wm+1, (height+1)/2, PUT_ROTATED);
853 }
854 else if (kqj && kqj->height <= h2/2+3)
855 {
856 put_subimage (kqj, 0, 0, rv, width-wm-kqj->width, hm+1, 0);
857 put_subimage (kqj, 0, 0, rv, wm+1, height-hm-kqj->height, PUT_ROTATED);
858 }
859 else if (kqj)
860 {
861 put_subimage (kqj, 0, 0, rv, (width+1-kqj->width)/2, (height+1-kqj->height)/2, 0);
862 }
863 }
864
865 fill_image (rv, 0, 0, width, 1, 0, 0, 0);
866 fill_image (rv, 0, 0, 1, height, 0, 0, 0);
867 fill_image (rv, 0, height-1, width, 1, 0, 0, 0);
868 fill_image (rv, width-1, 0, 1, height, 0, 0, 0);
869
870 put_subimage (face_img, color, face, rv, 1, 2, 0);
871 subw = face_img->width / face_img->list->across;
872 subh = face_img->height / face_img->list->down;
873 if (width > subw*2+4)
874 put_subimage (face_img, color, face, rv, width-1-subw, height-2-subh, PUT_ROTATED);
875
876 img = get_image("suits", subw-2, (subw-2)*4, GI_NOT_BIGGER);
877 put_subimage (img, 0, suit, rv, 1+subw/2-img->width/2, 4+subh, 0);
878 if (width > subw*2+4)
879 put_subimage (img, 0, suit, rv,
880 width-1-subw/2-img->width/2, height-4-subh-img->height/img->list->down,
881 PUT_ROTATED);
882 }
883
884 static image *
card_synth(image_list * list,int type,int width,int height)885 card_synth(image_list *list, int type, int width, int height)
886 {
887 image *rv;
888 static int minw=0, minh=0;
889
890 for (rv = list->subimage[type]; rv; rv=rv->next)
891 if (rv->width == width && rv->height == height)
892 return rv;
893
894 if (minw == 0)
895 {
896 image *val, *suit;
897 int face_w = width*2/11;
898 val = get_image("a-k", face_w*2, face_w*13, 0);
899 suit = get_image("suits", 9, 9*4, 0);
900 minw = val->width / val->list->across + 2;
901 minh = val->height / val->list->down + suit->height / suit->list->down + 6;
902 }
903
904 if (width < minw)
905 width = minw;
906 if (height < minh)
907 height = minh;
908
909 rv = alloc_synth_image(list, width, height, type);
910 rv->synth_func = card_synth2;
911 return rv;
912 }
913
914 static void
empty_synth2(image * img)915 empty_synth2(image *img)
916 {
917 fill_image (img, 0, 0, img->width, img->height, 0, 102, 0);
918 fill_image (img, 0, img->height-1, img->width, 1, 0, 0, 0);
919 fill_image (img, img->width-1, 0, 1, img->height, 0, 0, 0);
920 fill_image (img, 0, 0, img->width, 1, 0, 204, 0);
921 fill_image (img, 0, 0, 1, img->height, 0, 204, 0);
922 }
923
924 static image *
empty_synth(image_list * list,int type,int width,int height)925 empty_synth(image_list *list, int type, int width, int height)
926 {
927 image *rv, *img;
928
929 for (rv = list->subimage[type]; rv; rv=rv->next)
930 if (rv->width == width && rv->height == height)
931 return rv;
932
933 rv = alloc_synth_image(list, width, height, type);
934 rv->synth_func = empty_synth2;
935 return rv;
936 }
937
938 static void
back_synth2(image * img)939 back_synth2(image *img)
940 {
941 image *tile = get_image ("back-tile", 1, 1, 0);
942 int xo, yo, size;
943 int x, y, l, r;
944 int xs[6];
945 int x01, x23, x24, x25;
946
947 for (x=0; x<img->width; x += tile->width)
948 for (y=0; y<img->height; y += tile->height)
949 put_image (tile, 0, 0, tile->width, tile->height, img, x, y, 0);
950 fill_image (img, 0, img->height-1, img->width, 1, 0, 0, 0);
951 fill_image (img, img->width-1, 0, 1, img->height, 0, 0, 0);
952 fill_image (img, 0, 0, img->width, 1, 0, 0, 0);
953 fill_image (img, 0, 0, 1, img->height, 0, 0, 0);
954
955 if (img->width < img->height)
956 size = img->width * 2/3;
957 else
958 size = img->height * 2/3;
959 xo = (img->width - size) / 2;
960 yo = (img->height - size) / 2;
961
962 x = (size-1) * 203 / 256;
963 x25 = size - 1 - x;
964 x23 = x25 * 105 / 256;
965 x24 = x25 - x23;
966
967 x = (size-1) * 200 / 256;
968 x01 = size - 1 - x;
969
970 for (y=0; y<size; y++)
971 {
972 xs[0] = y * 192/256;
973 xs[1] = xs[0] + x01;
974 xs[2] = (size-1-y) * 203/256;
975 xs[3] = xs[2] + x23;
976 xs[4] = xs[2] + x24;
977 xs[5] = xs[2] + x25;
978
979 l = (xs[0] < xs[2]) ? xs[0] : xs[2];
980 r = (xs[1] < xs[3]) ? xs[1] : xs[3];
981 fill_image (img, l+xo, y+yo, r-l+1, 1, 0, 0, 0);
982
983 l = (xs[0] > xs[4]) ? xs[0] : xs[4];
984 r = (xs[1] > xs[5]) ? xs[1] : xs[5];
985 fill_image (img, l+xo, y+yo, r-l+1, 1, 0, 0, 0);
986 }
987
988 }
989
990 static image *
back_synth(image_list * list,int type,int width,int height)991 back_synth(image_list *list, int type, int width, int height)
992 {
993 image *rv, *img;
994
995 for (rv = list->subimage[type]; rv; rv=rv->next)
996 if (rv->width == width && rv->height == height)
997 return rv;
998
999 rv = alloc_synth_image(list, width, height, type);
1000 rv->synth_func = back_synth2;
1001 return rv;
1002 }
1003
1004 static image_list card_images[] = {
1005 { "ac", 1, 1, {0,0,0}, 0, card_synth, 0 },
1006 { "ad", 1, 1, {0,0,0}, 0, card_synth, 0 },
1007 { "as", 1, 1, {0,0,0}, 0, card_synth, 0 },
1008 { "ah", 1, 1, {0,0,0}, 0, card_synth, 0 },
1009 { "2c", 1, 1, {0,0,0}, 0, card_synth, 0 },
1010 { "2d", 1, 1, {0,0,0}, 0, card_synth, 0 },
1011 { "2s", 1, 1, {0,0,0}, 0, card_synth, 0 },
1012 { "2h", 1, 1, {0,0,0}, 0, card_synth, 0 },
1013 { "3c", 1, 1, {0,0,0}, 0, card_synth, 0 },
1014 { "3d", 1, 1, {0,0,0}, 0, card_synth, 0 },
1015 { "3s", 1, 1, {0,0,0}, 0, card_synth, 0 },
1016 { "3h", 1, 1, {0,0,0}, 0, card_synth, 0 },
1017 { "4c", 1, 1, {0,0,0}, 0, card_synth, 0 },
1018 { "4d", 1, 1, {0,0,0}, 0, card_synth, 0 },
1019 { "4s", 1, 1, {0,0,0}, 0, card_synth, 0 },
1020 { "4h", 1, 1, {0,0,0}, 0, card_synth, 0 },
1021 { "5c", 1, 1, {0,0,0}, 0, card_synth, 0 },
1022 { "5d", 1, 1, {0,0,0}, 0, card_synth, 0 },
1023 { "5s", 1, 1, {0,0,0}, 0, card_synth, 0 },
1024 { "5h", 1, 1, {0,0,0}, 0, card_synth, 0 },
1025 { "6c", 1, 1, {0,0,0}, 0, card_synth, 0 },
1026 { "6d", 1, 1, {0,0,0}, 0, card_synth, 0 },
1027 { "6s", 1, 1, {0,0,0}, 0, card_synth, 0 },
1028 { "6h", 1, 1, {0,0,0}, 0, card_synth, 0 },
1029 { "7c", 1, 1, {0,0,0}, 0, card_synth, 0 },
1030 { "7d", 1, 1, {0,0,0}, 0, card_synth, 0 },
1031 { "7s", 1, 1, {0,0,0}, 0, card_synth, 0 },
1032 { "7h", 1, 1, {0,0,0}, 0, card_synth, 0 },
1033 { "8c", 1, 1, {0,0,0}, 0, card_synth, 0 },
1034 { "8d", 1, 1, {0,0,0}, 0, card_synth, 0 },
1035 { "8s", 1, 1, {0,0,0}, 0, card_synth, 0 },
1036 { "8h", 1, 1, {0,0,0}, 0, card_synth, 0 },
1037 { "9c", 1, 1, {0,0,0}, 0, card_synth, 0 },
1038 { "9d", 1, 1, {0,0,0}, 0, card_synth, 0 },
1039 { "9s", 1, 1, {0,0,0}, 0, card_synth, 0 },
1040 { "9h", 1, 1, {0,0,0}, 0, card_synth, 0 },
1041 { "0c", 1, 1, {0,0,0}, 0, card_synth, 0 },
1042 { "0d", 1, 1, {0,0,0}, 0, card_synth, 0 },
1043 { "0s", 1, 1, {0,0,0}, 0, card_synth, 0 },
1044 { "0h", 1, 1, {0,0,0}, 0, card_synth, 0 },
1045 { "jc", 1, 1, {0,0,0}, 0, card_synth, 0 },
1046 { "jd", 1, 1, {0,0,0}, 0, card_synth, 0 },
1047 { "js", 1, 1, {0,0,0}, 0, card_synth, 0 },
1048 { "jh", 1, 1, {0,0,0}, 0, card_synth, 0 },
1049 { "qc", 1, 1, {0,0,0}, 0, card_synth, 0 },
1050 { "qd", 1, 1, {0,0,0}, 0, card_synth, 0 },
1051 { "qs", 1, 1, {0,0,0}, 0, card_synth, 0 },
1052 { "qh", 1, 1, {0,0,0}, 0, card_synth, 0 },
1053 { "kc", 1, 1, {0,0,0}, 0, card_synth, 0 },
1054 { "kd", 1, 1, {0,0,0}, 0, card_synth, 0 },
1055 { "ks", 1, 1, {0,0,0}, 0, card_synth, 0 },
1056 { "kh", 1, 1, {0,0,0}, 0, card_synth, 0 },
1057 { "empty", 1, 1, {0,0,0}, 0, empty_synth, 0 },
1058 { "back", 1, 1, {0,0,0}, 0, back_synth, 0 },
1059 { 0 }
1060 };
1061
1062