summaryrefslogtreecommitdiff
path: root/apps/plugins/xrick/draw.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/xrick/draw.c')
-rw-r--r--apps/plugins/xrick/draw.c702
1 files changed, 702 insertions, 0 deletions
diff --git a/apps/plugins/xrick/draw.c b/apps/plugins/xrick/draw.c
new file mode 100644
index 0000000000..a759ed5239
--- /dev/null
+++ b/apps/plugins/xrick/draw.c
@@ -0,0 +1,702 @@
1/*
2 * xrick/draw.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16/*
17 * NOTES
18 *
19 * This is the only file which accesses the video. Anything calling d_*
20 * function should be video-independant.
21 *
22 * draw.c draws into a 320x200 or 0x0140x0xc8 8-bits depth frame buffer,
23 * using the CGA 2 bits color codes. It is up to the video to figure out
24 * how to display the frame buffer. Whatever draw.c does, does not show
25 * until the screen is explicitely refreshed.
26 *
27 * The "screen" is the whole 0x0140 by 0x00c8 screen, coordinates go from
28 * 0x0000,0x0000 to 0x013f,0x00c7.
29 *
30 * The "map" is a 0x0100 by 0x0140 rectangle that represents the active
31 * game area.
32 *
33 * Relative to the screen, the "map" is located at 0x0020,-0x0040 : the
34 * "map" is composed of two hidden 0x0100 by 0x0040 rectangles (one at the
35 * top and one at the bottom) and one visible 0x0100 by 0x00c0 rectangle (in
36 * the middle).
37 *
38 * The "map screen" is the visible rectangle ; it is a 0x0100 by 0xc0
39 * rectangle located at 0x0020,0x00.
40 *
41 * Coordinates can be relative to the screen, the map, or the map screen.
42 *
43 * Coordinates can be expressed in pixels. When relative to the map or the
44 * map screen, they can also be expressed in tiles, the map being composed
45 * of rows of 0x20 tiles of 0x08 by 0x08 pixels.
46 */
47
48#include "xrick/system/system.h"
49
50#include "xrick/game.h"
51#include "xrick/draw.h"
52
53#include "xrick/data/sprites.h"
54#include "xrick/data/tiles.h"
55
56#include "xrick/maps.h"
57#include "xrick/rects.h"
58#include "xrick/data/img.h"
59
60
61/*
62 * counters positions (pixels, screen)
63 */
64#ifdef GFXPC
65#define DRAW_STATUS_SCORE_X 0x28
66#define DRAW_STATUS_LIVES_X 0xE8
67#define DRAW_STATUS_Y 0x08
68#endif
69#define DRAW_STATUS_BULLETS_X 0x68
70#define DRAW_STATUS_BOMBS_X 0xA8
71#ifdef GFXST
72#define DRAW_STATUS_SCORE_X 0x20
73#define DRAW_STATUS_LIVES_X 0xF0
74#define DRAW_STATUS_Y 0
75#endif
76
77
78/*
79 * public vars
80 */
81U8 *draw_tllst; /* pointer to tiles list */
82#ifdef GFXPC
83U16 draw_filter; /* CGA colors filter */
84#endif
85U8 draw_tilesBank; /* tile number offset */
86
87rect_t draw_STATUSRECT = {
88 DRAW_STATUS_SCORE_X, DRAW_STATUS_Y,
89 DRAW_STATUS_LIVES_X + 6 * 8 - DRAW_STATUS_SCORE_X, 8,
90 NULL
91};
92const rect_t draw_SCREENRECT = { 0, 0, SYSVID_WIDTH, SYSVID_HEIGHT, NULL };
93
94size_t game_color_count = 0;
95img_color_t *game_colors = NULL;
96
97/*
98 * private vars
99 */
100static U8 *fb; /* frame buffer pointer */
101
102
103/*
104 * Set the frame buffer pointer
105 *
106 * x, y: position (pixels, screen)
107 */
108void
109draw_setfb(U16 x, U16 y)
110{
111 fb = sysvid_fb + x + y * SYSVID_WIDTH;
112}
113
114
115/*
116 * Clip to map screen
117 *
118 * x, y: position (pixels, map) CHANGED clipped
119 * width, height: dimension CHANGED clipped
120 * return: true if fully clipped, false if still (at least partly) visible
121 */
122bool
123draw_clipms(S16 *x, S16 *y, U16 *width, U16 *height)
124{
125 if (*x < 0) {
126 if (*x + *width < 0)
127 return true;
128 else {
129 *width += *x;
130 *x = 0;
131 }
132 }
133 else {
134 if (*x > 0x0100)
135 return true;
136 else if (*x + *width > 0x0100) {
137 *width = 0x0100 - *x;
138 }
139 }
140
141 if (*y < DRAW_XYMAP_SCRTOP) {
142 if ((*y + *height) < DRAW_XYMAP_SCRTOP)
143 return true;
144 else {
145 *height += *y - DRAW_XYMAP_SCRTOP;
146 *y = DRAW_XYMAP_SCRTOP;
147 }
148 }
149 else {
150 if (*y >= DRAW_XYMAP_HBTOP)
151 return true;
152 else if (*y + *height > DRAW_XYMAP_HBTOP)
153 *height = DRAW_XYMAP_HBTOP - *y;
154 }
155
156 return false;
157}
158
159
160/*
161 * Draw a list of tiles onto the frame buffer
162 * start at position indicated by fb ; at the end of each (sub)list,
163 * perform a "carriage return + line feed" i.e. go back to the initial
164 * position then go down one tile row (8 pixels)
165 *
166 * ASM 1e33
167 * fb: CHANGED (see above)
168 * draw_tllst: CHANGED points to the element following 0xfe/0xff end code
169 */
170void
171draw_tilesList(void)
172{
173 U8 *t;
174
175 t = fb;
176 while (draw_tilesSubList() != 0xFE) { /* draw sub-list */
177 t += 8 * SYSVID_WIDTH; /* go down one tile i.e. 8 lines */
178 fb = t;
179 }
180}
181
182
183/*
184 * Draw a list of tiles onto the frame buffer -- same as draw_tilesList,
185 * but accept an immediate string as parameter. Note that the string needs
186 * to be properly terminated with 0xfe (\376) and 0xff (\377) chars.
187 */
188void
189draw_tilesListImm(U8 *list)
190{
191 draw_tllst = list;
192 draw_tilesList();
193}
194
195
196/*
197 * Draw a sub-list of tiles onto the frame buffer
198 * start at position indicated by fb ; leave fb pointing to the next
199 * tile to the right of the last tile drawn
200 *
201 * ASM 1e41
202 * fpb: CHANGED (see above)
203 * draw_tllst: CHANGED points to the element following 0xfe/0xff end code
204 * returns: end code (0xfe : end of list ; 0xff : end of sub-list)
205 */
206U8
207draw_tilesSubList()
208{
209 U8 i;
210
211 i = *(draw_tllst++);
212 while (i != 0xFF && i != 0xFE) { /* while not end */
213 draw_tile(i); /* draw tile */
214 i = *(draw_tllst++);
215 }
216 return i;
217}
218
219
220/*
221 * Draw a tile
222 * at position indicated by fb ; leave fb pointing to the next tile
223 * to the right of the tile drawn
224 *
225 * ASM 1e6c
226 * tlnbr: tile number
227 * draw_filter: CGA colors filter
228 * fb: CHANGED (see above)
229 */
230void
231draw_tile(U8 tileNumber)
232{
233 U8 i, k, *f;
234
235#ifdef GFXPC
236 U16 x;
237#endif
238
239#ifdef GFXST
240 U32 x;
241#endif
242
243 f = fb; /* frame buffer */
244 for (i = 0; i < TILES_NBR_LINES; i++) { /* for all 8 pixel lines */
245
246#ifdef GFXPC
247 x = tiles_data[draw_tilesBank * TILES_NBR_TILES + tileNumber][i] & draw_filter;
248 /*
249 * tiles / perform the transformation from CGA 2 bits
250 * per pixel to frame buffer 8 bits per pixels
251 */
252 for (k = 8; k--; x >>= 2)
253 f[k] = x & 3;
254 f += SYSVID_WIDTH; /* next line */
255#endif
256
257#ifdef GFXST
258 x = tiles_data[draw_tilesBank * TILES_NBR_TILES + tileNumber][i];
259 /*
260 * tiles / perform the transformation from ST 4 bits
261 * per pixel to frame buffer 8 bits per pixels
262 */
263 for (k = 8; k--; x >>= 4)
264 f[k] = x & 0x0F;
265 f += SYSVID_WIDTH; /* next line */
266#endif
267
268 }
269
270 fb += 8; /* next tile */
271}
272
273/*
274 * Draw a sprite
275 *
276 * ASM 1a09
277 * nbr: sprite number
278 * x, y: sprite position (pixels, screen)
279 * fb: CHANGED
280 */
281#ifdef GFXPC
282void
283draw_sprite(U8 nbr, U16 x, U16 y)
284{
285 U8 i, j, k, *f;
286 U16 xm = 0, xp = 0;
287
288 draw_setfb(x, y);
289
290 for (i = 0; i < SPRITES_NBR_COLS; i++) { /* for each tile column */
291 f = fb; /* frame buffer */
292 for (j = 0; j < SPRITES_NBR_ROWS; j++) { /* for each pixel row */
293 xm = sprites_data[nbr][i][j].mask; /* mask */
294 xp = sprites_data[nbr][i][j].pict; /* picture */
295 /*
296 * sprites / perform the transformation from CGA 2 bits
297 * per pixel to frame buffer 8 bits per pixels
298 */
299 for (k = 8; k--; xm >>= 2, xp >>= 2)
300 f[k] = (f[k] & (xm & 3)) | (xp & 3);
301 f += SYSVID_WIDTH;
302 }
303 fb += 8;
304 }
305}
306#endif
307
308
309/*
310 * Draw a sprite
311 *
312 * foobar
313 */
314#ifdef GFXST
315void
316draw_sprite(U8 number, U16 x, U16 y)
317{
318 U8 i, j, k, *f;
319 U16 g;
320 U32 d;
321
322 draw_setfb(x, y);
323 g = 0;
324 for (i = 0; i < SPRITES_NBR_ROWS; i++) { /* rows */
325 f = fb;
326 for (j = 0; j < SPRITES_NBR_COLS; j++) { /* cols */
327 d = sprites_data[number][g++];
328 for (k = 8; k--; d >>= 4)
329 if (d & 0x0F) f[k] = (f[k] & 0xF0) | (d & 0x0F);
330 f += 8;
331 }
332 fb += SYSVID_WIDTH;
333 }
334}
335#endif
336
337
338/*
339 * Draw a sprite
340 *
341 * NOTE re-using original ST graphics format
342 */
343#ifdef GFXST
344void
345draw_sprite2(U8 number, U16 x, U16 y, bool front)
346{
347 U32 d = 0; /* sprite data */
348 S16 x0, y0; /* clipped x, y */
349 U16 w, h; /* width, height */
350 S16 g, /* sprite data offset*/
351 r, c, /* row, column */
352 i, /* frame buffer shifter */
353 im; /* tile flag shifter */
354 U8 flg; /* tile flag */
355
356 x0 = x;
357 y0 = y;
358 w = SPRITES_NBR_COLS * 8; /* each tile column is 8 pixels */
359 h = SPRITES_NBR_ROWS;
360
361 if (draw_clipms(&x0, &y0, &w, &h)) /* return if not visible */
362 return;
363
364 g = 0;
365 draw_setfb(x0 - DRAW_XYMAP_SCRLEFT, y0 - DRAW_XYMAP_SCRTOP + 8);
366
367 for (r = 0; r < SPRITES_NBR_ROWS; r++) {
368 if (r >= h || y + r < y0) continue;
369
370 i = 0x1f;
371 im = x - (x & 0xfff8);
372 flg = map_eflg[map_map[(y + r) >> 3][(x + 0x1f)>> 3]];
373
374#ifdef ENABLE_CHEATS
375#define LOOP(N, C0, C1) \
376 d = sprites_data[number][g + N]; \
377 for (c = C0; c >= C1; c--, i--, d >>= 4, im--) { \
378 if (im == 0) { \
379 flg = map_eflg[map_map[(y + r) >> 3][(x + c) >> 3]]; \
380 im = 8; \
381 } \
382 if (c >= w || x + c < x0) continue; \
383 if (!front && !game_cheat3 && (flg & MAP_EFLG_FGND)) continue; \
384 if (d & 0x0F) fb[i] = (fb[i] & 0xF0) | (d & 0x0F); \
385 if (game_cheat3) fb[i] |= 0x10; \
386 }
387#else
388#define LOOP(N, C0, C1) \
389 d = sprites_data[number][g + N]; \
390 for (c = C0; c >= C1; c--, i--, d >>= 4, im--) { \
391 if (im == 0) { \
392 flg = map_eflg[map_map[(y + r) >> 3][(x + c) >> 3]]; \
393 im = 8; \
394 } \
395 if (!front && (flg & MAP_EFLG_FGND)) continue; \
396 if (c >= w || x + c < x0) continue; \
397 if (d & 0x0F) fb[i] = (fb[i] & 0xF0) | (d & 0x0F); \
398 }
399#endif
400 LOOP(3, 0x1f, 0x18);
401 LOOP(2, 0x17, 0x10);
402 LOOP(1, 0x0f, 0x08);
403 LOOP(0, 0x07, 0x00);
404
405#undef LOOP
406
407 fb += SYSVID_WIDTH;
408 g += SPRITES_NBR_COLS;
409 }
410}
411
412#endif
413
414
415/*
416 * Draw a sprite
417 * align to tile column, determine plane automatically, and clip
418 *
419 * nbr: sprite number
420 * x, y: sprite position (pixels, map).
421 * fb: CHANGED
422 */
423#ifdef GFXPC
424void
425draw_sprite2(U8 number, U16 x, U16 y, bool front)
426{
427 U8 k, *f, c, r, dx;
428 U16 cmax, rmax;
429 U16 xm = 0, xp = 0;
430 S16 xmap, ymap;
431
432 /* align to tile column, prepare map coordinate and clip */
433 xmap = x & 0xFFF8;
434 ymap = y;
435 cmax = SPRITES_NBR_COLS * 8; /* width, 4 tile columns, 8 pixels each */
436 rmax = SPRITES_NBR_ROWS; /* height, 15 pixels */
437 dx = (x - xmap) * 2;
438 if (draw_clipms(&xmap, &ymap, &cmax, &rmax)) /* return if not visible */
439 return;
440
441 /* get back to screen */
442 draw_setfb(xmap - DRAW_XYMAP_SCRLEFT, ymap - DRAW_XYMAP_SCRTOP);
443 xmap >>= 3;
444 cmax >>= 3;
445
446 /* draw */
447 for (c = 0; c < cmax; c++) { /* for each tile column */
448 f = fb;
449 for (r = 0; r < rmax; r++) { /* for each pixel row */
450 /* check that tile is not hidden behind foreground */
451#ifdef ENABLE_CHEATS
452 if (front || game_cheat3 ||
453 !(map_eflg[map_map[(ymap + r) >> 3][xmap + c]] & MAP_EFLG_FGND)) {
454#else
455 if (front ||
456 !(map_eflg[map_map[(ymap + r) >> 3][xmap + c]] & MAP_EFLG_FGND)) {
457#endif
458 xp = xm = 0;
459 if (c > 0) {
460 xm |= sprites_data[number][c - 1][r].mask << (16 - dx);
461 xp |= sprites_data[number][c - 1][r].pict << (16 - dx);
462 }
463 else
464 xm |= 0xFFFF << (16 - dx);
465 if (c < cmax) {
466 xm |= sprites_data[number][c][r].mask >> dx;
467 xp |= sprites_data[number][c][r].pict >> dx;
468 }
469 else
470 xm |= 0xFFFF >> dx;
471 /*
472 * sprites / perform the transformation from CGA 2 bits
473 * per pixel to frame buffer 8 bits per pixels
474 */
475 for (k = 8; k--; xm >>= 2, xp >>= 2) {
476 f[k] = ((f[k] & (xm & 3)) | (xp & 3));
477#ifdef ENABLE_CHEATS
478 if (game_cheat3) f[k] |= 4;
479#endif
480 }
481 }
482 f += SYSVID_WIDTH;
483 }
484 fb += 8;
485 }
486}
487#endif
488
489
490/*
491 * Redraw the map behind a sprite
492 * align to tile column and row, and clip
493 *
494 * x, y: sprite position (pixels, map).
495 */
496void
497draw_spriteBackground(U16 x, U16 y)
498{
499 U8 r, c;
500 U16 rmax, cmax;
501 S16 xmap, ymap;
502 U16 xs, ys;
503
504 /* aligne to column and row, prepare map coordinate, and clip */
505 xmap = x & 0xFFF8;
506 ymap = y & 0xFFF8;
507 cmax = (x - xmap == 0 ? 0x20 : 0x28); /* width, 4 tl cols, 8 pix each */
508 rmax = (y & 0x04) ? 0x20 : 0x18; /* height, 3 or 4 tile rows */
509 if (draw_clipms(&xmap, &ymap, &cmax, &rmax)) /* don't draw if fully clipped */
510 return;
511
512 /* get back to screen */
513 xs = xmap - DRAW_XYMAP_SCRLEFT;
514 ys = ymap - DRAW_XYMAP_SCRTOP;
515 xmap >>= 3;
516 ymap >>= 3;
517 cmax >>= 3;
518 rmax >>= 3;
519
520 /* draw */
521 for (r = 0; r < rmax; r++) { /* for each row */
522#ifdef GFXPC
523 draw_setfb(xs, ys + r * 8);
524#endif
525#ifdef GFXST
526 draw_setfb(xs, 8 + ys + r * 8);
527#endif
528 for (c = 0; c < cmax; c++) { /* for each column */
529 draw_tile(map_map[ymap + r][xmap + c]);
530 }
531 }
532}
533
534
535/*
536 * Draw entire map screen background tiles onto frame buffer.
537 *
538 * ASM 0af5, 0a54
539 */
540void
541draw_map(void)
542{
543 U8 i, j;
544
545 draw_tilesBank = map_tilesBank;
546
547 for (i = 0; i < 0x18; i++) /* 0x18 rows */
548 {
549#ifdef GFXPC
550 draw_setfb(-DRAW_XYMAP_SCRLEFT, (i * 8));
551#endif
552#ifdef GFXST
553 draw_setfb(-DRAW_XYMAP_SCRLEFT, 8 + (i * 8));
554#endif
555 for (j = 0; j < 0x20; j++) /* 0x20 tiles per row */
556 {
557 draw_tile(map_map[i + 8][j]);
558 }
559 }
560}
561
562
563/*
564 * Draw status indicators
565 *
566 * ASM 0309
567 */
568void
569draw_drawStatus(void)
570{
571 S8 i;
572 U32 sv;
573 static U8 s[7] = {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfe};
574
575 draw_tilesBank = 0;
576
577 for (i = 5, sv = game_score; i >= 0; i--) {
578 s[i] = 0x30 + (U8)(sv % 10);
579 sv /= 10;
580 }
581 draw_tllst = s;
582
583 draw_setfb(DRAW_STATUS_SCORE_X, DRAW_STATUS_Y);
584 draw_tilesList();
585
586 draw_setfb(DRAW_STATUS_BULLETS_X, DRAW_STATUS_Y);
587 for (i = 0; i < game_bullets; i++)
588 draw_tile(TILES_BULLET);
589
590 draw_setfb(DRAW_STATUS_BOMBS_X, DRAW_STATUS_Y);
591 for (i = 0; i < game_bombs; i++)
592 draw_tile(TILES_BOMB);
593
594 draw_setfb(DRAW_STATUS_LIVES_X, DRAW_STATUS_Y);
595 for (i = 0; i < game_lives; i++)
596 draw_tile(TILES_RICK);
597}
598
599
600/*
601 * Draw info indicators
602 */
603#ifdef ENABLE_CHEATS
604void
605draw_infos(void)
606{
607 draw_tilesBank = 0;
608
609#ifdef GFXPC
610 draw_filter = 0xffff;
611#endif
612
613 draw_setfb(0x00, DRAW_STATUS_Y);
614 draw_tile(game_cheat1 ? 'T' : '@');
615 draw_setfb(0x08, DRAW_STATUS_Y);
616 draw_tile(game_cheat2 ? 'N' : '@');
617 draw_setfb(0x10, DRAW_STATUS_Y);
618 draw_tile(game_cheat3 ? 'V' : '@');
619}
620#endif
621
622
623/*
624 * Clear status indicators
625 */
626void
627draw_clearStatus(void)
628{
629 U8 i;
630
631#ifdef GFXPC
632 draw_tilesBank = map_tilesBank;
633#endif
634#ifdef GFXST
635 draw_tilesBank = 0;
636#endif
637 draw_setfb(DRAW_STATUS_SCORE_X, DRAW_STATUS_Y);
638 for (i = 0; i < DRAW_STATUS_LIVES_X/8 + 6 - DRAW_STATUS_SCORE_X/8; i++) {
639#ifdef GFXPC
640 draw_tile(map_map[MAP_ROW_SCRTOP + (DRAW_STATUS_Y / 8)][i]);
641#endif
642#ifdef GFXST
643 draw_tile('@');
644#endif
645 }
646}
647
648/*
649 * Draw a picture
650 */
651#ifdef GFXST
652void
653draw_pic(const pic_t * picture)
654{
655 U8 *f;
656 U16 i, j, k, pp;
657 U32 v;
658
659 draw_setfb(picture->xPos, picture->yPos);
660 pp = 0;
661
662 for (i = 0; i < picture->height; i++) { /* rows */
663 f = fb;
664 for (j = 0; j < picture->width; j += 8) { /* cols */
665 v = picture->pixels[pp++];
666 for (k = 8; k--; v >>= 4)
667 f[k] = v & 0x0F;
668 f += 8;
669 }
670 fb += SYSVID_WIDTH;
671 }
672}
673#endif
674
675
676/*
677 * Draw a bitmap
678 */
679void
680draw_img(img_t *image)
681{
682 U8 *f;
683 U16 i, j, pp;
684
685 sysvid_setPalette(image->colors, image->ncolors);
686
687 draw_setfb(image->xPos, image->yPos);
688 pp = 0;
689
690 for (i = 0; i < image->height; i++) /* rows */
691 {
692 f = fb;
693 for (j = 0; j < image->width; j++) /* cols */
694 {
695 f[j] = image->pixels[pp++];
696 }
697 fb += SYSVID_WIDTH;
698 }
699}
700
701
702/* eof */