rnd-20040819-1-src
[rocksndiamonds.git] / src / libem / graphics.c
1
2 #if defined(TARGET_X11)
3
4 /* 2000-08-13T14:36:17Z
5  *
6  * graphics manipulation crap
7  */
8
9 #include <X11/Xlib.h>
10 #include <X11/Xutil.h>
11
12 #include "global.h"
13 #include "display.h"
14 #include "level.h"
15
16 #include <stdio.h>
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, 0, 0);
71         } else if (x < 2 * TILEX && y >= 2 * TILEY) {
72                 XCopyArea(display, screenPixmap, xwindow, screenGC, x, y, 20 * TILEX, 14 * TILEY - y, 0, 0);
73                 XCopyArea(display, screenPixmap, xwindow, screenGC, x, 0, 20 * TILEX, y - 2 * TILEY, 0, 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, 0, 0);
76                 XCopyArea(display, screenPixmap, xwindow, screenGC, 0, y, x - 2 * TILEX, 12 * TILEY, 22 * TILEX - x, 0);
77         } else {
78                 XCopyArea(display, screenPixmap, xwindow, screenGC, x, y, 22 * TILEX - x, 14 * TILEY - y, 0, 0);
79                 XCopyArea(display, screenPixmap, xwindow, screenGC, 0, y, x - 2 * TILEX, 14 * TILEY - y, 22 * TILEX - x, 0);
80                 XCopyArea(display, screenPixmap, xwindow, screenGC, x, 0, 22 * TILEX - x, y - 2 * TILEY, 0, 14 * TILEY - y);
81                 XCopyArea(display, screenPixmap, xwindow, screenGC, 0, 0, x - 2 * TILEX, y - 2 * TILEY, 22 * TILEX - x, 14 * TILEY - y);
82         }
83
84         XCopyArea(display, scorePixmap, xwindow, scoreGC, 0, 0, 20 * TILEX, SCOREY, 0, 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 #if 0
188
189 #if 0
190     printf("::: %ld, %ld\n", objmaskBitmap, sprmaskBitmap);
191 #endif
192
193     if (sprmaskBitmap)
194     {
195       int width = 16 * 4;
196       int height = 16 * 4;
197       XImage *src_ximage = XGetImage(display, sprmaskBitmap, 0, 0,
198                                      width, height, AllPlanes, ZPixmap);
199       XImage *dst_ximage = XGetImage(display, xwindow, 0, 0,
200                                      width, height, AllPlanes, ZPixmap);
201       int x, y;
202
203       if (src_ximage == NULL)
204       {
205         printf("src_ximage failed\n");
206         exit(1);
207       }
208
209       if (dst_ximage == NULL)
210       {
211         printf("dst_ximage failed\n");
212         exit(1);
213       }
214
215       for (x=0; x<width; x++)
216       {
217         for (y=0; y<height; y++)
218         {
219           unsigned long pixel = XGetPixel(src_ximage, x, y);
220
221           if (pixel != BlackPixel(display, screen))
222             pixel = WhitePixel(display, screen);
223
224           XPutPixel(dst_ximage, x, y, pixel);
225         }
226       }
227
228       XPutImage(display, xwindow, screenGC, dst_ximage, 0, 0, 0, 13 * TILEY,
229                 width, height);
230     }
231 #endif
232
233
234   }
235 }
236
237 void game_initscreen(void)
238 {
239         unsigned int x,y;
240
241         xdebug("game_initscreen");
242
243 #if 0
244         printf("--> M5.1: xwindow == %ld\n", xwindow);
245 #endif
246
247         frame = 6;
248         screen_x = 0;
249         screen_y = 0;
250
251 #if 0
252         printf("--> M5.2: &window == %ld\n", &window);
253         printf("--> M5.2: xwindow == %ld\n", xwindow);
254         printf("--> M5.2: &xwindow == %ld\n", &xwindow);
255         printf("--> M5.2: screen == %ld\n", screen);
256         printf("--> M5.2: &screentiles[0][0] == %ld\n", &screentiles[0][0]);
257 #endif
258
259         for (y = 0; y < 14; y++) {
260                 for (x = 0; x < 22; x++) {
261 #if 0
262                   printf("--> M5.2.A: xwindow == %ld [%d,%d]\n", xwindow, x,y);
263 #endif
264                         screentiles[y][x] = -1;
265 #if 0
266                   printf("--> M5.2.B: xwindow == %ld [%d,%d]\n", xwindow, x,y);
267 #endif
268                 }
269         }
270
271 #if 0
272         printf("--> M5.3: xwindow == %ld\n", xwindow);
273 #endif
274
275         colour_shuffle();
276         colours[0] += 16;
277         colours[1] += 16;
278         colours[2] += 16;
279         colour_anim = 0;
280
281 #if 0
282         printf("--> M5.4: xwindow == %ld\n", xwindow);
283 #endif
284
285         XFillRectangle(display, scorePixmap, scoreGC, 0, 0, 20 * TILEX, SCOREY);
286         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 11 * SCOREX, colours[0] * SCOREY, 3 * SCOREX, SCOREY, 1 * SCOREX, 0); /* 0-63 time */
287         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 18 * SCOREX, colours[0] * SCOREY, 6 * SCOREX, SCOREY, 15 * SCOREX, 0); /* 112-207 diamonds */
288         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 14 * SCOREX, colours[0] * SCOREY, 4 * SCOREX, SCOREY, 32 * SCOREX, 0); /* 256-319 score */
289
290 #if 0
291         printf("--> M5.X: xwindow == %ld\n", xwindow);
292 #endif
293 }
294
295 void game_blitscore(void)
296 {
297         unsigned int i;
298
299         xdebug("game_blitscore");
300
301         i = (lev.time + 4) / 5;
302         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 7 * SCOREX, 0); i /= 10;
303         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 6 * SCOREX, 0); i /= 10;
304         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 5 * SCOREX, 0); i /= 10;
305         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 4 * SCOREX, 0);
306         i = lev.score;
307         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 39 * SCOREX, 0); i /= 10;
308         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 38 * SCOREX, 0); i /= 10;
309         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 37 * SCOREX, 0); i /= 10;
310         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 36 * SCOREX, 0);
311         if (lev.home == 0) {
312                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 12 * SCOREX, 24 * SCOREY, 12 * SCOREX, SCOREY, 14 * SCOREX, 0); /* relax */
313                 goto done;
314         }
315         if (ply1.alive + ply2.alive >= lev.home && lev.required == 0) {
316                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 24 * SCOREX, colours[2] * SCOREY, 12 * SCOREX, SCOREY, 14 * SCOREX, 0); /* find the exit */
317                 goto done;
318         }
319         if (ply1.alive + ply2.alive < lev.home) {
320                 if (++colour_anim > 11) colour_anim = 0;
321                 if (colour_anim < 6) {
322                         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 0, 24 * SCOREY, 12 * SCOREX, SCOREY, 14 * SCOREX, 0); /* forget it */
323                         goto done;
324                 }
325                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 18 * SCOREX, colours[0] * SCOREY, 6 * SCOREX, SCOREY, 15 * SCOREX, 0); /* diamonds */
326         }
327         i = lev.required;
328         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 24 * SCOREX, 0); i /= 10;
329         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 23 * SCOREX, 0); i /= 10;
330         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 22 * SCOREX, 0); i /= 10;
331         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 21 * SCOREX, 0);
332 done:
333 }
334
335 void game_animscreen(void)
336 {
337         unsigned int x,y;
338
339         xdebug("game_animscreen");
340
341         x = (frame * ply1.oldx + (8 - frame) * ply1.x) * TILEX / 8 + (19 * TILEX) / 2;
342         y = (frame * ply1.oldy + (8 - frame) * ply1.y) * TILEY / 8 + (11 * TILEY) / 2;
343         if (x > lev.width * TILEX) x = lev.width * TILEX;
344         if (y > lev.height * TILEY) y = lev.height * TILEY;
345         if (x < 20 * TILEX) x = 20 * TILEY;
346         if (y < 12 * TILEY) y = 12 * TILEY;
347         screen_x = x - 19 * TILEX;
348         screen_y = y - 11 * TILEY;
349
350         animscreen();
351         blitplayer(&ply1);
352         blitplayer(&ply2);
353         blitscreen();
354         XFlush(display);
355
356         Random = Random * 129 + 1;
357 }
358
359 void title_initscreen(void)
360 {
361         xdebug("title_initscreen");
362
363         screen_x = 0;
364         screen_y = 0;
365
366         colour_shuffle();
367         colours[1] += 8;
368         colour_anim = 0;
369
370         XCopyArea(display, ttlPixmap, screenPixmap, screenGC, 0, 0, 20 * TILEX, 12 * TILEY, 0, 0);
371         if (botmaskBitmap) {
372                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 0, colours[1] * SCOREY, 20 * TILEX, SCOREY, 0, 0);
373                 XSetClipMask(display, scoreGC, botmaskBitmap);
374                 XSetClipOrigin(display, scoreGC, 0, 0 - colours[0] * SCOREY);
375         }
376         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 0, colours[0] * SCOREY, 20 * TILEX, SCOREY, 0, 0);
377         if (botmaskBitmap) {
378                 XSetClipMask(display, scoreGC, None);
379         }
380 }
381
382 void title_blitscore(void)
383 {
384         unsigned int x, y, i;
385
386         xdebug("title_blitscore");
387
388         if (++colour_anim > 30) colour_anim = 0;
389         i = colour_anim >= 16 ? 31 - colour_anim : colour_anim;
390         x = (i / 8 + 18) * 2 * SCOREX;
391         y = (i % 8 + 16) * SCOREY;
392
393         if (botmaskBitmap) {
394                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 32 * SCOREX, colours[1] * SCOREY, 2 * SCOREX, SCOREY, 32 * SCOREX, 0);
395                 XSetClipMask(display, scoreGC, botmaskBitmap);
396                 XSetClipOrigin(display, scoreGC, 32 * SCOREX - x, 0 - y);
397         }
398         XCopyArea(display, botPixmap, scorePixmap, scoreGC, x, y, 2 * SCOREX, SCOREY, 32 * SCOREX, 0);
399         if (botmaskBitmap) {
400                 XSetClipMask(display, scoreGC, None);
401         }
402 }
403
404 void title_blitants(unsigned int y)
405 {
406         static const char ants_dashes[2] = { 8, 7 };
407
408         xdebug("title_blitants");
409
410         XSetDashes(display, antsGC, colour_anim, ants_dashes, 2);
411         XDrawRectangle(display, screenPixmap, antsGC, 0, y * TILEY, 20 * TILEX - 1, TILEY - 1);
412 }
413
414 void title_animscreen(void)
415 {
416         blitscreen();
417         XFlush(display);
418
419         Random = Random * 129 + 1;
420 }
421
422 void title_string(unsigned int y, unsigned int left, unsigned int right, char *string)
423 {
424         int i;
425         unsigned int x;
426
427         xdebug("title_string");
428
429         y *= TILEY; left *= SCOREX; right *= SCOREX;
430         x = (left + right - strlen(string) * 12) / 2;
431         if (x < left || x >= right) x = left;
432
433         XCopyArea(display, ttlPixmap, screenPixmap, screenGC, left, y, right - left, TILEY, left, y);
434         if (ttlmaskBitmap) XSetClipMask(display, screenGC, ttlmaskBitmap);
435         for (i = 0; string[i] && x < right; i++) {
436                 unsigned short ch_pos, ch_x, ch_y;
437                 ch_pos = map_ttl[string[i] & 127];
438                 if (ch_pos < 640) {
439                         ch_x = (ch_pos % 320);
440                         ch_y = (ch_pos / 320 + 12) * TILEY;
441                         if (ttlmaskBitmap) XSetClipOrigin(display, screenGC, x - ch_x, y - ch_y);
442                         XCopyArea(display, ttlPixmap, screenPixmap, screenGC, ch_x, ch_y, 12, TILEY, x, y);
443                 }
444                 x += 12;
445         }
446         XSetClipMask(display, screenGC, None);
447 }
448
449 #endif