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