diff options
author | 3gg <3gg@shellblade.net> | 2025-09-02 19:53:28 -0700 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2025-09-02 19:53:28 -0700 |
commit | eca9315556ab4e9c813180de5f33c1e0b8bbb9c3 (patch) | |
tree | ef5a1ad9102571ca08a1b4c6424b016d3c54fb00 | |
parent | bab4a8169135dfecb2e434cca6825dcb96e1b9ec (diff) |
-rw-r--r-- | demos/isomap/isomap.c | 2 | ||||
-rw-r--r-- | src/gfx2d.c | 94 |
2 files changed, 52 insertions, 44 deletions
diff --git a/demos/isomap/isomap.c b/demos/isomap/isomap.c index b9b6568..bca27f6 100644 --- a/demos/isomap/isomap.c +++ b/demos/isomap/isomap.c | |||
@@ -59,7 +59,7 @@ static bool init(GfxApp* app, GfxAppState* state, int argc, const char** argv) { | |||
59 | } | 59 | } |
60 | 60 | ||
61 | state->stag = isogfx_make_sprite(iso, state->stag_sheet); | 61 | state->stag = isogfx_make_sprite(iso, state->stag_sheet); |
62 | isogfx_set_sprite_position(iso, state->stag, 5, 4); | 62 | isogfx_set_sprite_position(iso, state->stag, 0, 0); |
63 | 63 | ||
64 | if (!((state->backend = iso_backend_init(iso)))) { | 64 | if (!((state->backend = iso_backend_init(iso)))) { |
65 | return false; | 65 | return false; |
diff --git a/src/gfx2d.c b/src/gfx2d.c index da265b0..9767308 100644 --- a/src/gfx2d.c +++ b/src/gfx2d.c | |||
@@ -79,17 +79,49 @@ static inline ivec2 ivec2_scale(ivec2 a, int s) { | |||
79 | 79 | ||
80 | static inline ivec2 ivec2_neg(ivec2 a) { return (ivec2){.x = -a.x, .y = -a.y}; } | 80 | static inline ivec2 ivec2_neg(ivec2 a) { return (ivec2){.x = -a.x, .y = -a.y}; } |
81 | 81 | ||
82 | static inline ivec2 iso2cart(ivec2 iso, int s, int t, int w) { | ||
83 | return (ivec2){.x = (iso.x - iso.y) * (s / 2) + (w / 2), | ||
84 | .y = (iso.x + iso.y) * (t / 2)}; | ||
85 | } | ||
86 | |||
87 | static inline vec2 vec2_add(vec2 a, vec2 b) { | 82 | static inline vec2 vec2_add(vec2 a, vec2 b) { |
88 | return (vec2){.x = a.x + b.x, .y = a.y + b.y}; | 83 | return (vec2){.x = a.x + b.x, .y = a.y + b.y}; |
89 | } | 84 | } |
90 | 85 | ||
91 | static inline vec2 ivec2_to_vec2(ivec2 a) { return (vec2){a.x, a.y}; } | 86 | static inline vec2 ivec2_to_vec2(ivec2 a) { return (vec2){a.x, a.y}; } |
92 | 87 | ||
88 | // Not actually used because we pre-compute the two axis vectors instead. | ||
89 | // See make_iso_coord_system() and the other definition of iso2cart() below. | ||
90 | // static inline ivec2 iso2cart(ivec2 iso, int s, int t, int w) { | ||
91 | // return (ivec2){.x = (iso.x - iso.y) * (s / 2) + (w / 2), | ||
92 | // .y = (iso.x + iso.y) * (t / 2)}; | ||
93 | // } | ||
94 | |||
95 | /// Create the basis for the isometric coordinate system with origin and vectors | ||
96 | /// expressed in the Cartesian system. | ||
97 | static CoordSystem make_iso_coord_system( | ||
98 | const Tm_Map* const map, const Screen* const screen) { | ||
99 | assert(map); | ||
100 | assert(screen); | ||
101 | const ivec2 o = {screen->width / 2, 0}; | ||
102 | const ivec2 x = { | ||
103 | .x = map->base_tile_width / 2, .y = map->base_tile_height / 2}; | ||
104 | const ivec2 y = { | ||
105 | .x = -map->base_tile_width / 2, .y = map->base_tile_height / 2}; | ||
106 | return (CoordSystem){o, x, y}; | ||
107 | } | ||
108 | |||
109 | /// Map isometric coordinates to Cartesian coordinates. | ||
110 | /// | ||
111 | /// For a tile, this gets the screen position of the top diamond-corner of the | ||
112 | /// tile. | ||
113 | /// | ||
114 | /// Takes the camera displacement into account. | ||
115 | static ivec2 iso2cart( | ||
116 | const CoordSystem iso_space, ivec2 camera, int iso_x, int iso_y) { | ||
117 | const ivec2 vx_offset = ivec2_scale(iso_space.x, iso_x); | ||
118 | const ivec2 vy_offset = ivec2_scale(iso_space.y, iso_y); | ||
119 | const ivec2 screen_origin = | ||
120 | ivec2_add(iso_space.o, ivec2_add(vx_offset, vy_offset)); | ||
121 | const ivec2 origin_view_space = ivec2_add(screen_origin, ivec2_neg(camera)); | ||
122 | return origin_view_space; | ||
123 | } | ||
124 | |||
93 | // Method 1. | 125 | // Method 1. |
94 | // static inline vec2 cart2iso(vec2 cart, int s, int t, int w) { | 126 | // static inline vec2 cart2iso(vec2 cart, int s, int t, int w) { |
95 | // const double x = cart.x - (double)(w / 2); | 127 | // const double x = cart.x - (double)(w / 2); |
@@ -125,20 +157,6 @@ static inline Pixel* screen_xy_mut(Screen* screen, int x, int y) { | |||
125 | return (Pixel*)screen_xy_const_ref(screen, x, y); | 157 | return (Pixel*)screen_xy_const_ref(screen, x, y); |
126 | } | 158 | } |
127 | 159 | ||
128 | /// Create the basis for the isometric coordinate system with origin and vectors | ||
129 | /// expressed in the Cartesian system. | ||
130 | static CoordSystem make_iso_coord_system( | ||
131 | const Tm_Map* const map, const Screen* const screen) { | ||
132 | assert(map); | ||
133 | assert(screen); | ||
134 | const ivec2 o = {screen->width / 2, 0}; | ||
135 | const ivec2 x = { | ||
136 | .x = map->base_tile_width / 2, .y = map->base_tile_height / 2}; | ||
137 | const ivec2 y = { | ||
138 | .x = -map->base_tile_width / 2, .y = map->base_tile_height / 2}; | ||
139 | return (CoordSystem){o, x, y}; | ||
140 | } | ||
141 | |||
142 | // ----------------------------------------------------------------------------- | 160 | // ----------------------------------------------------------------------------- |
143 | // Renderer, world and tile management. | 161 | // Renderer, world and tile management. |
144 | // ----------------------------------------------------------------------------- | 162 | // ----------------------------------------------------------------------------- |
@@ -498,18 +516,6 @@ void isogfx_update(IsoGfx* iso, double t) { | |||
498 | // Rendering and picking. | 516 | // Rendering and picking. |
499 | // ----------------------------------------------------------------------------- | 517 | // ----------------------------------------------------------------------------- |
500 | 518 | ||
501 | /// Get the screen position of the top diamond-corner of the tile at world | ||
502 | /// (x,y). | ||
503 | static ivec2 GetTileScreenOrigin( | ||
504 | const CoordSystem iso_space, ivec2 camera, int world_x, int world_y) { | ||
505 | const ivec2 vx_offset = ivec2_scale(iso_space.x, world_x); | ||
506 | const ivec2 vy_offset = ivec2_scale(iso_space.y, world_y); | ||
507 | const ivec2 screen_origin = | ||
508 | ivec2_add(iso_space.o, ivec2_add(vx_offset, vy_offset)); | ||
509 | const ivec2 origin_view_space = ivec2_add(screen_origin, ivec2_neg(camera)); | ||
510 | return origin_view_space; | ||
511 | } | ||
512 | |||
513 | static Pixel alpha_blend(Pixel src, Pixel dst) { | 519 | static Pixel alpha_blend(Pixel src, Pixel dst) { |
514 | if ((src.a == 255) || (dst.a == 0)) { | 520 | if ((src.a == 255) || (dst.a == 0)) { |
515 | return src; | 521 | return src; |
@@ -609,17 +615,15 @@ static void draw_map(IsoGfx* iso) { | |||
609 | // screen-centric approach would juggle multiple tiles throughout the scan. | 615 | // screen-centric approach would juggle multiple tiles throughout the scan. |
610 | for (int wy = 0; wy < iso->map->world_height; ++wy) { | 616 | for (int wy = 0; wy < iso->map->world_height; ++wy) { |
611 | for (int wx = 0; wx < iso->map->world_width; ++wx) { | 617 | for (int wx = 0; wx < iso->map->world_width; ++wx) { |
612 | const Tile tile = tm_layer_get_tile(iso->map, layer, wx, wy); | 618 | const Tile tile = tm_layer_get_tile(iso->map, layer, wx, wy); |
613 | const ivec2 screen_origin = | 619 | const ivec2 screen_origin = iso2cart(iso->iso_space, iso->camera, wx, wy); |
614 | GetTileScreenOrigin(iso->iso_space, iso->camera, wx, wy); | ||
615 | draw_tile(iso, screen_origin, tile); | 620 | draw_tile(iso, screen_origin, tile); |
616 | } | 621 | } |
617 | } | 622 | } |
618 | } | 623 | } |
619 | 624 | ||
620 | static void draw_sprite( | 625 | static void draw_sprite( |
621 | IsoGfx* iso, ivec2 origin, const SpriteInstance* sprite, | 626 | IsoGfx* iso, const SpriteInstance* sprite, const Ss_SpriteSheet* sheet) { |
622 | const Ss_SpriteSheet* sheet) { | ||
623 | assert(iso); | 627 | assert(iso); |
624 | assert(sprite); | 628 | assert(sprite); |
625 | assert(sheet); | 629 | assert(sheet); |
@@ -627,10 +631,18 @@ static void draw_sprite( | |||
627 | assert(sprite->animation < sheet->num_rows); | 631 | assert(sprite->animation < sheet->num_rows); |
628 | assert(sprite->frame >= 0); | 632 | assert(sprite->frame >= 0); |
629 | 633 | ||
634 | // Apply an offset similarly to how we offset tiles. The sprite is offset by | ||
635 | // -base_tile_width/2 along the x-axis to align the sprite with the leftmost | ||
636 | // edge of the tile it is on. | ||
637 | const ivec2 screen_origin = iso2cart( | ||
638 | iso->iso_space, iso->camera, sprite->position.x, sprite->position.y); | ||
639 | const ivec2 offset = {-(iso->map->base_tile_width / 2), 0}; | ||
640 | const ivec2 top_left = ivec2_add(screen_origin, offset); | ||
641 | |||
630 | const Ss_Row* row = ss_get_sprite_sheet_row(sheet, sprite->animation); | 642 | const Ss_Row* row = ss_get_sprite_sheet_row(sheet, sprite->animation); |
631 | const uint8_t* frame = ss_get_sprite_sheet_sprite(sheet, row, sprite->frame); | 643 | const uint8_t* frame = ss_get_sprite_sheet_sprite(sheet, row, sprite->frame); |
632 | draw_rect( | 644 | draw_rect( |
633 | &iso->screen, origin, sheet->sprite_width, sheet->sprite_height, | 645 | &iso->screen, top_left, sheet->sprite_width, sheet->sprite_height, |
634 | sheet->palette.colours, frame); | 646 | sheet->palette.colours, frame); |
635 | } | 647 | } |
636 | 648 | ||
@@ -641,10 +653,7 @@ static void draw_sprites(IsoGfx* iso) { | |||
641 | sprite = sprite->next) { | 653 | sprite = sprite->next) { |
642 | const Ss_SpriteSheet* sheet = sprite->sheet; | 654 | const Ss_SpriteSheet* sheet = sprite->sheet; |
643 | assert(sheet); | 655 | assert(sheet); |
644 | 656 | draw_sprite(iso, sprite, sheet); | |
645 | const ivec2 screen_origin = GetTileScreenOrigin( | ||
646 | iso->iso_space, iso->camera, sprite->position.x, sprite->position.y); | ||
647 | draw_sprite(iso, screen_origin, sprite, sheet); | ||
648 | } | 657 | } |
649 | } | 658 | } |
650 | 659 | ||
@@ -666,8 +675,7 @@ void isogfx_draw_tile(IsoGfx* iso, int x, int y, Tile tile) { | |||
666 | assert(x < iso->map->world_width); | 675 | assert(x < iso->map->world_width); |
667 | assert(y < iso->map->world_height); | 676 | assert(y < iso->map->world_height); |
668 | 677 | ||
669 | const ivec2 screen_origin = | 678 | const ivec2 screen_origin = iso2cart(iso->iso_space, iso->camera, x, y); |
670 | GetTileScreenOrigin(iso->iso_space, iso->camera, x, y); | ||
671 | draw_tile(iso, screen_origin, tile); | 679 | draw_tile(iso, screen_origin, tile); |
672 | } | 680 | } |
673 | 681 | ||