Skip to content

Commit

Permalink
Editor: Support multiple autotilesets per tile
Browse files Browse the repository at this point in the history
Tiles can now be present in multiple autotilesets in the same tileset. They would be autotileable with all (max. 10) autotilesets they are included in.

The editor allows for pressing Ctrl+1, Ctrl+2, etc... up until Ctrl+9 to allow for autotiling a tile with additional 9 autotilesets. This is visually indicated in the autotile help strings.
  • Loading branch information
Vankata453 committed Oct 17, 2024
1 parent fd79c60 commit ca328d3
Show file tree
Hide file tree
Showing 11 changed files with 218 additions and 139 deletions.
4 changes: 2 additions & 2 deletions data/images/autotiles.satc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
;; |
;; V
;; Contains :
;; The autotileset name (unused as of writing these lines) : (name "snow")
;; The autotileset name (used as an indicator in the editor) : (name "snow")
;; The name of the autotileset is "snow".
;; The default tile ID (used if no tile matches any mask) : (default 11)
;; If a very special tile is needed (and it doesn't exist), it will use this tile (it's a center tile) by default.
Expand Down Expand Up @@ -75,7 +75,7 @@
;; (Contributor, 2020)
;;
;;
;; NOTE : A single id MUST NOT OCCUR MORE THAN ONE AUTOTILE IN THE ENTIRE FILE.
;; NOTE : A single id MUST NOT OCCUR IN MORE THAN ONE AUTOTILE IN AN AUTOTILESET.
;; Otherwise, the behavior is UNDEFINED.

(supertux-autotiles
Expand Down
6 changes: 6 additions & 0 deletions src/editor/editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,12 @@ Editor::get_tileselect_move_mode() const
return m_toolbox_widget->get_tileselect_move_mode();
}

void
Editor::update_autotileset()
{
m_overlay_widget->update_autotileset();
}

void
Editor::scroll(const Vector& velocity)
{
Expand Down
2 changes: 2 additions & 0 deletions src/editor/editor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ class Editor final : public Screen,
void check_deprecated_tiles(bool focus = false);
bool has_deprecated_tiles() const { return m_has_deprecated_tiles; }

void update_autotileset();

/** Checks whether the level can be saved and does not contain
obvious issues (currently: check if main sector and a spawn point
named "main" is present) */
Expand Down
157 changes: 116 additions & 41 deletions src/editor/overlay_widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include "editor/overlay_widget.hpp"

#include <fmt/format.h>

#include "editor/editor.hpp"
#include "editor/node_marker.hpp"
#include "editor/object_menu.hpp"
Expand Down Expand Up @@ -53,6 +55,7 @@ EditorOverlayWidget::EditorOverlayWidget(Editor& editor) :
m_editor(editor),
m_hovered_tile(0, 0),
m_hovered_tile_prev(0, 0),
m_last_hovered_tile(0, 0),
m_sector_pos(0, 0),
m_mouse_pos(0, 0),
m_previous_mouse_pos(0, 0),
Expand All @@ -66,6 +69,8 @@ EditorOverlayWidget::EditorOverlayWidget(Editor& editor) :
m_selected_object(nullptr),
m_edited_path(nullptr),
m_last_node_marker(nullptr),
m_available_autotilesets(),
m_current_autotileset(0),
m_object_tip(new Tip()),
m_obj_mouse_desync(0, 0),
m_rectangle_preview(new TileSelection()),
Expand Down Expand Up @@ -170,7 +175,7 @@ EditorOverlayWidget::autotile(const Vector& pos, uint32_t tile)
if (!tilemap || !is_position_inside_tilemap(tilemap, pos)) return;

tilemap->save_state();
tilemap->autotile(static_cast<int>(pos.x), static_cast<int>(pos.y), tile);
tilemap->autotile(static_cast<int>(pos.x), static_cast<int>(pos.y), tile, get_current_autotileset());
}

void
Expand All @@ -196,7 +201,7 @@ EditorOverlayWidget::autotile_corner(const Vector& pos, uint32_t tile,
if (!tilemap || !is_position_inside_tilemap(tilemap, pos)) return;

tilemap->save_state();
tilemap->autotile_corner(static_cast<int>(pos.x), static_cast<int>(pos.y), tile, op);
tilemap->autotile_corner(static_cast<int>(pos.x), static_cast<int>(pos.y), tile, get_current_autotileset(), op);
}

void
Expand Down Expand Up @@ -231,25 +236,27 @@ EditorOverlayWidget::put_tile(const Vector& target_tile)
{
for (add_tile.y = static_cast<float>(tiles->m_height) - 1.0f; add_tile.y >= 0; add_tile.y--)
{

uint32_t tile = tiles->pos(static_cast<int>(add_tile.x), static_cast<int>(add_tile.y));
auto tilemap = m_editor.get_selected_tilemap();

if (g_config->editor_autotile_mode && ((tilemap && tilemap->get_autotileset(tile)) || tile == 0))
if (g_config->editor_autotile_mode)
{
if (tile == 0)
{
tilemap->autotile_erase(target_tile + add_tile, hovered_corner + add_tile);
}
else if (tilemap->get_autotileset(tile)->is_corner())
AutotileSet* autotileset = get_current_autotileset();
if (autotileset)
{
input_autotile_corner(hovered_corner + add_tile,
tile,
target_tile + add_tile);
}
else
{
input_autotile(target_tile + add_tile, tile);
if (tile == 0)
{
m_editor.get_selected_tilemap()->autotile_erase(target_tile + add_tile, hovered_corner + add_tile, autotileset);
}
else if (get_current_autotileset()->is_corner())
{
input_autotile_corner(hovered_corner + add_tile,
tile,
target_tile + add_tile);
}
else
{
input_autotile(target_tile + add_tile, tile);
}
}
}
else
Expand Down Expand Up @@ -418,10 +425,8 @@ EditorOverlayWidget::check_tiles_for_fill(uint32_t replace_tile,
{
if (g_config->editor_autotile_mode)
{
return m_editor.get_tileset()->get_autotileset_from_tile(replace_tile)
== m_editor.get_tileset()->get_autotileset_from_tile(target_tile)
&& m_editor.get_tileset()->get_autotileset_from_tile(replace_tile)
!= m_editor.get_tileset()->get_autotileset_from_tile(third_tile);
return m_editor.get_tileset()->has_mutual_autotileset(replace_tile, target_tile) &&
!m_editor.get_tileset()->has_mutual_autotileset(replace_tile, third_tile);
}
else
{
Expand Down Expand Up @@ -1072,6 +1077,8 @@ EditorOverlayWidget::update_tile_selection()
}
}
}

update_autotileset();
}

bool
Expand Down Expand Up @@ -1197,45 +1204,63 @@ bool
EditorOverlayWidget::on_key_up(const SDL_KeyboardEvent& key)
{
auto sym = key.keysym.sym;
if (sym == SDLK_LSHIFT) {
if (sym == SDLK_LSHIFT)
{
g_config->editor_snap_to_grid = !g_config->editor_snap_to_grid;
}
if (sym == SDLK_LCTRL || sym == SDLK_RCTRL)
else if (sym == SDLK_LCTRL || sym == SDLK_RCTRL)
{
if (action_pressed)
{
g_config->editor_autotile_mode = !g_config->editor_autotile_mode;
m_current_autotileset = 0;
action_pressed = false;
}
// Hovered objects depend on which keys are pressed
hover_object();
}
if (sym == SDLK_LALT || sym == SDLK_RALT) {
else if (sym == SDLK_LALT || sym == SDLK_RALT)
{
alt_pressed = false;
}
else if (sym > SDLK_0 && sym <= SDLK_9)
{
if (m_current_autotileset == static_cast<int>(sym - SDLK_0))
m_current_autotileset = 0;
}
return true;
}

bool
EditorOverlayWidget::on_key_down(const SDL_KeyboardEvent& key)
{
auto sym = key.keysym.sym;
if (sym == SDLK_F8) {

if (sym == SDLK_F8)
{
g_config->editor_render_grid = !g_config->editor_render_grid;
}
if (sym == SDLK_F7 || sym == SDLK_LSHIFT) {
else if (sym == SDLK_F7 || sym == SDLK_LSHIFT)
{
g_config->editor_snap_to_grid = !g_config->editor_snap_to_grid;
}
if (sym == SDLK_F5 || ((sym == SDLK_LCTRL || sym == SDLK_RCTRL) && !action_pressed))
else if (sym == SDLK_F5 || ((sym == SDLK_LCTRL || sym == SDLK_RCTRL) && !action_pressed))
{
g_config->editor_autotile_mode = !g_config->editor_autotile_mode;
m_current_autotileset = 0;
action_pressed = true;
// Hovered objects depend on which keys are pressed
hover_object();
}
if (sym == SDLK_LALT || sym == SDLK_RALT) {
else if (sym == SDLK_LALT || sym == SDLK_RALT)
{
alt_pressed = true;
}
else if (sym > SDLK_0 && sym <= SDLK_9)
{
if (m_current_autotileset == 0)
m_current_autotileset = static_cast<int>(sym - SDLK_0);
}
return true;
}

Expand All @@ -1254,10 +1279,55 @@ EditorOverlayWidget::update_pos()
m_editor.get_sector()->get_camera().get_translation();
m_hovered_tile = sp_to_tp(m_sector_pos);

if (m_last_hovered_tile != m_hovered_tile)
{
m_last_hovered_tile = m_hovered_tile;

if (m_editor.get_tiles()->pos(0, 0) == 0) // Erasing
update_autotileset();
}

// update tip
hover_object();
}

void
EditorOverlayWidget::update_autotileset()
{
if (m_editor.get_tiles()->pos(0, 0) == 0) // Erasing
{
const uint32_t current_tile = m_editor.get_selected_tilemap()->get_tile_id(static_cast<int>(m_hovered_tile.x), static_cast<int>(m_hovered_tile.y));
m_available_autotilesets = m_editor.get_tileset()->get_autotilesets_from_tile(current_tile);
}
else
{
m_available_autotilesets = m_editor.get_tileset()->get_autotilesets_from_tile(m_editor.get_tiles()->pos(0, 0));
}
}

AutotileSet*
EditorOverlayWidget::get_current_autotileset() const
{
if (m_available_autotilesets.empty())
return nullptr;

if (m_current_autotileset < 0 || m_current_autotileset > static_cast<int>(m_available_autotilesets.size() - 1))
return m_available_autotilesets.front();

return m_available_autotilesets[m_current_autotileset];
}

std::string
EditorOverlayWidget::get_autotileset_key_range() const
{
if (m_available_autotilesets.size() < 2)
return "";
if (m_available_autotilesets.size() == 2)
return "(+1)";

return "(+1-" + std::to_string(std::min(static_cast<int>(m_available_autotilesets.size() - 1), 9)) + ")";
}

void
EditorOverlayWidget::draw_tile_tip(DrawingContext& context)
{
Expand Down Expand Up @@ -1563,22 +1633,23 @@ EditorOverlayWidget::draw(DrawingContext& context)

if (g_config->editor_autotile_help)
{
if (m_editor.get_tileset()->get_autotileset_from_tile(m_editor.get_tiles()->pos(0, 0)) != nullptr)
if (g_config->editor_autotile_mode)
{
if (g_config->editor_autotile_mode)
{
context.color().draw_text(Resources::normal_font, _("Autotile mode is on"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_active_color);
}
else
AutotileSet* autotileset = get_current_autotileset();
if (m_editor.get_tiles()->pos(0, 0) == 0)
{
context.color().draw_text(Resources::normal_font, _("Hold Ctrl to enable autotile"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_available_color);
if (autotileset)
{
context.color().draw_text(Resources::normal_font, fmt::format(fmt::runtime(_("Autotile erasing mode is on (\"{}\")")), autotileset->get_name()), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_active_color);
}
else
{
context.color().draw_text(Resources::normal_font, _("Autotile erasing cannot be performed here"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_error_color);
}
}
}
else if (g_config->editor_autotile_mode)
{
if (m_editor.get_tiles()->pos(0, 0) == 0)
else if (autotileset)
{
context.color().draw_text(Resources::normal_font, _("Autotile erasing mode is on"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_active_color);
context.color().draw_text(Resources::normal_font, fmt::format(fmt::runtime(_("Autotile mode is on (\"{}\")")), autotileset->get_name()), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_active_color);
}
else
{
Expand All @@ -1587,7 +1658,11 @@ EditorOverlayWidget::draw(DrawingContext& context)
}
else if (m_editor.get_tiles()->pos(0, 0) == 0)
{
context.color().draw_text(Resources::normal_font, _("Hold Ctrl to enable autotile erasing"), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_available_color);
context.color().draw_text(Resources::normal_font, fmt::format(fmt::runtime(_("Hold Ctrl{} to enable autotile erasing")), get_autotileset_key_range()), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_available_color);
}
else
{
context.color().draw_text(Resources::normal_font, fmt::format(fmt::runtime(_("Hold Ctrl{} to enable autotile")), get_autotileset_key_range()), Vector(144, 16), ALIGN_LEFT, LAYER_OBJECTS+1, EditorOverlayWidget::text_autotile_available_color);
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/editor/overlay_widget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "supertux/timer.hpp"
#include "util/typed_uid.hpp"

class AutotileSet;
class Color;
class DrawingContext;
class Editor;
Expand Down Expand Up @@ -64,6 +65,7 @@ class EditorOverlayWidget final : public Widget
virtual void on_window_resize() override;

void update_pos();
void update_autotileset();
void delete_markers();
void update_node_iterators();
void on_level_change();
Expand Down Expand Up @@ -101,6 +103,9 @@ class EditorOverlayWidget final : public Widget
void select_object();
void add_path_node();

AutotileSet* get_current_autotileset() const;
std::string get_autotileset_key_range() const;

void draw_tile_tip(DrawingContext&);
void draw_tile_grid(DrawingContext&, int tile_size, bool draw_shadow) const;
void draw_tilemap_border(DrawingContext&);
Expand Down Expand Up @@ -130,6 +135,7 @@ class EditorOverlayWidget final : public Widget
Editor& m_editor;
Vector m_hovered_tile;
Vector m_hovered_tile_prev;
Vector m_last_hovered_tile;
Vector m_sector_pos;
Vector m_mouse_pos;
Vector m_previous_mouse_pos;
Expand All @@ -147,6 +153,9 @@ class EditorOverlayWidget final : public Widget
TypedUID<PathGameObject> m_edited_path;
TypedUID<NodeMarker> m_last_node_marker;

std::vector<AutotileSet*> m_available_autotilesets;
int m_current_autotileset;

std::unique_ptr<Tip> m_object_tip;
Vector m_obj_mouse_desync;

Expand Down
2 changes: 2 additions & 0 deletions src/editor/toolbox_widget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ EditorToolboxWidget::on_mouse_button_down(const SDL_MouseButtonEvent& button)
{
if (m_tilebox->on_mouse_button_down(button))
{
m_editor.update_autotileset();
update_mouse_icon();
return true;
}
Expand Down Expand Up @@ -150,6 +151,7 @@ EditorToolboxWidget::on_mouse_button_down(const SDL_MouseButtonEvent& button)
case 0:
m_tilebox->get_tiles()->set_tile(0);
m_tilebox->set_object("");
m_editor.update_autotileset();
update_mouse_icon();
break;

Expand Down
Loading

0 comments on commit ca328d3

Please sign in to comment.