diff options
| -rw-r--r-- | src/isogfx.c | 78 |
1 files changed, 41 insertions, 37 deletions
diff --git a/src/isogfx.c b/src/isogfx.c index b715ca8..e182dff 100644 --- a/src/isogfx.c +++ b/src/isogfx.c | |||
| @@ -32,7 +32,11 @@ typedef struct vec2 { | |||
| 32 | // Renderer state. | 32 | // Renderer state. |
| 33 | // ----------------------------------------------------------------------------- | 33 | // ----------------------------------------------------------------------------- |
| 34 | 34 | ||
| 35 | // TODO: Define a struct Screen with width, height and pixels. | 35 | typedef struct Screen { |
| 36 | int width; | ||
| 37 | int height; | ||
| 38 | Pixel* pixels; | ||
| 39 | } Screen; | ||
| 36 | 40 | ||
| 37 | typedef struct SpriteInstance { | 41 | typedef struct SpriteInstance { |
| 38 | struct SpriteInstance* next; | 42 | struct SpriteInstance* next; |
| @@ -43,11 +47,9 @@ typedef struct SpriteInstance { | |||
| 43 | } SpriteInstance; | 47 | } SpriteInstance; |
| 44 | 48 | ||
| 45 | typedef struct IsoGfx { | 49 | typedef struct IsoGfx { |
| 46 | int screen_width; | 50 | Screen screen; |
| 47 | int screen_height; | ||
| 48 | double last_animation_time; | 51 | double last_animation_time; |
| 49 | Tile next_tile; // For procedurally-generated tiles. | 52 | Tile next_tile; // For procedurally-generated tiles. |
| 50 | Pixel* screen; | ||
| 51 | Tm_Map* map; | 53 | Tm_Map* map; |
| 52 | Ts_TileSet* tileset; | 54 | Ts_TileSet* tileset; |
| 53 | SpriteInstance* head_sprite; // Head of sprites list. | 55 | SpriteInstance* head_sprite; // Head of sprites list. |
| @@ -90,21 +92,21 @@ static inline vec2 cart2iso(vec2 cart, int s, int t, int w) { | |||
| 90 | } | 92 | } |
| 91 | 93 | ||
| 92 | static inline const Pixel* screen_xy_const_ref( | 94 | static inline const Pixel* screen_xy_const_ref( |
| 93 | const IsoGfx* iso, int x, int y) { | 95 | const Screen* screen, int x, int y) { |
| 94 | assert(iso); | 96 | assert(screen); |
| 95 | assert(x >= 0); | 97 | assert(x >= 0); |
| 96 | assert(y >= 0); | 98 | assert(y >= 0); |
| 97 | assert(x < iso->screen_width); | 99 | assert(x < screen->width); |
| 98 | assert(y < iso->screen_height); | 100 | assert(y < screen->height); |
| 99 | return &iso->screen[y * iso->screen_width + x]; | 101 | return &screen->pixels[y * screen->width + x]; |
| 100 | } | 102 | } |
| 101 | 103 | ||
| 102 | static inline Pixel screen_xy(IsoGfx* iso, int x, int y) { | 104 | static inline Pixel screen_xy(Screen* screen, int x, int y) { |
| 103 | return *screen_xy_const_ref(iso, x, y); | 105 | return *screen_xy_const_ref(screen, x, y); |
| 104 | } | 106 | } |
| 105 | 107 | ||
| 106 | static inline Pixel* screen_xy_mut(IsoGfx* iso, int x, int y) { | 108 | static inline Pixel* screen_xy_mut(Screen* screen, int x, int y) { |
| 107 | return (Pixel*)screen_xy_const_ref(iso, x, y); | 109 | return (Pixel*)screen_xy_const_ref(screen, x, y); |
| 108 | } | 110 | } |
| 109 | 111 | ||
| 110 | // ----------------------------------------------------------------------------- | 112 | // ----------------------------------------------------------------------------- |
| @@ -126,16 +128,17 @@ IsoGfx* isogfx_new(const IsoGfxDesc* desc) { | |||
| 126 | memstack_alloc_aligned(&tmp.stack, sizeof(IsoGfx), alignof(IsoGfx)); | 128 | memstack_alloc_aligned(&tmp.stack, sizeof(IsoGfx), alignof(IsoGfx)); |
| 127 | *iso = tmp; | 129 | *iso = tmp; |
| 128 | 130 | ||
| 129 | iso->screen_width = desc->screen_width; | ||
| 130 | iso->screen_height = desc->screen_height; | ||
| 131 | iso->last_animation_time = 0.0; | ||
| 132 | |||
| 133 | const size_t screen_size_bytes = | 131 | const size_t screen_size_bytes = |
| 134 | desc->screen_width * desc->screen_height * sizeof(Pixel); | 132 | desc->screen_width * desc->screen_height * sizeof(Pixel); |
| 135 | iso->screen = | 133 | Pixel* screen = |
| 136 | memstack_alloc_aligned(&iso->stack, screen_size_bytes, alignof(Pixel)); | 134 | memstack_alloc_aligned(&iso->stack, screen_size_bytes, alignof(Pixel)); |
| 137 | 135 | ||
| 138 | iso->watermark = memstack_watermark(&iso->stack); | 136 | iso->screen = (Screen){.width = desc->screen_width, |
| 137 | .height = desc->screen_height, | ||
| 138 | .pixels = screen}; | ||
| 139 | |||
| 140 | iso->last_animation_time = 0.0; | ||
| 141 | iso->watermark = memstack_watermark(&iso->stack); | ||
| 139 | 142 | ||
| 140 | return iso; | 143 | return iso; |
| 141 | 144 | ||
| @@ -469,7 +472,7 @@ typedef struct CoordSystem { | |||
| 469 | /// expressed in the Cartesian system. | 472 | /// expressed in the Cartesian system. |
| 470 | static CoordSystem make_iso_coord_system(const IsoGfx* iso) { | 473 | static CoordSystem make_iso_coord_system(const IsoGfx* iso) { |
| 471 | assert(iso); | 474 | assert(iso); |
| 472 | const ivec2 o = {iso->screen_width / 2, 0}; | 475 | const ivec2 o = {iso->screen.width / 2, 0}; |
| 473 | const ivec2 x = { | 476 | const ivec2 x = { |
| 474 | .x = iso->map->base_tile_width / 2, .y = iso->map->base_tile_height / 2}; | 477 | .x = iso->map->base_tile_width / 2, .y = iso->map->base_tile_height / 2}; |
| 475 | const ivec2 y = { | 478 | const ivec2 y = { |
| @@ -517,9 +520,9 @@ static Pixel alpha_blend(Pixel src, Pixel dst) { | |||
| 517 | /// 'pixels' is the palette and 'indices' the pixel indices. Otherwise, the | 520 | /// 'pixels' is the palette and 'indices' the pixel indices. Otherwise, the |
| 518 | /// image is assumed to be in plain RGBA format. | 521 | /// image is assumed to be in plain RGBA format. |
| 519 | static void draw_rect( | 522 | static void draw_rect( |
| 520 | IsoGfx* iso, ivec2 top_left, int rect_width, int rect_height, | 523 | Screen* screen, ivec2 top_left, int rect_width, int rect_height, |
| 521 | const Pixel* pixels, const uint8_t* indices) { | 524 | const Pixel* pixels, const uint8_t* indices) { |
| 522 | assert(iso); | 525 | assert(screen); |
| 523 | 526 | ||
| 524 | #define rect_pixel(X, Y) \ | 527 | #define rect_pixel(X, Y) \ |
| 525 | (indices ? pixels[indices[Y * rect_width + X]] : pixels[Y * rect_width + X]) | 528 | (indices ? pixels[indices[Y * rect_width + X]] : pixels[Y * rect_width + X]) |
| @@ -532,16 +535,16 @@ static void draw_rect( | |||
| 532 | 535 | ||
| 533 | // Rect can exceed screen bounds, so clip along Y and X as we draw. | 536 | // Rect can exceed screen bounds, so clip along Y and X as we draw. |
| 534 | for (int py = py_offset; | 537 | for (int py = py_offset; |
| 535 | (py < rect_height) && (top_left.y + py < iso->screen_height); ++py) { | 538 | (py < rect_height) && (top_left.y + py < screen->height); ++py) { |
| 536 | const int sy = top_left.y + py; | 539 | const int sy = top_left.y + py; |
| 537 | for (int px = px_offset; | 540 | for (int px = px_offset; |
| 538 | (px < rect_width) && (top_left.x + px < iso->screen_width); ++px) { | 541 | (px < rect_width) && (top_left.x + px < screen->width); ++px) { |
| 539 | const Pixel colour = rect_pixel(px, py); | 542 | const Pixel colour = rect_pixel(px, py); |
| 540 | if (colour.a > 0) { | 543 | if (colour.a > 0) { |
| 541 | const int sx = top_left.x + px; | 544 | const int sx = top_left.x + px; |
| 542 | const Pixel dst = screen_xy(iso, sx, sy); | 545 | const Pixel dst = screen_xy(screen, sx, sy); |
| 543 | const Pixel final = alpha_blend(colour, dst); | 546 | const Pixel final = alpha_blend(colour, dst); |
| 544 | *screen_xy_mut(iso, sx, sy) = final; | 547 | *screen_xy_mut(screen, sx, sy) = final; |
| 545 | } | 548 | } |
| 546 | } | 549 | } |
| 547 | } | 550 | } |
| @@ -567,16 +570,17 @@ static void draw_tile(IsoGfx* iso, ivec2 screen_origin, Tile tile) { | |||
| 567 | pTile->height - iso->map->base_tile_height}; | 570 | pTile->height - iso->map->base_tile_height}; |
| 568 | const ivec2 top_left = ivec2_add(screen_origin, offset); | 571 | const ivec2 top_left = ivec2_add(screen_origin, offset); |
| 569 | 572 | ||
| 570 | draw_rect(iso, top_left, pTile->width, pTile->height, pixels, 0); | 573 | draw_rect( |
| 574 | &iso->screen, top_left, pTile->width, pTile->height, pixels, nullptr); | ||
| 571 | } | 575 | } |
| 572 | 576 | ||
| 573 | static void draw_world(IsoGfx* iso) { | 577 | static void draw_world(IsoGfx* iso) { |
| 574 | assert(iso); | 578 | assert(iso); |
| 575 | 579 | ||
| 576 | const int W = iso->screen_width; | 580 | const int W = iso->screen.width; |
| 577 | const int H = iso->screen_height; | 581 | const int H = iso->screen.height; |
| 578 | 582 | ||
| 579 | memset(iso->screen, 0, W * H * sizeof(Pixel)); | 583 | memset(iso->screen.pixels, 0, W * H * sizeof(Pixel)); |
| 580 | 584 | ||
| 581 | const CoordSystem iso_space = make_iso_coord_system(iso); | 585 | const CoordSystem iso_space = make_iso_coord_system(iso); |
| 582 | 586 | ||
| @@ -609,7 +613,7 @@ static void draw_sprite( | |||
| 609 | const Ss_Row* row = ss_get_sprite_sheet_row(sheet, sprite->animation); | 613 | const Ss_Row* row = ss_get_sprite_sheet_row(sheet, sprite->animation); |
| 610 | const uint8_t* frame = ss_get_sprite_sheet_sprite(sheet, row, sprite->frame); | 614 | const uint8_t* frame = ss_get_sprite_sheet_sprite(sheet, row, sprite->frame); |
| 611 | draw_rect( | 615 | draw_rect( |
| 612 | iso, origin, sheet->sprite_width, sheet->sprite_height, | 616 | &iso->screen, origin, sheet->sprite_width, sheet->sprite_height, |
| 613 | sheet->palette.colours, frame); | 617 | sheet->palette.colours, frame); |
| 614 | } | 618 | } |
| 615 | 619 | ||
| @@ -651,13 +655,13 @@ void isogfx_get_screen_size(const IsoGfx* iso, int* width, int* height) { | |||
| 651 | assert(iso); | 655 | assert(iso); |
| 652 | assert(width); | 656 | assert(width); |
| 653 | assert(height); | 657 | assert(height); |
| 654 | *width = iso->screen_width; | 658 | *width = iso->screen.width; |
| 655 | *height = iso->screen_height; | 659 | *height = iso->screen.height; |
| 656 | } | 660 | } |
| 657 | 661 | ||
| 658 | const Pixel* isogfx_get_screen_buffer(const IsoGfx* iso) { | 662 | const Pixel* isogfx_get_screen_buffer(const IsoGfx* iso) { |
| 659 | assert(iso); | 663 | assert(iso); |
| 660 | return iso->screen; | 664 | return iso->screen.pixels; |
| 661 | } | 665 | } |
| 662 | 666 | ||
| 663 | void isogfx_pick_tile( | 667 | void isogfx_pick_tile( |
| @@ -668,7 +672,7 @@ void isogfx_pick_tile( | |||
| 668 | 672 | ||
| 669 | const vec2 xy_iso = cart2iso( | 673 | const vec2 xy_iso = cart2iso( |
| 670 | (vec2){.x = xcart, .y = ycart}, iso->map->base_tile_width, | 674 | (vec2){.x = xcart, .y = ycart}, iso->map->base_tile_width, |
| 671 | iso->map->base_tile_height, iso->screen_width); | 675 | iso->map->base_tile_height, iso->screen.width); |
| 672 | 676 | ||
| 673 | if ((0 <= xy_iso.x) && (xy_iso.x < iso->map->world_width) && | 677 | if ((0 <= xy_iso.x) && (xy_iso.x < iso->map->world_width) && |
| 674 | (0 <= xy_iso.y) && (xy_iso.y < iso->map->world_height)) { | 678 | (0 <= xy_iso.y) && (xy_iso.y < iso->map->world_height)) { |
