summaryrefslogtreecommitdiff
path: root/gfx-iso/src/isogfx.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2024-08-29 20:12:19 -0700
committer3gg <3gg@shellblade.net>2024-08-29 20:12:19 -0700
commit8bfa0c652cfb36ca0dfe10a1d35c7b6199e064ba (patch)
treec2e22565590aabb123eb43d87e69aa9758a0c4dc /gfx-iso/src/isogfx.c
parent7a59d85dfead20dc34081badad6c8940e7190001 (diff)
More consistent changing of coordinates.
Diffstat (limited to 'gfx-iso/src/isogfx.c')
-rw-r--r--gfx-iso/src/isogfx.c103
1 files changed, 58 insertions, 45 deletions
diff --git a/gfx-iso/src/isogfx.c b/gfx-iso/src/isogfx.c
index 5c1c2d1..f7d0fa9 100644
--- a/gfx-iso/src/isogfx.c
+++ b/gfx-iso/src/isogfx.c
@@ -237,9 +237,9 @@ static const Pixel* tile_xy_const_ref(
237 return &mem_get_chunk(&iso->pixels, tile->pixels_handle)[y * tile->width + x]; 237 return &mem_get_chunk(&iso->pixels, tile->pixels_handle)[y * tile->width + x];
238} 238}
239 239
240static Pixel tile_xy(const IsoGfx* iso, const TileData* tile, int x, int y) { 240// static Pixel tile_xy(const IsoGfx* iso, const TileData* tile, int x, int y) {
241 return *tile_xy_const_ref(iso, tile, x, y); 241// return *tile_xy_const_ref(iso, tile, x, y);
242} 242// }
243 243
244static Pixel* tile_xy_mut(const IsoGfx* iso, TileData* tile, int x, int y) { 244static Pixel* tile_xy_mut(const IsoGfx* iso, TileData* tile, int x, int y) {
245 return (Pixel*)tile_xy_const_ref(iso, tile, x, y); 245 return (Pixel*)tile_xy_const_ref(iso, tile, x, y);
@@ -444,7 +444,7 @@ bool isogfx_load_world(IsoGfx* iso, const char* filepath) {
444 // Tile set path is relative to the tile map file. Make it relative to the 444 // Tile set path is relative to the tile map file. Make it relative to the
445 // current working directory before loading. 445 // current working directory before loading.
446 char ts_path_cwd[PATH_MAX] = {0}; 446 char ts_path_cwd[PATH_MAX] = {0};
447 if (!make_relative_path(filepath, ts_path, ts_path_cwd, PATH_MAX)) { 447 if (!path_make_relative(filepath, ts_path, ts_path_cwd, PATH_MAX)) {
448 goto cleanup; 448 goto cleanup;
449 } 449 }
450 450
@@ -724,14 +724,24 @@ typedef struct CoordSystem {
724/// expressed in the Cartesian system. 724/// expressed in the Cartesian system.
725static CoordSystem make_iso_coord_system(const IsoGfx* iso) { 725static CoordSystem make_iso_coord_system(const IsoGfx* iso) {
726 assert(iso); 726 assert(iso);
727 // const ivec2 o = {(iso->screen_width / 2) - (iso->tile_width / 2), 0}; 727 const ivec2 o = {iso->screen_width / 2, 0};
728 const ivec2 o = {
729 (iso->screen_width / 2) - (iso->tile_width / 2), iso->tile_height};
730 const ivec2 x = {.x = iso->tile_width / 2, .y = iso->tile_height / 2}; 728 const ivec2 x = {.x = iso->tile_width / 2, .y = iso->tile_height / 2};
731 const ivec2 y = {.x = -iso->tile_width / 2, .y = iso->tile_height / 2}; 729 const ivec2 y = {.x = -iso->tile_width / 2, .y = iso->tile_height / 2};
732 return (CoordSystem){o, x, y}; 730 return (CoordSystem){o, x, y};
733} 731}
734 732
733/// Get the screen position of the top diamond-corner of the tile at world
734/// (x,y).
735static ivec2 GetTileScreenOrigin(
736 const CoordSystem iso_space, int world_x, int world_y) {
737 const ivec2 vx_offset = ivec2_scale(iso_space.x, world_x);
738 const ivec2 vy_offset = ivec2_scale(iso_space.y, world_y);
739 const ivec2 screen_origin =
740 ivec2_add(iso_space.o, ivec2_add(vx_offset, vy_offset));
741
742 return screen_origin;
743}
744
735static Pixel alpha_blend(Pixel src, Pixel dst) { 745static Pixel alpha_blend(Pixel src, Pixel dst) {
736 if ((src.a == 255) || (dst.a == 0)) { 746 if ((src.a == 255) || (dst.a == 0)) {
737 return src; 747 return src;
@@ -761,7 +771,7 @@ static Pixel alpha_blend(Pixel src, Pixel dst) {
761/// 'pixels' is the palette and 'indices' the pixel indices. Otherwise, the 771/// 'pixels' is the palette and 'indices' the pixel indices. Otherwise, the
762/// image is assumed to be in plain RGBA format. 772/// image is assumed to be in plain RGBA format.
763static void draw_rect( 773static void draw_rect(
764 IsoGfx* iso, ivec2 origin, int rect_width, int rect_height, 774 IsoGfx* iso, ivec2 top_left, int rect_width, int rect_height,
765 const Pixel* pixels, const uint8_t* indices) { 775 const Pixel* pixels, const uint8_t* indices) {
766 assert(iso); 776 assert(iso);
767 777
@@ -769,20 +779,24 @@ static void draw_rect(
769 (indices ? pixels[indices[py * rect_width + px]] \ 779 (indices ? pixels[indices[py * rect_width + px]] \
770 : pixels[py * rect_width + px]) 780 : pixels[py * rect_width + px])
771 781
772 // Rect can exceed screen bounds, so we must clip it. 782 // Rect origin can be outside screen bounds, so we must offset accordingly to
783 // draw only the visible portion.
773#define max(a, b) (a > b ? a : b) 784#define max(a, b) (a > b ? a : b)
774 const int py_offset = max(0, rect_height - origin.y); 785 const int px_offset = max(0, -top_left.x);
775 origin.y = max(0, origin.y - rect_height); 786 const int py_offset = max(0, -top_left.y);
787 // Adjust top-left to be inside bounds.
788 top_left.x = max(0, top_left.x);
789 top_left.y = max(0, top_left.y);
776 790
777 // Clip along Y and X as we draw. 791 // Rect can exceed screen bounds, so clip along Y and X as we draw.
778 for (int py = py_offset; 792 for (int py = py_offset;
779 (py < rect_height) && (origin.y + py < iso->screen_height); ++py) { 793 (py < rect_height) && (top_left.y + py < iso->screen_height); ++py) {
780 const int sy = origin.y + py - py_offset; 794 const int sy = top_left.y + py - py_offset;
781 for (int px = 0; (px < rect_width) && (origin.x + px < iso->screen_width); 795 for (int px = px_offset;
782 ++px) { 796 (px < rect_width) && (top_left.x + px < iso->screen_width); ++px) {
783 const Pixel colour = rect_pixel(px, py); 797 const Pixel colour = rect_pixel(px, py);
784 if (colour.a > 0) { 798 if (colour.a > 0) {
785 const int sx = origin.x + px; 799 const int sx = top_left.x + px;
786 const Pixel dst = screen_xy(iso, sx, sy); 800 const Pixel dst = screen_xy(iso, sx, sy);
787 const Pixel final = alpha_blend(colour, dst); 801 const Pixel final = alpha_blend(colour, dst);
788 *screen_xy_mut(iso, sx, sy) = final; 802 *screen_xy_mut(iso, sx, sy) = final;
@@ -791,18 +805,29 @@ static void draw_rect(
791 } 805 }
792} 806}
793 807
794static void draw_tile(IsoGfx* iso, ivec2 origin, Tile tile) { 808/// Draw a tile.
809///
810/// 'screen_origin' is the screen coordinates of the top diamond-corner of the
811/// tile (the base tile for super tiles).
812/// World (0, 0) -> (screen_width / 2, 0).
813static void draw_tile(IsoGfx* iso, ivec2 screen_origin, Tile tile) {
795 assert(iso); 814 assert(iso);
796 815
797 const TileData* tile_data = mempool_get_block(&iso->tiles, tile); 816 const TileData* tile_data = mempool_get_block(&iso->tiles, tile);
798 assert(tile_data); 817 assert(tile_data);
799
800 const Pixel* pixels = tile_xy_const_ref(iso, tile_data, 0, 0); 818 const Pixel* pixels = tile_xy_const_ref(iso, tile_data, 0, 0);
801 819
802 draw_rect(iso, origin, tile_data->width, tile_data->height, pixels, 0); 820 // Move from the top diamond-corner to the top-left corner of the tile image.
821 // For regular tiles, tile height == base tile height, so the y offset is 0.
822 // For super tiles, move as high up as the height of the tile.
823 const ivec2 offset = {
824 -(iso->tile_width / 2), tile_data->height - iso->tile_height};
825 const ivec2 top_left = ivec2_add(screen_origin, offset);
826
827 draw_rect(iso, top_left, tile_data->width, tile_data->height, pixels, 0);
803} 828}
804 829
805static void draw(IsoGfx* iso) { 830static void draw_world(IsoGfx* iso) {
806 assert(iso); 831 assert(iso);
807 832
808 const int W = iso->screen_width; 833 const int W = iso->screen_width;
@@ -817,14 +842,11 @@ static void draw(IsoGfx* iso) {
817 // Ex: walk in screen space and fetch the tile. 842 // Ex: walk in screen space and fetch the tile.
818 // The tile-centric approach might be more cache-friendly since the 843 // The tile-centric approach might be more cache-friendly since the
819 // screen-centric approach would juggle multiple tiles throughout the scan. 844 // screen-centric approach would juggle multiple tiles throughout the scan.
820 for (int ty = 0; ty < iso->world_height; ++ty) { 845 for (int wy = 0; wy < iso->world_height; ++wy) {
821 for (int tx = 0; tx < iso->world_width; ++tx) { 846 for (int wx = 0; wx < iso->world_width; ++wx) {
822 const Tile tile = world_xy(iso, tx, ty); 847 const Tile tile = world_xy(iso, wx, wy);
823 const ivec2 so = ivec2_add( 848 const ivec2 screen_origin = GetTileScreenOrigin(iso_space, wx, wy);
824 iso_space.o, 849 draw_tile(iso, screen_origin, tile);
825 ivec2_add(
826 ivec2_scale(iso_space.x, tx), ivec2_scale(iso_space.y, ty)));
827 draw_tile(iso, so, tile);
828 } 850 }
829 } 851 }
830} 852}
@@ -855,18 +877,15 @@ static void draw_sprites(IsoGfx* iso) {
855 const SpriteSheetData* sheet = mem_get_chunk(&iso->sheets, sprite->sheet); 877 const SpriteSheetData* sheet = mem_get_chunk(&iso->sheets, sprite->sheet);
856 assert(sheet); 878 assert(sheet);
857 879
858 const ivec2 so = ivec2_add( 880 const ivec2 screen_origin =
859 iso_space.o, ivec2_add( 881 GetTileScreenOrigin(iso_space, sprite->position.x, sprite->position.y);
860 ivec2_scale(iso_space.x, sprite->position.x), 882 draw_sprite(iso, screen_origin, sprite, sheet);
861 ivec2_scale(iso_space.y, sprite->position.y)));
862
863 draw_sprite(iso, so, sprite, sheet);
864 }); 883 });
865} 884}
866 885
867void isogfx_render(IsoGfx* iso) { 886void isogfx_render(IsoGfx* iso) {
868 assert(iso); 887 assert(iso);
869 draw(iso); 888 draw_world(iso);
870 draw_sprites(iso); 889 draw_sprites(iso);
871} 890}
872 891
@@ -877,15 +896,9 @@ void isogfx_draw_tile(IsoGfx* iso, int x, int y, Tile tile) {
877 assert(x < iso->world_width); 896 assert(x < iso->world_width);
878 assert(y < iso->world_height); 897 assert(y < iso->world_height);
879 898
880 // const ivec2 o = {(iso->screen_width / 2) - (iso->tile_width / 2), 0}; 899 const CoordSystem iso_space = make_iso_coord_system(iso);
881 const ivec2 o = { 900 const ivec2 screen_origin = GetTileScreenOrigin(iso_space, x, y);
882 (iso->screen_width / 2) - (iso->tile_width / 2), iso->tile_height}; 901 draw_tile(iso, screen_origin, tile);
883 const ivec2 vx = {.x = iso->tile_width / 2, .y = iso->tile_height / 2};
884 const ivec2 vy = {.x = -iso->tile_width / 2, .y = iso->tile_height / 2};
885 const ivec2 so =
886 ivec2_add(o, ivec2_add(ivec2_scale(vx, x), ivec2_scale(vy, y)));
887
888 draw_tile(iso, so, tile);
889} 902}
890 903
891bool isogfx_resize(IsoGfx* iso, int screen_width, int screen_height) { 904bool isogfx_resize(IsoGfx* iso, int screen_width, int screen_height) {