add basic autotiling

This commit is contained in:
Sven Balzer
2025-03-26 22:04:53 +01:00
parent db55a510a6
commit e129469b08
5 changed files with 581 additions and 451 deletions
+134 -24
View File
@@ -177,39 +177,55 @@ struct PerFrame {
Sint32 drag_start[2];
Sint32 mouse[2];
Sint32 map_width;
Uint32 flags;
};
static PerFrame per_frame = {};
typedef enum : Uint8 {
TILEKIND_ERROR = 0,
TILEKIND_NONE = 1,
TILEKIND_GRASS = 2,
TILEKIND_GROUND = 3,
TILEKIND_WATER = 4,
} TileKind;
#define TILE_CORNER_INFO(top_left, top_right, bottom_right, bottom_left) (((top_left) << 24) | ((top_right) << 16) | ((bottom_right) << 8) | bottom_left)
typedef struct {
Uint16 type;
const char *asset_path;
Uint32 corner_info;
} TileInfo;
static TileInfo tile_infos[] = {
{ 0x0001, "tiles/error.png" },
{ 0x0000, "tiles/empty.png" },
{ 0x0100, "tiles/grass_1.png" },
{ 0x0101, "tiles/grass_2.png" },
{ 0x0102, "tiles/grass_3.png" },
{ 0x0103, "tiles/grass_4.png" },
{ 0x0200, "tiles/ground_1.png" },
{ 0x0201, "tiles/ground_2.png" },
{ 0x0202, "tiles/ground_3.png" },
{ 0x0300, "tiles/water_1.png" },
{ 0x0301, "tiles/water_2.png" },
{ 0x0400, "tiles/grass_ground_1.png" },
{ 0x0401, "tiles/grass_ground_2.png" },
{ 0x0402, "tiles/grass_ground_3.png" },
{ 0x0410, "tiles/grass_ground_outer_corner.png" },
{ 0x0411, "tiles/grass_ground_outer_corner_2.png" },
{ 0x0420, "tiles/grass_ground_inner_corner.png" },
{ 0x0421, "tiles/grass_ground_inner_corner_2.png" },
{ 0x0422, "tiles/grass_ground_inner_corner_3.png" },
{ 0x0001, "tiles/error.png", TILE_CORNER_INFO(TILEKIND_ERROR, TILEKIND_ERROR, TILEKIND_ERROR, TILEKIND_ERROR ) },
{ 0x0000, "tiles/empty.png", TILE_CORNER_INFO(TILEKIND_NONE, TILEKIND_NONE, TILEKIND_NONE, TILEKIND_NONE ) },
{ 0x0100, "tiles/grass_1.png", TILE_CORNER_INFO(TILEKIND_GRASS, TILEKIND_GRASS, TILEKIND_GRASS, TILEKIND_GRASS ) },
{ 0x0101, "tiles/grass_2.png", TILE_CORNER_INFO(TILEKIND_GRASS, TILEKIND_GRASS, TILEKIND_GRASS, TILEKIND_GRASS ) },
{ 0x0102, "tiles/grass_3.png", TILE_CORNER_INFO(TILEKIND_GRASS, TILEKIND_GRASS, TILEKIND_GRASS, TILEKIND_GRASS ) },
{ 0x0103, "tiles/grass_4.png", TILE_CORNER_INFO(TILEKIND_GRASS, TILEKIND_GRASS, TILEKIND_GRASS, TILEKIND_GRASS ) },
{ 0x0200, "tiles/ground_1.png", TILE_CORNER_INFO(TILEKIND_GROUND, TILEKIND_GROUND, TILEKIND_GROUND, TILEKIND_GROUND ) },
{ 0x0201, "tiles/ground_2.png", TILE_CORNER_INFO(TILEKIND_GROUND, TILEKIND_GROUND, TILEKIND_GROUND, TILEKIND_GROUND ) },
{ 0x0202, "tiles/ground_3.png", TILE_CORNER_INFO(TILEKIND_GROUND, TILEKIND_GROUND, TILEKIND_GROUND, TILEKIND_GROUND ) },
{ 0x0300, "tiles/water_1.png", TILE_CORNER_INFO(TILEKIND_WATER, TILEKIND_WATER, TILEKIND_WATER, TILEKIND_WATER ) },
{ 0x0301, "tiles/water_2.png", TILE_CORNER_INFO(TILEKIND_WATER, TILEKIND_WATER, TILEKIND_WATER, TILEKIND_WATER ) },
{ 0x0400, "tiles/grass_ground_1.png", TILE_CORNER_INFO(TILEKIND_GROUND, TILEKIND_GROUND, TILEKIND_GRASS, TILEKIND_GRASS ) },
{ 0x0401, "tiles/grass_ground_2.png", TILE_CORNER_INFO(TILEKIND_GROUND, TILEKIND_GROUND, TILEKIND_GRASS, TILEKIND_GRASS ) },
{ 0x0402, "tiles/grass_ground_3.png", TILE_CORNER_INFO(TILEKIND_GROUND, TILEKIND_GROUND, TILEKIND_GRASS, TILEKIND_GRASS ) },
{ 0x0410, "tiles/grass_ground_outer_corner.png", TILE_CORNER_INFO(TILEKIND_GROUND, TILEKIND_GROUND, TILEKIND_GRASS, TILEKIND_GROUND ) },
{ 0x0411, "tiles/grass_ground_outer_corner_2.png", TILE_CORNER_INFO(TILEKIND_GROUND, TILEKIND_GROUND, TILEKIND_GRASS, TILEKIND_GROUND ) },
{ 0x0420, "tiles/grass_ground_inner_corner.png", TILE_CORNER_INFO(TILEKIND_GRASS, TILEKIND_GROUND, TILEKIND_GRASS, TILEKIND_GRASS ) },
{ 0x0421, "tiles/grass_ground_inner_corner_2.png", TILE_CORNER_INFO(TILEKIND_GRASS, TILEKIND_GROUND, TILEKIND_GRASS, TILEKIND_GRASS ) },
{ 0x0422, "tiles/grass_ground_inner_corner_3.png", TILE_CORNER_INFO(TILEKIND_GRASS, TILEKIND_GROUND, TILEKIND_GRASS, TILEKIND_GRASS ) },
{ 0x0423, "tiles/grass_ground_two_corner.png", TILE_CORNER_INFO(TILEKIND_GRASS, TILEKIND_GROUND, TILEKIND_GRASS, TILEKIND_GROUND ) },
};
static V4 cpu_tile_infos_buffer[SDL_arraysize(tile_infos)];
static Sint32 selected_tile_kind = -1;
static Sint32 selected_tile = -1;
static Sint32 selected_rotation = 0;
@@ -671,7 +687,8 @@ static V2 get_floor_intersection_of_mouse(V2 mouse_pos) {
float t = -camera_position.z / ray_dir.z;
V3 floor_intersection = camera_position + (t * ray_dir);
floor_intersection.xy += V2_(0.5f, 0.5f);
if (selected_tile != -1)
floor_intersection.xy += V2_(0.5f, 0.5f);
return floor_intersection.xy;
}
@@ -1273,6 +1290,73 @@ bool imgui_time_picker(const char *label, int time[3]) {
return result;
}
static Uint32 get_corner_info(Sint32 tile_pos_x, Sint32 tile_pos_y) {
Uint32 tile = current_map.tiles[tile_pos_y * current_map.width + tile_pos_x];
Uint32 index = tile & 0xffff;
Uint32 rotation = (tile & 0x30000) >> 16;
Uint32 base_corner_info = tile_infos[index].corner_info;
switch (rotation) {
case 0: return base_corner_info;
case 1: return std::rotl(base_corner_info, 8);
case 2: return std::rotl(base_corner_info, 16);
case 3: return std::rotl(base_corner_info, 24);
default: return tile_infos[0].corner_info;
}
}
Uint32 find_matching_tile(Uint32 corner_info) {
Uint32 corner_info_1 = std::rotr(corner_info, 8);
Uint32 corner_info_2 = std::rotr(corner_info, 16);
Uint32 corner_info_3 = std::rotr(corner_info, 24);
for (Uint32 i = 0; i < SDL_arraysize(tile_infos); i++) {
if (corner_info == tile_infos[i].corner_info)
return i;
if (corner_info_1 == tile_infos[i].corner_info)
return (1 << 16) | i;
if (corner_info_2 == tile_infos[i].corner_info)
return (2 << 16) | i;
if (corner_info_3 == tile_infos[i].corner_info)
return (3 << 16) | i;
}
return 0;
}
void change_map_tile(V2 pos, TileKind kind) {
Sint32 pos_x = (Sint32)roundf(pos.x);
Sint32 pos_y = (Sint32)roundf(pos.y);
if (pos_x < 0 || pos_y < 0 || pos_x > current_map.width - 1 || pos_y > current_map.height - 1)
return;
SDL_Log("TileKind Change: %d %d", pos_x, pos_y);
__m128i corner_infos = _mm_setr_epi32(get_corner_info(pos_x, pos_y + 1), get_corner_info(pos_x + 1, pos_y + 1), get_corner_info(pos_x + 1, pos_y), get_corner_info(pos_x, pos_y));
__m128i none_mask = _mm_cmpeq_epi8(corner_infos, _mm_set1_epi8(TILEKIND_NONE));
__m128i error_mask = _mm_cmpeq_epi8(corner_infos, _mm_set1_epi8(TILEKIND_ERROR));
__m128i kind_mask = _mm_setr_epi32(0x0000ff00, 0x000000ff, 0xff000000, 0x00ff0000);
__m128i replace_mask = _mm_or_si128(_mm_or_si128(none_mask, kind_mask), error_mask);
corner_infos = _mm_andnot_si128(replace_mask, corner_infos);
corner_infos = _mm_or_si128(corner_infos, _mm_and_si128(replace_mask, _mm_set1_epi8(kind)));
Uint32 corner_infos_u32[4];
_mm_storeu_si128((__m128i_u *)&corner_infos_u32, corner_infos);
current_map.tiles[(pos_y + 1) * current_map.width + pos_x + 0] = find_matching_tile(corner_infos_u32[0]);
current_map.tiles[(pos_y + 1) * current_map.width + pos_x + 1] = find_matching_tile(corner_infos_u32[1]);
current_map.tiles[(pos_y + 0) * current_map.width + pos_x + 1] = find_matching_tile(corner_infos_u32[2]);
current_map.tiles[(pos_y + 0) * current_map.width + pos_x + 0] = find_matching_tile(corner_infos_u32[3]);
update_buffer(current_map.gpu_buffer, 0, current_map.width * current_map.height * sizeof(Uint32), current_map.tiles);
}
int main(int argc, char **argv) {
setup_memory_functions();
@@ -1568,7 +1652,18 @@ int main(int argc, char **argv) {
if (show_tile_picker) {
if (ImGui::Begin("Tile Picker", &show_tile_picker, ImGuiWindowFlags_NoFocusOnAppearing)) {
if (SelectableTile("##tile", selected_tile == -1, NULL, 0, ImVec2(32, 32))) {
if (ImGui::Selectable("None", selected_tile_kind == -1 && selected_tile == -1)) {
selected_tile_kind = -1;
selected_tile = -1;
}
if (ImGui::Selectable("Grass", selected_tile_kind == TILEKIND_GRASS)) {
selected_tile_kind = TILEKIND_GRASS;
selected_tile = -1;
}
if (ImGui::Selectable("Ground", selected_tile_kind == TILEKIND_GROUND)) {
selected_tile_kind = TILEKIND_GROUND;
selected_tile = -1;
}
@@ -1582,8 +1677,10 @@ int main(int argc, char **argv) {
if (available >= 32)
ImGui::SameLine();
if (SelectableTile("##tile", selected_tile == i, &tile_atlas_texture_binding, i, ImVec2(32, 32), uv0, uv1, SDL_max(selected_rotation, 0)))
if (SelectableTile("##tile", selected_tile == i, &tile_atlas_texture_binding, i, ImVec2(32, 32), uv0, uv1, SDL_max(selected_rotation, 0))) {
selected_tile_kind = -1;
selected_tile = i;
}
ImGui::PopID();
}
@@ -1629,7 +1726,8 @@ int main(int argc, char **argv) {
}
ImGui::End();
} else {
selected_tile = -1;
selected_tile = -1;
selected_tile_kind = -1;
}
if (show_demo_window)
@@ -1731,6 +1829,10 @@ int main(int argc, char **argv) {
drag_start_pos[0] = tile_x;
drag_start_pos[1] = tile_y;
if (selected_tile_kind != -1) {
change_map_tile(floor_intersection, (TileKind)selected_tile_kind);
}
}
SDL_Keymod modifiers = SDL_GetModState();
@@ -1798,6 +1900,13 @@ int main(int argc, char **argv) {
case SDL_EVENT_MOUSE_MOTION: {
mouse_pos = V2_(event.motion.x, event.motion.y);
V2 floor_intersection = get_floor_intersection_of_mouse(mouse_pos);
SDL_Log("Move: %g %g", floor_intersection.x, floor_intersection.y);
if (selected_tile_kind != -1 && dragging_tile_change) {
V2 floor_intersection = get_floor_intersection_of_mouse(mouse_pos);
change_map_tile(floor_intersection, (TileKind)selected_tile_kind);
}
} break;
case SDL_EVENT_GAMEPAD_BUTTON_DOWN: {
@@ -1890,8 +1999,9 @@ int main(int argc, char **argv) {
per_frame.map_width = current_map.width;
per_frame.mouse[0] = tile_x;
per_frame.mouse[1] = tile_y;
per_frame.flags = selected_tile != -1;
if (dragging_tile_change) {
if (dragging_tile_change && selected_tile != -1) {
per_frame.drag_start[0] = drag_start_pos[0];
per_frame.drag_start[1] = drag_start_pos[1];
} else {