rnd-20040820-1-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 static unsigned short screentiles[14][22]; /* tiles currently on screen */
23
24 static unsigned int colours[8];
25 static unsigned int colour_anim;
26
27 static void xdebug(char *msg)
28 {
29 #if 0
30   XSync(display, False);
31   printf("EM DEBUG: %s\n", msg);
32 #endif
33 }
34
35 static void colour_shuffle(void)
36 {
37         unsigned int i, j, k;
38         for (i = 0; i < 8; i++) colours[i] = i;
39         for (i = 0; i < 8; i++) {
40                 Random = Random * 129 + 1;
41                 j = (Random >> 10) & 7;
42                 k = colours[i];
43                 colours[i] = colours[j];
44                 colours[j] = k;
45         }
46 }
47
48 /* copy the entire screen to the window at the scroll position
49  *
50  * perhaps use mit-shm to speed this up
51  */
52 void blitscreen(void)
53 {
54         unsigned int x = screen_x % (22 * TILEX);
55         unsigned int y = screen_y % (14 * TILEY);
56
57         xdebug("blitscreen");
58
59 #if 0
60         printf("::: %d, %d [%d, %d]\n", x, y, TILEX, TILEY);
61 #endif
62
63         if (x < 2 * TILEX && y < 2 * TILEY) {
64
65 #if 0
66           printf("!!! %ld, %ld, %ld, %ld\n",
67                  display, screenPixmap, xwindow, screenGC);
68 #endif
69
70                 XCopyArea(display, screenPixmap, xwindow, screenGC, x, y, 20 * TILEX, 12 * TILEY, SX, SY);
71         } else if (x < 2 * TILEX && y >= 2 * TILEY) {
72                 XCopyArea(display, screenPixmap, xwindow, screenGC, x, y, 20 * TILEX, 14 * TILEY - y, SX, SY);
73                 XCopyArea(display, screenPixmap, xwindow, screenGC, x, 0, 20 * TILEX, y - 2 * TILEY, SX, SY + 14 * TILEY - y);
74         } else if (x >= 2 * TILEX && y < 2 * TILEY) {
75                 XCopyArea(display, screenPixmap, xwindow, screenGC, x, y, 22 * TILEX - x, 12 * TILEY, SX, SY);
76                 XCopyArea(display, screenPixmap, xwindow, screenGC, 0, y, x - 2 * TILEX, 12 * TILEY, SX + 22 * TILEX - x, SY);
77         } else {
78                 XCopyArea(display, screenPixmap, xwindow, screenGC, x, y, 22 * TILEX - x, 14 * TILEY - y, SX, SY);
79                 XCopyArea(display, screenPixmap, xwindow, screenGC, 0, y, x - 2 * TILEX, 14 * TILEY - y, SX + 22 * TILEX - x, SY);
80                 XCopyArea(display, screenPixmap, xwindow, screenGC, x, 0, 22 * TILEX - x, y - 2 * TILEY, SX, SY + 14 * TILEY - y);
81                 XCopyArea(display, screenPixmap, xwindow, screenGC, 0, 0, x - 2 * TILEX, y - 2 * TILEY, SX + 22 * TILEX - x, SY + 14 * TILEY - y);
82         }
83
84         XCopyArea(display, scorePixmap, xwindow, scoreGC, 0, 0, 20 * TILEX, SCOREY, SX, SY + 12 * TILEY);
85         XFlush(display);
86
87         xdebug("blitscreen - done");
88 }
89
90 /* draw differences between game tiles and screen tiles
91  *
92  * implicitly handles scrolling and restoring background under the sprites
93  *
94  * perhaps use mit-shm to speed this up
95  */
96 static void animscreen(void)
97 {
98         unsigned int x, y, dx, dy;
99         unsigned short obj;
100         unsigned int left = screen_x / TILEX;
101         unsigned int top = screen_y / TILEY;
102
103         xdebug("animscreen");
104
105         for (y = top; y < top + 14; y++) {
106                 dy = y % 14;
107                 for (x = left; x < left + 22; x++) {
108                         dx = x % 22;
109                         obj = map_obj[frame][Draw[y][x]];
110                         if (screentiles[dy][dx] != obj) {
111                                 screentiles[dy][dx] = obj;
112                                 XCopyArea(display, objPixmap, screenPixmap, screenGC, (obj / 512) * TILEX, (obj % 512) * TILEY / 16, TILEX, TILEY, dx * TILEX, dy * TILEY);
113                         }
114                 }
115         }
116 }
117
118 /* blit players to the screen
119  *
120  * handles transparency and movement
121  */
122 static void blitplayer(struct PLAYER *ply)
123 {
124   unsigned int x, y, dx, dy;
125   unsigned short obj, spr;
126
127   xdebug("blitplayer");
128
129   if (ply->alive)
130   {
131     x = (frame * ply->oldx + (8 - frame) * ply->x) * TILEX / 8;
132     y = (frame * ply->oldy + (8 - frame) * ply->y) * TILEY / 8;
133     dx = x + TILEX - 1;
134     dy = y + TILEY - 1;
135
136     if ((unsigned int)(dx - screen_x) < (21 * TILEX - 1) &&
137         (unsigned int)(dy - screen_y) < (13 * TILEY - 1))
138     {
139       spr = map_spr[ply->num][frame][ply->anim];
140       x %= 22 * TILEX;
141       y %= 14 * TILEY;
142       dx %= 22 * TILEX;
143       dy %= 14 * TILEY;
144
145       if (objmaskBitmap)
146       {
147         obj = screentiles[y / TILEY][x / TILEX];
148         XCopyArea(display, objmaskBitmap, spriteBitmap, spriteGC,
149                   (obj / 512) * TILEX, (obj % 512) * TILEY / 16, TILEX, TILEY,
150                   -(x % TILEX), -(y % TILEY));
151
152         obj = screentiles[dy / TILEY][dx / TILEX];
153         XCopyArea(display, objmaskBitmap, spriteBitmap, spriteGC,
154                   (obj / 512) * TILEX, (obj % 512) * TILEY / 16, TILEX, TILEY,
155                   (22 * TILEX - x) % TILEX, (14 * TILEY - y) % TILEY);
156       }
157       else if (sprmaskBitmap)
158       {
159         XCopyArea(display, sprmaskBitmap, spriteBitmap, spriteGC,
160                   (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY, 0, 0);
161       }
162       else
163       {
164         XFillRectangle(display, spriteBitmap, spriteGC, 0, 0, TILEX, TILEY);
165       }
166
167       screentiles[y / TILEY][x / TILEX] = -1; /* mark screen as dirty */
168       screentiles[dy / TILEY][dx / TILEX] = -1;
169
170       XSetClipMask(display, screenGC, spriteBitmap);
171       XSetClipOrigin(display, screenGC, x, y);
172       XCopyArea(display, sprPixmap, screenPixmap, screenGC,
173                 (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY,
174                 x, y);
175       XSetClipOrigin(display, screenGC, x - 22 * TILEX, y);
176       XCopyArea(display, sprPixmap, screenPixmap, screenGC,
177                 (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY,
178                 x - 22 * TILEX, y);
179       XSetClipOrigin(display, screenGC, x, y - 14 * TILEY);
180       XCopyArea(display, sprPixmap, screenPixmap, screenGC,
181                 (spr / 8) * TILEX, (spr % 8) * TILEY, TILEX, TILEY,
182                 x, y - 14 * TILEY);
183       XSetClipMask(display, screenGC, None);
184     }
185   }
186 }
187
188 void game_initscreen(void)
189 {
190         unsigned int x,y;
191
192         xdebug("game_initscreen");
193
194         frame = 6;
195         screen_x = 0;
196         screen_y = 0;
197
198         for (y = 0; y < 14; y++) {
199                 for (x = 0; x < 22; x++) {
200                         screentiles[y][x] = -1;
201                 }
202         }
203
204         colour_shuffle();
205         colours[0] += 16;
206         colours[1] += 16;
207         colours[2] += 16;
208         colour_anim = 0;
209
210         XFillRectangle(display, scorePixmap, scoreGC, 0, 0, 20 * TILEX, SCOREY);
211         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 11 * SCOREX, colours[0] * SCOREY, 3 * SCOREX, SCOREY, 1 * SCOREX, 0); /* 0-63 time */
212         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 18 * SCOREX, colours[0] * SCOREY, 6 * SCOREX, SCOREY, 15 * SCOREX, 0); /* 112-207 diamonds */
213         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 14 * SCOREX, colours[0] * SCOREY, 4 * SCOREX, SCOREY, 32 * SCOREX, 0); /* 256-319 score */
214 }
215
216 void game_blitscore(void)
217 {
218         unsigned int i;
219
220         xdebug("game_blitscore");
221
222         i = (lev.time + 4) / 5;
223         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 7 * SCOREX, 0); i /= 10;
224         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 6 * SCOREX, 0); i /= 10;
225         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 5 * SCOREX, 0); i /= 10;
226         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 4 * SCOREX, 0);
227         i = lev.score;
228         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 39 * SCOREX, 0); i /= 10;
229         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 38 * SCOREX, 0); i /= 10;
230         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 37 * SCOREX, 0); i /= 10;
231         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 36 * SCOREX, 0);
232         if (lev.home == 0) {
233                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 12 * SCOREX, 24 * SCOREY, 12 * SCOREX, SCOREY, 14 * SCOREX, 0); /* relax */
234                 goto done;
235         }
236         if (ply1.alive + ply2.alive >= lev.home && lev.required == 0) {
237                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 24 * SCOREX, colours[2] * SCOREY, 12 * SCOREX, SCOREY, 14 * SCOREX, 0); /* find the exit */
238                 goto done;
239         }
240         if (ply1.alive + ply2.alive < lev.home) {
241                 if (++colour_anim > 11) colour_anim = 0;
242                 if (colour_anim < 6) {
243                         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 0, 24 * SCOREY, 12 * SCOREX, SCOREY, 14 * SCOREX, 0); /* forget it */
244                         goto done;
245                 }
246                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 18 * SCOREX, colours[0] * SCOREY, 6 * SCOREX, SCOREY, 15 * SCOREX, 0); /* diamonds */
247         }
248         i = lev.required;
249         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 24 * SCOREX, 0); i /= 10;
250         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 23 * SCOREX, 0); i /= 10;
251         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 22 * SCOREX, 0); i /= 10;
252         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 21 * SCOREX, 0);
253 done:
254 }
255
256 void game_animscreen(void)
257 {
258         unsigned int x,y;
259
260         xdebug("game_animscreen");
261
262         x = (frame * ply1.oldx + (8 - frame) * ply1.x) * TILEX / 8 + (19 * TILEX) / 2;
263         y = (frame * ply1.oldy + (8 - frame) * ply1.y) * TILEY / 8 + (11 * TILEY) / 2;
264         if (x > lev.width * TILEX) x = lev.width * TILEX;
265         if (y > lev.height * TILEY) y = lev.height * TILEY;
266         if (x < 20 * TILEX) x = 20 * TILEY;
267         if (y < 12 * TILEY) y = 12 * TILEY;
268         screen_x = x - 19 * TILEX;
269         screen_y = y - 11 * TILEY;
270
271         animscreen();
272         blitplayer(&ply1);
273         blitplayer(&ply2);
274         blitscreen();
275         XFlush(display);
276
277         Random = Random * 129 + 1;
278 }
279
280 void title_initscreen(void)
281 {
282         xdebug("title_initscreen");
283
284         screen_x = 0;
285         screen_y = 0;
286
287         colour_shuffle();
288         colours[1] += 8;
289         colour_anim = 0;
290
291         XCopyArea(display, ttlPixmap, screenPixmap, screenGC, 0, 0, 20 * TILEX, 12 * TILEY, 0, 0);
292         if (botmaskBitmap) {
293                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 0, colours[1] * SCOREY, 20 * TILEX, SCOREY, 0, 0);
294                 XSetClipMask(display, scoreGC, botmaskBitmap);
295                 XSetClipOrigin(display, scoreGC, 0, 0 - colours[0] * SCOREY);
296         }
297         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 0, colours[0] * SCOREY, 20 * TILEX, SCOREY, 0, 0);
298         if (botmaskBitmap) {
299                 XSetClipMask(display, scoreGC, None);
300         }
301 }
302
303 void title_blitscore(void)
304 {
305         unsigned int x, y, i;
306
307         xdebug("title_blitscore");
308
309         if (++colour_anim > 30) colour_anim = 0;
310         i = colour_anim >= 16 ? 31 - colour_anim : colour_anim;
311         x = (i / 8 + 18) * 2 * SCOREX;
312         y = (i % 8 + 16) * SCOREY;
313
314         if (botmaskBitmap) {
315                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 32 * SCOREX, colours[1] * SCOREY, 2 * SCOREX, SCOREY, 32 * SCOREX, 0);
316                 XSetClipMask(display, scoreGC, botmaskBitmap);
317                 XSetClipOrigin(display, scoreGC, 32 * SCOREX - x, 0 - y);
318         }
319         XCopyArea(display, botPixmap, scorePixmap, scoreGC, x, y, 2 * SCOREX, SCOREY, 32 * SCOREX, 0);
320         if (botmaskBitmap) {
321                 XSetClipMask(display, scoreGC, None);
322         }
323 }
324
325 void title_blitants(unsigned int y)
326 {
327         static const char ants_dashes[2] = { 8, 7 };
328
329         xdebug("title_blitants");
330
331         XSetDashes(display, antsGC, colour_anim, ants_dashes, 2);
332         XDrawRectangle(display, screenPixmap, antsGC, 0, y * TILEY, 20 * TILEX - 1, TILEY - 1);
333 }
334
335 void title_animscreen(void)
336 {
337         blitscreen();
338         XFlush(display);
339
340         Random = Random * 129 + 1;
341 }
342
343 static int ttl_map[] =
344 {
345   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
346   -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
347   -1,0,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,2,3,4,-1,      /* !',-. */
348   5,6,7,8,9,10,11,12,13,14,15,-1,-1,-1,-1,16,      /* 0123456789:? */
349   -1,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, /* ABCDEFGHIJKLMNO */
350   32,33,34,35,36,37,38,39,40,41,42,-1,-1,-1,-1,-1, /* PQRSTUVWXYZ */
351   -1,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, /* abcdefghijklmno */
352   32,33,34,35,36,37,38,39,40,41,42,-1,-1,-1,-1,-1  /* pqrstuvwxyz */
353 };
354
355 void title_string(unsigned int y, unsigned int left, unsigned int right,
356                   char *string)
357 {
358   int i;
359   unsigned int x;
360
361   xdebug("title_string");
362
363   y *= TILEY;
364   left *= SCOREX;
365   right *= SCOREX;
366
367   x = (left + right - strlen(string) * MENUFONTX) / 2;
368   if (x < left || x >= right) x = left;
369
370   /* restore background graphic where text will be drawn */
371   XCopyArea(display, ttlPixmap, screenPixmap, screenGC,
372             left, y, right - left, MENUFONTY, left, y);
373
374   if (ttlmaskBitmap)
375     XSetClipMask(display, screenGC, ttlmaskBitmap);
376
377   for (i = 0; string[i] && x < right; i++)
378   {
379     int ch_pos, ch_x, ch_y;
380
381     ch_pos = ttl_map[string[i] & 127];
382
383     if (ch_pos == -1 || ch_pos > 22 * 2)
384       continue;                         /* no graphic for this character */
385
386     ch_x = (ch_pos % 22) * GFXMENUFONTX;
387     ch_y = (ch_pos / 22 + 12) * TILEY;
388
389     if (ttlmaskBitmap)
390       XSetClipOrigin(display, screenGC, x - ch_x, y - ch_y);
391
392     XCopyArea(display, ttlPixmap, screenPixmap, screenGC,
393               ch_x, ch_y, MENUFONTX, MENUFONTY, x, y);
394
395     x += MENUFONTX;
396   }
397
398   XSetClipMask(display, screenGC, None);
399 }
400
401 #endif