rnd-20040816-2-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 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
188 void game_initscreen(void)
189 {
190         unsigned int x,y;
191
192         xdebug("game_initscreen");
193
194 #if 0
195         printf("--> M5.1: xwindow == %ld\n", xwindow);
196 #endif
197
198         frame = 6;
199         screen_x = 0;
200         screen_y = 0;
201
202 #if 0
203         printf("--> M5.2: &window == %ld\n", &window);
204         printf("--> M5.2: xwindow == %ld\n", xwindow);
205         printf("--> M5.2: &xwindow == %ld\n", &xwindow);
206         printf("--> M5.2: screen == %ld\n", screen);
207         printf("--> M5.2: &screentiles[0][0] == %ld\n", &screentiles[0][0]);
208 #endif
209
210         for (y = 0; y < 14; y++) {
211                 for (x = 0; x < 22; x++) {
212 #if 0
213                   printf("--> M5.2.A: xwindow == %ld [%d,%d]\n", xwindow, x,y);
214 #endif
215                         screentiles[y][x] = -1;
216 #if 0
217                   printf("--> M5.2.B: xwindow == %ld [%d,%d]\n", xwindow, x,y);
218 #endif
219                 }
220         }
221
222 #if 0
223         printf("--> M5.3: xwindow == %ld\n", xwindow);
224 #endif
225
226         colour_shuffle();
227         colours[0] += 16;
228         colours[1] += 16;
229         colours[2] += 16;
230         colour_anim = 0;
231
232 #if 0
233         printf("--> M5.4: xwindow == %ld\n", xwindow);
234 #endif
235
236         XFillRectangle(display, scorePixmap, scoreGC, 0, 0, 20 * TILEX, SCOREY);
237         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 11 * SCOREX, colours[0] * SCOREY, 3 * SCOREX, SCOREY, 1 * SCOREX, 0); /* 0-63 time */
238         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 18 * SCOREX, colours[0] * SCOREY, 6 * SCOREX, SCOREY, 15 * SCOREX, 0); /* 112-207 diamonds */
239         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 14 * SCOREX, colours[0] * SCOREY, 4 * SCOREX, SCOREY, 32 * SCOREX, 0); /* 256-319 score */
240
241 #if 0
242         printf("--> M5.X: xwindow == %ld\n", xwindow);
243 #endif
244 }
245
246 void game_blitscore(void)
247 {
248         unsigned int i;
249
250         xdebug("game_blitscore");
251
252         i = (lev.time + 4) / 5;
253         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 7 * SCOREX, 0); i /= 10;
254         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 6 * SCOREX, 0); i /= 10;
255         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 5 * SCOREX, 0); i /= 10;
256         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 4 * SCOREX, 0);
257         i = lev.score;
258         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 39 * SCOREX, 0); i /= 10;
259         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 38 * SCOREX, 0); i /= 10;
260         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 37 * SCOREX, 0); i /= 10;
261         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 36 * SCOREX, 0);
262         if (lev.home == 0) {
263                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 12 * SCOREX, 24 * SCOREY, 12 * SCOREX, SCOREY, 14 * SCOREX, 0); /* relax */
264                 goto done;
265         }
266         if (ply1.alive + ply2.alive >= lev.home && lev.required == 0) {
267                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 24 * SCOREX, colours[2] * SCOREY, 12 * SCOREX, SCOREY, 14 * SCOREX, 0); /* find the exit */
268                 goto done;
269         }
270         if (ply1.alive + ply2.alive < lev.home) {
271                 if (++colour_anim > 11) colour_anim = 0;
272                 if (colour_anim < 6) {
273                         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 0, 24 * SCOREY, 12 * SCOREX, SCOREY, 14 * SCOREX, 0); /* forget it */
274                         goto done;
275                 }
276                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 18 * SCOREX, colours[0] * SCOREY, 6 * SCOREX, SCOREY, 15 * SCOREX, 0); /* diamonds */
277         }
278         i = lev.required;
279         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 24 * SCOREX, 0); i /= 10;
280         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 23 * SCOREX, 0); i /= 10;
281         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 22 * SCOREX, 0); i /= 10;
282         XCopyArea(display, botPixmap, scorePixmap, scoreGC, (i % 10) * SCOREX, colours[1] * SCOREY, SCOREX, SCOREY, 21 * SCOREX, 0);
283 done:
284 }
285
286 void game_animscreen(void)
287 {
288         unsigned int x,y;
289
290         xdebug("game_animscreen");
291
292         x = (frame * ply1.oldx + (8 - frame) * ply1.x) * TILEX / 8 + (19 * TILEX) / 2;
293         y = (frame * ply1.oldy + (8 - frame) * ply1.y) * TILEY / 8 + (11 * TILEY) / 2;
294         if (x > lev.width * TILEX) x = lev.width * TILEX;
295         if (y > lev.height * TILEY) y = lev.height * TILEY;
296         if (x < 20 * TILEX) x = 20 * TILEY;
297         if (y < 12 * TILEY) y = 12 * TILEY;
298         screen_x = x - 19 * TILEX;
299         screen_y = y - 11 * TILEY;
300
301         animscreen();
302         blitplayer(&ply1);
303         blitplayer(&ply2);
304         blitscreen();
305         XFlush(display);
306
307         Random = Random * 129 + 1;
308 }
309
310 void title_initscreen(void)
311 {
312         xdebug("title_initscreen");
313
314         screen_x = 0;
315         screen_y = 0;
316
317         colour_shuffle();
318         colours[1] += 8;
319         colour_anim = 0;
320
321         XCopyArea(display, ttlPixmap, screenPixmap, screenGC, 0, 0, 20 * TILEX, 12 * TILEY, 0, 0);
322         if (botmaskBitmap) {
323                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 0, colours[1] * SCOREY, 20 * TILEX, SCOREY, 0, 0);
324                 XSetClipMask(display, scoreGC, botmaskBitmap);
325                 XSetClipOrigin(display, scoreGC, 0, 0 - colours[0] * SCOREY);
326         }
327         XCopyArea(display, botPixmap, scorePixmap, scoreGC, 0, colours[0] * SCOREY, 20 * TILEX, SCOREY, 0, 0);
328         if (botmaskBitmap) {
329                 XSetClipMask(display, scoreGC, None);
330         }
331 }
332
333 void title_blitscore(void)
334 {
335         unsigned int x, y, i;
336
337         xdebug("title_blitscore");
338
339         if (++colour_anim > 30) colour_anim = 0;
340         i = colour_anim >= 16 ? 31 - colour_anim : colour_anim;
341         x = (i / 8 + 18) * 2 * SCOREX;
342         y = (i % 8 + 16) * SCOREY;
343
344         if (botmaskBitmap) {
345                 XCopyArea(display, botPixmap, scorePixmap, scoreGC, 32 * SCOREX, colours[1] * SCOREY, 2 * SCOREX, SCOREY, 32 * SCOREX, 0);
346                 XSetClipMask(display, scoreGC, botmaskBitmap);
347                 XSetClipOrigin(display, scoreGC, 32 * SCOREX - x, 0 - y);
348         }
349         XCopyArea(display, botPixmap, scorePixmap, scoreGC, x, y, 2 * SCOREX, SCOREY, 32 * SCOREX, 0);
350         if (botmaskBitmap) {
351                 XSetClipMask(display, scoreGC, None);
352         }
353 }
354
355 void title_blitants(unsigned int y)
356 {
357         static const char ants_dashes[2] = { 8, 7 };
358
359         xdebug("title_blitants");
360
361         XSetDashes(display, antsGC, colour_anim, ants_dashes, 2);
362         XDrawRectangle(display, screenPixmap, antsGC, 0, y * TILEY, 20 * TILEX - 1, TILEY - 1);
363 }
364
365 void title_animscreen(void)
366 {
367         blitscreen();
368         XFlush(display);
369
370         Random = Random * 129 + 1;
371 }
372
373 void title_string(unsigned int y, unsigned int left, unsigned int right, char *string)
374 {
375         int i;
376         unsigned int x;
377
378         xdebug("title_string");
379
380         y *= TILEY; left *= SCOREX; right *= SCOREX;
381         x = (left + right - strlen(string) * 12) / 2;
382         if (x < left || x >= right) x = left;
383
384         XCopyArea(display, ttlPixmap, screenPixmap, screenGC, left, y, right - left, TILEY, left, y);
385         if (ttlmaskBitmap) XSetClipMask(display, screenGC, ttlmaskBitmap);
386         for (i = 0; string[i] && x < right; i++) {
387                 unsigned short ch_pos, ch_x, ch_y;
388                 ch_pos = map_ttl[string[i] & 127];
389                 if (ch_pos < 640) {
390                         ch_x = (ch_pos % 320);
391                         ch_y = (ch_pos / 320 + 12) * TILEY;
392                         if (ttlmaskBitmap) XSetClipOrigin(display, screenGC, x - ch_x, y - ch_y);
393                         XCopyArea(display, ttlPixmap, screenPixmap, screenGC, ch_x, ch_y, 12, TILEY, x, y);
394                 }
395                 x += 12;
396         }
397         XSetClipMask(display, screenGC, None);
398 }
399
400 #endif