rnd-20040823-2-src
[rocksndiamonds.git] / src / game_em / graphics.c
1 /* 2000-08-13T14:36:17Z
2  *
3  * graphics manipulation crap
4  */
5
6 #include <X11/Xlib.h>
7 #include <X11/Xutil.h>
8
9 #include "global.h"
10 #include "display.h"
11 #include "level.h"
12
13 #include <stdio.h>
14
15
16 #if defined(TARGET_X11)
17
18 unsigned int frame; /* current frame */
19 unsigned int screen_x; /* current scroll position */
20 unsigned int screen_y;
21
22 /* tiles currently on screen */
23 static unsigned short screentiles[MAX_BUF_YSIZE][MAX_BUF_XSIZE];
24
25 static unsigned int colours[8];
26 static unsigned int colour_anim;
27
28 static void xdebug(char *msg)
29 {
30 #if 0
31   XSync(display, False);
32   printf("EM DEBUG: %s\n", msg);
33 #endif
34 }
35
36 static void colour_shuffle(void)
37 {
38   unsigned int i, j, k;
39
40   for (i = 0; i < 8; i++)
41     colours[i] = i;
42
43   for (i = 0; i < 8; i++)
44   {
45     Random = Random * 129 + 1;
46     j = (Random >> 10) & 7;
47     k = colours[i];
48     colours[i] = colours[j];
49     colours[j] = k;
50   }
51 }
52
53
54 /* copy the entire screen to the window at the scroll position
55  *
56  * perhaps use mit-shm to speed this up
57  */
58
59 void blitscreen(void)
60 {
61   unsigned int x = screen_x % (MAX_BUF_XSIZE * TILEX);
62   unsigned int y = screen_y % (MAX_BUF_YSIZE * TILEY);
63
64   xdebug("blitscreen");
65
66   if (em_game_status == EM_GAME_STATUS_MENU)
67   {
68     ClearRectangle(screenBitmap, 0, SCR_MENUY * TILEY,
69                    SCR_FIELDX * TILEX, (17 - SCR_MENUY) * TILEY);
70     BlitBitmap(scoreBitmap, screenBitmap, 0, 0, SCR_MENUX * TILEX, SCOREY,
71                0, SCR_MENUY * TILEY);
72   }
73
74   if (x < 2 * TILEX && y < 2 * TILEY)
75   {
76     BlitBitmap(screenBitmap, window, x, y,
77                SCR_FIELDX * TILEX, SCR_FIELDY * TILEY, SX, SY);
78   }
79   else if (x < 2 * TILEX && y >= 2 * TILEY)
80   {
81     BlitBitmap(screenBitmap, window, x, y,
82                SCR_FIELDX * TILEX, MAX_BUF_YSIZE * TILEY - y,
83                SX, SY);
84     BlitBitmap(screenBitmap, window, x, 0,
85                SCR_FIELDX * TILEX, y - 2 * TILEY,
86                SX, SY + MAX_BUF_YSIZE * TILEY - y);
87   }
88   else if (x >= 2 * TILEX && y < 2 * TILEY)
89   {
90     BlitBitmap(screenBitmap, window, x, y,
91                MAX_BUF_XSIZE * TILEX - x, SCR_FIELDY * TILEY,
92                SX, SY);
93     BlitBitmap(screenBitmap, window, 0, y,
94                x - 2 * TILEX, SCR_FIELDY * TILEY,
95                SX + MAX_BUF_XSIZE * TILEX - x, SY);
96   }
97   else
98   {
99     BlitBitmap(screenBitmap, window, x, y,
100                MAX_BUF_XSIZE * TILEX - x, MAX_BUF_YSIZE * TILEY - y,
101                SX, SY);
102     BlitBitmap(screenBitmap, window, 0, y,
103                x - 2 * TILEX, MAX_BUF_YSIZE * TILEY - y,
104                SX + MAX_BUF_XSIZE * TILEX - x, SY);
105     BlitBitmap(screenBitmap, window, x, 0,
106                MAX_BUF_XSIZE * TILEX - x, y - 2 * TILEY,
107                SX, SY + MAX_BUF_YSIZE * TILEY - y);
108     BlitBitmap(screenBitmap, window, 0, 0,
109                x - 2 * TILEX, y - 2 * TILEY,
110                SX + MAX_BUF_XSIZE * TILEX - x, SY + MAX_BUF_YSIZE * TILEY - y);
111   }
112
113   if (em_game_status == EM_GAME_STATUS_PLAY && SCR_FIELDY < 17)
114   {
115     BlitBitmap(scoreBitmap, window, 0, 0, SCR_FIELDX * TILEX, SCOREY,
116                SX, SY + SCR_FIELDY * TILEY);
117     ClearRectangle(window, SX, SY + SCR_FIELDY * TILEY + SCOREY,
118                    SCR_FIELDX * TILEX, (17 - SCR_FIELDY) * TILEY - SCOREY);
119   }
120
121   XFlush(display);
122
123   xdebug("blitscreen - done");
124 }
125
126
127 /* draw differences between game tiles and screen tiles
128  *
129  * implicitly handles scrolling and restoring background under the sprites
130  *
131  * perhaps use mit-shm to speed this up
132  */
133
134 static void animscreen(void)
135 {
136   unsigned int x, y, dx, dy;
137   unsigned short obj;
138   unsigned int left = screen_x / TILEX;
139   unsigned int top = screen_y / TILEY;
140
141   xdebug("animscreen");
142
143   for (y = top; y < top + MAX_BUF_YSIZE; y++)
144   {
145     dy = y % MAX_BUF_YSIZE;
146     for (x = left; x < left + MAX_BUF_XSIZE; x++)
147     {
148       dx = x % MAX_BUF_XSIZE;
149       obj = map_obj[frame][Draw[y][x]];
150
151       if (screentiles[dy][dx] != obj)
152       {
153         screentiles[dy][dx] = obj;
154         BlitBitmap(objBitmap, screenBitmap,
155                    (obj / 512) * TILEX, (obj % 512) * TILEY / 16,
156                    TILEX, TILEY, dx * TILEX, dy * TILEY);
157       }
158     }
159   }
160 }
161
162
163 /* blit players to the screen
164  *
165  * handles transparency and movement
166  */
167
168 static void blitplayer(struct PLAYER *ply)
169 {
170   unsigned int x, y, dx, dy;
171   unsigned short obj, spr;
172
173   xdebug("blitplayer");
174
175   if (ply->alive)
176   {
177     x = (frame * ply->oldx + (8 - frame) * ply->x) * TILEX / 8;
178     y = (frame * ply->oldy + (8 - frame) * ply->y) * TILEY / 8;
179     dx = x + TILEX - 1;
180     dy = y + TILEY - 1;
181
182     if ((unsigned int)(dx - screen_x) < ((MAX_BUF_XSIZE - 1) * TILEX - 1) &&
183         (unsigned int)(dy - screen_y) < ((MAX_BUF_YSIZE - 1) * TILEY - 1))
184     {
185       spr = map_spr[ply->num][frame][ply->anim];
186       x  %= MAX_BUF_XSIZE * TILEX;
187       y  %= MAX_BUF_YSIZE * TILEY;
188       dx %= MAX_BUF_XSIZE * TILEX;
189       dy %= MAX_BUF_YSIZE * TILEY;
190
191       if (objmaskBitmap)
192       {
193         obj = screentiles[y / TILEY][x / TILEX];
194         XCopyArea(display, objmaskBitmap, spriteBitmap, spriteGC,
195                   (obj / 512) * TILEX, (obj % 512) * TILEY / 16, TILEX, TILEY,
196                   -(x % TILEX), -(y % TILEY));
197
198         obj = screentiles[dy / TILEY][dx / TILEX];
199         XCopyArea(display, objmaskBitmap, spriteBitmap, spriteGC,
200                   (obj / 512) * TILEX, (obj % 512) * TILEY / 16, TILEX, TILEY,
201                   (MAX_BUF_XSIZE * TILEX - x) % TILEX,
202                   (MAX_BUF_YSIZE * TILEY - y) % TILEY);
203       }
204       else if (sprmaskBitmap)
205       {
206         XCopyArea(display, sprmaskBitmap, spriteBitmap, spriteGC,
207                   (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY, 0, 0);
208       }
209       else
210       {
211         XFillRectangle(display, spriteBitmap, spriteGC, 0, 0, TILEX, TILEY);
212       }
213
214       screentiles[y / TILEY][x / TILEX] = -1; /* mark screen as dirty */
215       screentiles[dy / TILEY][dx / TILEX] = -1;
216
217 #if 1
218
219
220 #if 1
221
222       SetClipMask(sprBitmap, sprBitmap->stored_clip_gc, spriteBitmap);
223
224       SetClipOrigin(sprBitmap, sprBitmap->stored_clip_gc, x, y);
225       BlitBitmapMasked(sprBitmap, screenBitmap,
226                        (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY,
227                        x, y);
228
229       SetClipOrigin(sprBitmap, sprBitmap->stored_clip_gc,
230                     x - MAX_BUF_XSIZE * TILEX, y);
231       BlitBitmapMasked(sprBitmap, screenBitmap,
232                        (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY,
233                        x - MAX_BUF_XSIZE * TILEX, y);
234
235       SetClipOrigin(sprBitmap, sprBitmap->stored_clip_gc,
236                     x, y - MAX_BUF_YSIZE * TILEY);
237       BlitBitmapMasked(sprBitmap, screenBitmap,
238                        (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY,
239                        x, y - MAX_BUF_YSIZE * TILEY);
240
241       SetClipMask(sprBitmap, sprBitmap->stored_clip_gc, None);
242
243 #else
244
245       XSetClipMask(display, sprBitmap->stored_clip_gc, spriteBitmap);
246
247       XSetClipOrigin(display, sprBitmap->stored_clip_gc, x, y);
248       XCopyArea(display, sprBitmap->drawable, screenBitmap->drawable,
249                 sprBitmap->stored_clip_gc,
250                 (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY,
251                 x, y);
252
253       XSetClipOrigin(display, sprBitmap->stored_clip_gc,
254                      x - MAX_BUF_XSIZE * TILEX, y);
255       XCopyArea(display, sprBitmap->drawable, screenBitmap->drawable,
256                 sprBitmap->stored_clip_gc,
257                 (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY,
258                 x - MAX_BUF_XSIZE * TILEX, y);
259
260       XSetClipOrigin(display, sprBitmap->stored_clip_gc,
261                      x, y - MAX_BUF_YSIZE * TILEY);
262       XCopyArea(display, sprBitmap->drawable, screenBitmap->drawable,
263                 sprBitmap->stored_clip_gc,
264                 (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY,
265                 x, y - MAX_BUF_YSIZE * TILEY);
266
267       XSetClipMask(display, sprBitmap->stored_clip_gc, None);
268
269 #endif
270
271 #else
272
273       XSetClipMask(display, screenGC, spriteBitmap);
274       XSetClipOrigin(display, screenGC, x, y);
275       XCopyArea(display, sprPixmap, screenPixmap, screenGC,
276                 (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY,
277                 x, y);
278       XSetClipOrigin(display, screenGC, x - MAX_BUF_XSIZE * TILEX, y);
279       XCopyArea(display, sprPixmap, screenPixmap, screenGC,
280                 (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY,
281                 x - MAX_BUF_XSIZE * TILEX, y);
282       XSetClipOrigin(display, screenGC, x, y - MAX_BUF_YSIZE * TILEY);
283       XCopyArea(display, sprPixmap, screenPixmap, screenGC,
284                 (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY,
285                 x, y - MAX_BUF_YSIZE * TILEY);
286       XSetClipMask(display, screenGC, None);
287
288 #endif
289     }
290   }
291 }
292
293
294 /* draw static text for time, gems and score counter */
295
296 void game_initscreen(void)
297 {
298   unsigned int x,y;
299
300   xdebug("game_initscreen");
301
302   frame = 6;
303   screen_x = 0;
304   screen_y = 0;
305
306   for (y = 0; y < MAX_BUF_YSIZE; y++)
307     for (x = 0; x < MAX_BUF_XSIZE; x++)
308       screentiles[y][x] = -1;
309
310   colour_shuffle();
311   colours[0] += 16;
312   colours[1] += 16;
313   colours[2] += 16;
314   colour_anim = 0;
315
316   ClearRectangle(scoreBitmap, 0, 0, SCR_FIELDX * TILEX, SCOREY);
317   BlitBitmap(botBitmap, scoreBitmap,
318              11 * SCOREX, colours[0] * SCOREY, 3 * SCOREX, SCOREY,
319              1 * SCOREX, 0);                            /* 0-63 time */
320   BlitBitmap(botBitmap, scoreBitmap,
321              18 * SCOREX, colours[0] * SCOREY, 6 * SCOREX, SCOREY,
322              11 * SCOREX, 0);                           /* 112-207 diamonds */
323   BlitBitmap(botBitmap, scoreBitmap,
324              14 * SCOREX, colours[0] * SCOREY, 4 * SCOREX, SCOREY,
325              24 * SCOREX, 0);                           /* 256-319 score */
326 }
327
328
329 /* draw current values for time, gems and score counter */
330
331 void game_blitscore(void)
332 {
333   unsigned int i;
334
335   xdebug("game_blitscore");
336
337   DrawGameDoorValues_EM(lev.required, ply1.dynamite, lev.score,
338                         (lev.time + 4) / 5);
339
340   i = (lev.time + 4) / 5;
341   BlitBitmap(botBitmap, scoreBitmap,
342              (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY,
343              7 * SCOREX, 0);
344   i /= 10;
345   BlitBitmap(botBitmap, scoreBitmap,
346              (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY,
347              6 * SCOREX, 0);
348   i /= 10;
349   BlitBitmap(botBitmap, scoreBitmap,
350              (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY,
351              5 * SCOREX, 0);
352   i /= 10;
353   BlitBitmap(botBitmap, scoreBitmap,
354              (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY,
355              4 * SCOREX, 0);
356
357   i = lev.score;
358   BlitBitmap(botBitmap, scoreBitmap,
359              (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY,
360              31 * SCOREX, 0);
361   i /= 10;
362   BlitBitmap(botBitmap, scoreBitmap,
363              (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY,
364              30 * SCOREX, 0);
365   i /= 10;
366   BlitBitmap(botBitmap, scoreBitmap,
367              (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY,
368              29 * SCOREX, 0);
369   i /= 10;
370   BlitBitmap(botBitmap, scoreBitmap,
371              (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY,
372              28 * SCOREX, 0);
373
374   if (lev.home == 0)
375   {
376     BlitBitmap(botBitmap, scoreBitmap,
377                12 * SCOREX, 24 * SCOREY, 12 * SCOREX, SCOREY,
378                14 * SCOREX, 0); /* relax */
379
380     goto done;
381   }
382
383   if (ply1.alive + ply2.alive >= lev.home && lev.required == 0)
384   {
385     BlitBitmap(botBitmap, scoreBitmap,
386                24 * SCOREX, colours[2] * SCOREY, 12 * SCOREX, SCOREY,
387                14 * SCOREX, 0); /* find the exit */
388
389     goto done;
390   }
391
392   if (ply1.alive + ply2.alive < lev.home)
393   {
394     if (++colour_anim > 11)
395       colour_anim = 0;
396
397     if (colour_anim < 6)
398     {
399       BlitBitmap(botBitmap, scoreBitmap,
400                  0, 24 * SCOREY, 12 * SCOREX, SCOREY,
401                  14 * SCOREX, 0); /* forget it */
402
403       goto done;
404     }
405
406     BlitBitmap(botBitmap, scoreBitmap,
407                18 * SCOREX, colours[0] * SCOREY, 6 * SCOREX, SCOREY,
408                15 * SCOREX, 0); /* diamonds */
409   }
410
411   i = lev.required;
412   BlitBitmap(botBitmap, scoreBitmap,
413              (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY,
414              20 * SCOREX, 0);
415   i /= 10;
416   BlitBitmap(botBitmap, scoreBitmap,
417              (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY,
418              19 * SCOREX, 0);
419   i /= 10;
420   BlitBitmap(botBitmap, scoreBitmap,
421              (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY,
422              18 * SCOREX, 0);
423   i /= 10;
424   BlitBitmap(botBitmap, scoreBitmap,
425              (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY,
426              17 * SCOREX, 0);
427
428  done:
429 }
430
431 void game_animscreen(void)
432 {
433   unsigned int x,y;
434
435   xdebug("game_animscreen");
436
437   x = (frame * ply1.oldx + (8 - frame) * ply1.x) * TILEX / 8
438     + ((SCR_FIELDX - 1) * TILEX) / 2;
439   y = (frame * ply1.oldy + (8 - frame) * ply1.y) * TILEY / 8
440     + ((SCR_FIELDY - 1) * TILEY) / 2;
441
442   if (x > lev.width * TILEX)
443     x = lev.width * TILEX;
444   if (y > lev.height * TILEY)
445     y = lev.height * TILEY;
446
447   if (x < SCR_FIELDX * TILEX)
448     x = SCR_FIELDX * TILEY;
449   if (y < SCR_FIELDY * TILEY)
450     y = SCR_FIELDY * TILEY;
451
452   screen_x = x - (SCR_FIELDX - 1) * TILEX;
453   screen_y = y - (SCR_FIELDY - 1) * TILEY;
454
455   animscreen();
456   blitplayer(&ply1);
457   blitplayer(&ply2);
458   blitscreen();
459
460   XFlush(display);
461
462   Random = Random * 129 + 1;
463 }
464
465
466 /* draw main menu background and copyright note */
467
468 void title_initscreen(void)
469 {
470   xdebug("title_initscreen");
471
472   screen_x = 0;
473   screen_y = 0;
474
475   colour_shuffle();
476   colours[1] += 8;
477   colour_anim = 0;
478
479 #if 1
480
481   /* draw title screen on menu background */
482
483   BlitBitmap(ttlBitmap, screenBitmap, ORIG_MENU_SX, ORIG_MENU_SY,
484              SCR_MENUX * TILEX, SCR_MENUY * TILEY, 0, 0);
485
486   /* draw copyright note at footer */
487
488   if (botmaskBitmap)
489   {
490     BlitBitmap(botBitmap, scoreBitmap, 0, colours[1] * SCOREY,
491                SCR_MENUX * TILEX, SCOREY, 0, 0);
492
493     SetClipOrigin(botBitmap, botBitmap->stored_clip_gc,
494                   0, 0 - colours[0] * SCOREY);
495   }
496
497   BlitBitmapMasked(botBitmap, scoreBitmap, 0, colours[0] * SCOREY,
498                    SCR_MENUX * TILEX, SCOREY, 0, 0);
499
500 #else
501
502   XCopyArea(display, ttlPixmap, screenPixmap, screenGC,
503             0, 0, SCR_MENUX * TILEX, SCR_MENUY * TILEY, 0, 0);
504
505   if (botmaskBitmap)
506   {
507     XCopyArea(display, botPixmap, scorePixmap, scoreGC,
508               0, colours[1] * SCOREY, SCR_MENUX * TILEX, SCOREY, 0, 0);
509     XSetClipMask(display, scoreGC, botmaskBitmap);
510     XSetClipOrigin(display, scoreGC, 0, 0 - colours[0] * SCOREY);
511   }
512
513   XCopyArea(display, botPixmap, scorePixmap, scoreGC,
514             0, colours[0] * SCOREY, SCR_MENUX * TILEX, SCOREY, 0, 0);
515
516   if (botmaskBitmap)
517     XSetClipMask(display, scoreGC, None);
518
519 #endif
520 }
521
522
523 /* draw bouncing ball on main menu footer */
524
525 void title_blitscore(void)
526 {
527   unsigned int x, y, i;
528
529   xdebug("title_blitscore");
530
531   if (++colour_anim > 30)
532     colour_anim = 0;
533
534   i = colour_anim >= 16 ? 31 - colour_anim : colour_anim;
535   x = (i / 8 + 18) * 2 * SCOREX;
536   y = (i % 8 + 16) * SCOREY;
537
538 #if 1
539   if (botmaskBitmap)
540   {
541     BlitBitmap(botBitmap, scoreBitmap,
542                32 * SCOREX, colours[1] * SCOREY, 2 * SCOREX, SCOREY,
543                32 * SCOREX, 0);
544
545     SetClipOrigin(botBitmap, botBitmap->stored_clip_gc,
546                   32 * SCOREX - x, 0 - y);
547   }
548
549   BlitBitmapMasked(botBitmap, scoreBitmap,
550                    x, y, 2 * SCOREX, SCOREY, 32 * SCOREX, 0);
551
552 #else
553
554   if (botmaskBitmap)
555   {
556     XCopyArea(display, botPixmap, scorePixmap, scoreGC,
557               32 * SCOREX, colours[1] * SCOREY, 2 * SCOREX, SCOREY,
558               32 * SCOREX, 0);
559     XSetClipMask(display, scoreGC, botmaskBitmap);
560     XSetClipOrigin(display, scoreGC, 32 * SCOREX - x, 0 - y);
561   }
562
563   XCopyArea(display, botPixmap, scorePixmap, scoreGC,
564             x, y, 2 * SCOREX, SCOREY, 32 * SCOREX, 0);
565
566   if (botmaskBitmap)
567     XSetClipMask(display, scoreGC, None);
568 #endif
569 }
570
571 void title_animscreen(void)
572 {
573   blitscreen();
574   XFlush(display);
575
576   Random = Random * 129 + 1;
577 }
578
579 static int ttl_map[] =
580 {
581   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
582   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
583   -1,0,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,2,3,4,-1,      /* !',-. */
584   5,6,7,8,9,10,11,12,13,14,15,-1,-1,-1,-1,16,      /* 0123456789:? */
585   -1,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, /* ABCDEFGHIJKLMNO */
586   32,33,34,35,36,37,38,39,40,41,42,-1,-1,-1,-1,-1, /* PQRSTUVWXYZ */
587   -1,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, /* abcdefghijklmno */
588   32,33,34,35,36,37,38,39,40,41,42,-1,-1,-1,-1,-1  /* pqrstuvwxyz */
589 };
590
591 void title_string(unsigned int y, unsigned int left, unsigned int right,
592                   char *string)
593 {
594   int i;
595   unsigned int x;
596
597   xdebug("title_string");
598
599   y *= TILEY;
600   left *= SCOREX;
601   right *= SCOREX;
602
603   x = (left + right - strlen(string) * MENUFONTX) / 2;
604   if (x < left || x >= right)
605     x = left;
606
607   /* restore background graphic where text will be drawn */
608   BlitBitmap(ttlBitmap, screenBitmap, ORIG_MENU_SX + left, ORIG_MENU_SY + y,
609              right - left, MENUFONTY, left, y);
610
611 #if 1
612 #else
613   if (ttlmaskBitmap)
614     XSetClipMask(display, screenGC, ttlmaskBitmap);
615 #endif
616
617   for (i = 0; string[i] && x < right; i++)
618   {
619     int ch_pos, ch_x, ch_y;
620
621     ch_pos = ttl_map[string[i] & 127];
622
623     if (ch_pos == -1 || ch_pos > 22 * 2)
624       continue;                         /* no graphic for this character */
625
626     ch_x = (ch_pos % 22) * GFXMENUFONTX;
627     ch_y = (ch_pos / 22 + 12) * TILEY;
628
629 #if 1
630     SetClipOrigin(ttlBitmap, ttlBitmap->stored_clip_gc,
631                   x - ORIG_MENU_SX - ch_x, y - ORIG_MENU_SY - ch_y);
632
633     BlitBitmapMasked(ttlBitmap, screenBitmap, ch_x, ch_y, MENUFONTX, MENUFONTY,
634                      x - ORIG_MENU_SX, y - ORIG_MENU_SY);
635 #else
636     if (ttlmaskBitmap)
637       XSetClipOrigin(display, screenGC, x - ch_x, y - ch_y);
638
639     XCopyArea(display, ttlPixmap, screenPixmap, screenGC,
640               ch_x, ch_y, MENUFONTX, MENUFONTY, x, y);
641 #endif
642
643     x += MENUFONTX;
644   }
645
646 #if 1
647 #else
648   XSetClipMask(display, screenGC, None);
649 #endif
650 }
651
652 #endif