A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 702 lines 16 kB view raw
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 */