add basic autotiling
This commit is contained in:
+134
-24
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user