[cd skip] Feature auto tiling (#56)

* Added auto tiling functionality

* Highlight when dragging in tiles dialog

* Added the set grid size option for right-click menu on auto-tiles.

* Bug fix: dropping source tile on target tile only selects the tile but removes state of dragging

* Bug fix: crash when adding an auto tiling image

* CR: implementation based on extended tileset

* Bug fix: corrected choosing tiles

* CR: using tile 18 for drawing instead of the complete tile-set

* Bug fix: delete tool now works with click on tile instead of dragging

* Feature: added alternatives to auto-tiling. Each alternative has its own probability to appear while painting new auto-tiles.

* Bug fix: set original image to 100% when all probabilites for the alternatives are 0. Improved documentation.

* Feature: improved auto-tiling algorithm, avoids reselecting the alternative auto-tiles when dragging or clicking on the same auto-tile

* Store generated auto tiles into atlas management system and fix tabs width

* Fix merging conflicts

Co-authored-by: fgnm <fgnm.dev@gmail.com>
This commit is contained in:
jantwegener
2021-07-16 23:28:51 +02:00
committed by GitHub
parent e3d6fd8c0d
commit 6a15fb05b0
22 changed files with 1632 additions and 370 deletions
@@ -25,8 +25,11 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.kotcrab.vis.ui.widget.VisLabel;
import com.kotcrab.vis.ui.widget.VisTable;
import games.rednblack.editor.plugin.tiled.data.AutoTileVO;
import games.rednblack.editor.plugin.tiled.data.TileVO;
import games.rednblack.editor.plugin.tiled.manager.ResourcesManager;
import games.rednblack.editor.plugin.tiled.view.tabs.AbstractGridTilesTab;
import games.rednblack.editor.plugin.tiled.view.tabs.AutoGridTilesTab;
import games.rednblack.editor.plugin.tiled.view.tabs.GridTilesTab;
import games.rednblack.editor.plugin.tiled.view.tabs.SettingsTab;
import games.rednblack.h2d.common.UIDraggablePanel;
@@ -39,11 +42,11 @@ import games.rednblack.h2d.common.view.ui.widget.imagetabbedpane.ImageTabbedPane
*/
public class TiledPanel extends UIDraggablePanel {
public static final float GRID_WIDTH = 220f;
public static final float GRID_WIDTH = 240f;
public static final float GRID_HEIGHT = 250f;
public static final float DROP_WIDTH = 220f;
public static final float DROP_WIDTH = 240f;
public static final float DROP_HEIGHT = 140f;
public static final float SETTINGS_WIDTH = 220f;
public static final float SETTINGS_WIDTH = 240f;
public static final float SETTINGS_HEIGHT = 150f;
public TiledPlugin tiledPlugin;
@@ -55,10 +58,13 @@ public class TiledPanel extends UIDraggablePanel {
private GridTilesTab tilesTab;
private SettingsTab settingsTab;
private AutoGridTilesTab autoGridTilesTab;
private VisTable mainTable;
private Engine engine;
private ResourcesManager resourcesManager;
private boolean isAutoGridTabSelected;
public TiledPanel(TiledPlugin tiledPlugin) {
super("Tiles");
this.tiledPlugin = tiledPlugin;
@@ -104,8 +110,11 @@ public class TiledPanel extends UIDraggablePanel {
if (tab instanceof SettingsTab) {
WIDTH = SETTINGS_WIDTH;
HEIGHT = SETTINGS_HEIGHT;
} else if (tab instanceof GridTilesTab) {
if (GridTilesTab.isDrop) {
} else if (tab instanceof AbstractGridTilesTab) {
isAutoGridTabSelected = tab instanceof AutoGridTilesTab;
tiledPlugin.setAutoGridTilesTabSelected(isAutoGridTabSelected);
if (((AbstractGridTilesTab<?>) tab).isDrop) {
WIDTH = DROP_WIDTH;
HEIGHT = DROP_HEIGHT;
} else {
@@ -140,8 +149,10 @@ public class TiledPanel extends UIDraggablePanel {
});
initTabs();
}
pack();
public boolean isAutoGridTilesTabSelected() {
return isAutoGridTabSelected;
}
public void setFixedPosition() {
@@ -152,6 +163,10 @@ public class TiledPanel extends UIDraggablePanel {
return tilesTab.getContentTable();
}
public Table getAutoGridDropTable() {
return autoGridTilesTab.getContentTable();
}
public void reInitGridSettings() {
settingsTab.resetGridCategory();
}
@@ -160,22 +175,36 @@ public class TiledPanel extends UIDraggablePanel {
tilesTab.addTile(tileName, type);
}
public void addAutoTile(String tileName, int type) {
autoGridTilesTab.addTile(tileName, type);
}
public void selectTile(TileVO tileVO) {
tilesTab.selectTile(tileVO);
}
public void selectAutoTile(AutoTileVO tileVO) {
autoGridTilesTab.selectTile(tileVO);
}
public void removeTile() {
tilesTab.removeTile();
reInitTabTable();
reInitTabTable(tilesTab);
tilesTab.scrollTiles();
}
public void removeAllTiles() {
tilesTab.removeAllTiles();
reInitTabTable();
reInitTabTable(tilesTab);
tilesTab.scrollTiles();
}
public void removeAutoTile() {
autoGridTilesTab.removeTile();
reInitTabTable(autoGridTilesTab);
autoGridTilesTab.scrollTiles();
}
private void initTabs() {
tilesTab = new GridTilesTab(this, 0);
tilesTab.initView();
@@ -184,15 +213,27 @@ public class TiledPanel extends UIDraggablePanel {
settingsTab = new SettingsTab(this, "Settings", 1);
settingsTab.initView();
tabbedPane.insert(settingsTab.getTabIndex(), settingsTab);
autoGridTilesTab = new AutoGridTilesTab(this, "Auto Tiling", 2);
autoGridTilesTab.initView();
tabbedPane.insert(autoGridTilesTab.getTabIndex(), autoGridTilesTab);
reInitTabTable();
// reinit the currently visible tab
if (isAutoGridTabSelected) {
reInitTabTable(autoGridTilesTab);
} else {
reInitTabTable(tilesTab);
}
}
public void reInitTabTable() {
float width = GridTilesTab.isDrop ? DROP_WIDTH : GRID_WIDTH;
float height = GridTilesTab.isDrop ? DROP_HEIGHT : GRID_HEIGHT;
public void reInitTabTable(AbstractGridTilesTab<?> tab) {
isAutoGridTabSelected = tab instanceof AutoGridTilesTab;
tiledPlugin.setAutoGridTilesTabSelected(isAutoGridTabSelected);
float width = tab.isDrop ? DROP_WIDTH : GRID_WIDTH;
float height = tab.isDrop ? DROP_HEIGHT : GRID_HEIGHT;
tabTable.clear();
tabTable.add(tilesTab.getContentTable())
tabTable.add(tab.getContentTable())
.width(width)
.height(height);
tabTable.pack();
@@ -18,8 +18,11 @@
package games.rednblack.editor.plugin.tiled;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import games.rednblack.editor.renderer.data.TexturePackVO;
import org.puremvc.java.interfaces.INotification;
import org.puremvc.java.patterns.mediator.Mediator;
@@ -27,12 +30,21 @@ import com.badlogic.ashley.core.Engine;
import com.badlogic.ashley.core.Entity;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.PixmapIO;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.utils.DragAndDrop;
import com.badlogic.gdx.scenes.scene2d.utils.DragAndDrop.Target;
import com.kotcrab.vis.ui.util.dialog.Dialogs;
import com.kotcrab.vis.ui.util.dialog.OptionDialogAdapter;
import games.rednblack.editor.plugin.tiled.data.AlternativeAutoTileVO;
import games.rednblack.editor.plugin.tiled.data.AutoTileVO;
import games.rednblack.editor.plugin.tiled.data.TileVO;
import games.rednblack.editor.plugin.tiled.manager.AutoGridTileManager;
import games.rednblack.editor.plugin.tiled.tools.DeleteTileTool;
import games.rednblack.editor.plugin.tiled.tools.DrawTileTool;
import games.rednblack.editor.plugin.tiled.view.SpineDrawable;
@@ -51,11 +63,16 @@ public class TiledPanelMediator extends Mediator<TiledPanel> {
public static final String NAME = TAG;
private TiledPlugin tiledPlugin;
private DragAndDrop.Target target;
private DragAndDrop.Target targetGrid;
private DragAndDrop.Target targetAutoGrid;
private AutoGridTileManager autoGridTileManager;
public TiledPanelMediator(TiledPlugin tiledPlugin) {
super(NAME, new TiledPanel(tiledPlugin));
this.tiledPlugin = tiledPlugin;
autoGridTileManager = new AutoGridTileManager(tiledPlugin);
viewComponent.initLockView();
}
@@ -71,6 +88,11 @@ public class TiledPanelMediator extends Mediator<TiledPanel> {
TiledPlugin.ACTION_SET_GRID_SIZE_FROM_LIST,
TiledPlugin.ACTION_SET_OFFSET,
TiledPlugin.OPEN_DROP_DOWN,
TiledPlugin.AUTO_TILE_SELECTED,
TiledPlugin.ACTION_DELETE_AUTO_TILE,
TiledPlugin.AUTO_OPEN_DROP_DOWN,
TiledPlugin.AUTO_FILL_TILES,
TiledPlugin.ACTION_SETUP_ALTERNATIVES_AUTO_TILE,
TiledPlugin.GRID_CHANGED,
SettingsTab.OK_BTN_CLICKED,
TiledPlugin.ACTION_SET_GRID_SIZE_FROM_ITEM,
@@ -94,31 +116,8 @@ public class TiledPanelMediator extends Mediator<TiledPanel> {
tiledPlugin.initSaveData();
viewComponent.initView();
if (target != null)
tiledPlugin.facade.sendNotification(MsgAPI.REMOVE_TARGET, target);
target = new DragAndDrop.Target(viewComponent.getDropTable()) {
@Override
public boolean drag(DragAndDrop.Source source, DragAndDrop.Payload payload, float x, float y, int pointer) {
return true;
}
@Override
public void drop(DragAndDrop.Source source, DragAndDrop.Payload payload, float x, float y, int pointer) {
ResourcePayloadObject resourcePayloadObject = (ResourcePayloadObject) payload.getObject();
int type = mapClassNameToEntityType(resourcePayloadObject.className);
if (type == EntityFactory.UNKNOWN_TYPE) return; //only some resources can become a tile!
String tileName = resourcePayloadObject.name;
// we send a notifier even in the case when the tile is not already added
tiledPlugin.facade.sendNotification(TiledPlugin.TILE_ADDED, new Object[]{tileName, type});
if (type == EntityFactory.IMAGE_TYPE) {
// ensure that all selected images are dropped
// the respective listener is responsible for dropping one-by-one, since he tracks the selected ones
tiledPlugin.facade.sendNotification(MsgAPI.IMAGE_BUNDLE_DROP, new Object[]{tileName, type});
}
}
};
tiledPlugin.facade.sendNotification(MsgAPI.ADD_TARGET, target);
targetGrid = initTarget(targetGrid, viewComponent.getDropTable(), false);
targetAutoGrid = initTarget(targetAutoGrid, viewComponent.getAutoGridDropTable(), true);
Engine engine = tiledPlugin.getAPI().getEngine();
viewComponent.setEngine(engine);
viewComponent.setFixedPosition();
@@ -129,17 +128,40 @@ public class TiledPanelMediator extends Mediator<TiledPanel> {
Object[] payload = notification.getBody();
tileName = (String) payload[0];
int type = (int) payload[1];
// we only add tiles that have not been added previously
if (tiledPlugin.dataToSave.containsTile(tileName)) return;
boolean isAutoTilesTarget = (boolean) payload[2];
viewComponent.addTile(tileName, type);
if (isAutoTilesTarget) {
// we only add tiles that have not been added previously
if (tiledPlugin.dataToSave.containsAutoTile(tileName)) return;
tiledPlugin.dataToSave.addTile(tileName, type);
// retract the images for the auto-tiles
retractAutoTiles(tileName);
viewComponent.addAutoTile(tileName, type);
tiledPlugin.dataToSave.addAutoTile(tileName, type);
} else {
// we only add tiles that have not been added previously
if (tiledPlugin.dataToSave.containsTile(tileName)) return;
viewComponent.addTile(tileName, type);
tiledPlugin.dataToSave.addTile(tileName, type);
}
tiledPlugin.saveDataManager.save();
break;
case TiledPlugin.TILE_SELECTED:
viewComponent.selectTile(notification.getBody());
case TiledPlugin.AUTO_TILE_SELECTED:
if (viewComponent.isAutoGridTilesTabSelected()) {
viewComponent.selectAutoTile(notification.getBody());
} else {
viewComponent.selectTile(notification.getBody());
}
break;
case TiledPlugin.AUTO_FILL_TILES:
autoGridTileManager.autoFill();
break;
case TiledPlugin.OPEN_DROP_DOWN:
tileName = notification.getBody();
HashMap<String, String> actionsSet = new HashMap<>();
@@ -150,24 +172,41 @@ public class TiledPanelMediator extends Mediator<TiledPanel> {
tiledPlugin.facade.sendNotification(TiledPlugin.TILE_SELECTED, tiledPlugin.dataToSave.getTile(tileName));
tiledPlugin.getAPI().showPopup(actionsSet, tileName);
break;
case TiledPlugin.AUTO_OPEN_DROP_DOWN:
tileName = notification.getBody();
HashMap<String, String> autoActionsSet = new HashMap<>();
autoActionsSet.put(TiledPlugin.ACTION_SET_GRID_SIZE_FROM_LIST, "Set grid size");
autoActionsSet.put(TiledPlugin.ACTION_DELETE_AUTO_TILE, "Delete");
// autoActionsSet.put(TiledPlugin.ACTION_OPEN_OFFSET_PANEL, "Set offset");
autoActionsSet.put(TiledPlugin.ACTION_SETUP_ALTERNATIVES_AUTO_TILE, "Setup alternatives");
tiledPlugin.facade.sendNotification(TiledPlugin.AUTO_TILE_SELECTED, tiledPlugin.dataToSave.getAutoTile(tileName));
tiledPlugin.getAPI().showPopup(autoActionsSet, tileName);
break;
case MsgAPI.ACTION_DELETE_IMAGE_RESOURCE:
tileName = notification.getBody();
tiledPlugin.facade.sendNotification(TiledPlugin.ACTION_DELETE_TILE, tileName);
tiledPlugin.facade.sendNotification(TiledPlugin.ACTION_DELETE_AUTO_TILE, tileName);
break;
case TiledPlugin.ACTION_SET_GRID_SIZE_FROM_LIST:
float width = 0;
float height = 0;
TileVO t = tiledPlugin.dataToSave.getTile(notification.getBody());
if (t.entityType == EntityFactory.SPINE_TYPE) {
SpineDrawable spineDrawable = tiledPlugin.pluginRM.getSpineDrawable(t.regionName);
width = spineDrawable.width;
height = spineDrawable.height;
} else {
if (tiledPlugin.isAutoGridTilesTabSelected()) {
AutoTileVO t = tiledPlugin.dataToSave.getAutoTile(notification.getBody());
TextureRegion r = tiledPlugin.pluginRM.getTextureRegion(t.regionName, t.entityType);
width = r.getRegionWidth();
height = r.getRegionHeight();
width = r.getRegionWidth() / TiledPlugin.AUTO_TILE_COLS;
height = r.getRegionHeight() / TiledPlugin.AUTO_TILE_ROWS;
} else {
TileVO t = tiledPlugin.dataToSave.getTile(notification.getBody());
if (t.entityType == EntityFactory.SPINE_TYPE) {
SpineDrawable spineDrawable = tiledPlugin.pluginRM.getSpineDrawable(t.regionName);
width = spineDrawable.width;
height = spineDrawable.height;
} else {
TextureRegion r = tiledPlugin.pluginRM.getTextureRegion(t.regionName, t.entityType);
width = r.getRegionWidth();
height = r.getRegionHeight();
}
}
tiledPlugin.dataToSave.setGrid(width / tiledPlugin.getPixelToWorld(), height / tiledPlugin.getPixelToWorld());
tiledPlugin.facade.sendNotification(TiledPlugin.GRID_CHANGED);
break;
@@ -180,6 +219,25 @@ public class TiledPanelMediator extends Mediator<TiledPanel> {
viewComponent.removeTile();
break;
case TiledPlugin.ACTION_DELETE_AUTO_TILE:
String tn2 = notification.getBody();
if (!tiledPlugin.dataToSave.containsAutoTile(tn2)) return;
tiledPlugin.dataToSave.removeAutoTile(tn2);
tiledPlugin.saveDataManager.save();
tiledPlugin.setSelectedAutoTileVO(new AutoTileVO());
for (AutoTileVO autoTile : tiledPlugin.dataToSave.getAutoTiles()) {
Iterator<AlternativeAutoTileVO> iter = autoTile.alternativeAutoTileList.iterator();
while (iter.hasNext()) {
AlternativeAutoTileVO alternativeAutoTileVO = iter.next();
if (alternativeAutoTileVO.region.equals(tn2)) {
iter.remove();
}
}
}
viewComponent.removeAutoTile();
tiledPlugin.facade.sendNotification(TiledPlugin.ACTION_RECALC_PERCENT_ALTERNATIVES_AUTO_TILE);
case TiledPlugin.ACTION_DELETE_TILE_ALL:
Dialogs.showOptionDialog(tiledPlugin.getAPI().getUIStage(), "Delete all...", "Do you really want to delete all tiles?",
Dialogs.OptionDialogType.YES_NO, new OptionDialogAdapter() {
@@ -242,6 +300,99 @@ public class TiledPanelMediator extends Mediator<TiledPanel> {
}
}
/**
* Retracts all auto-tiles from the given auto-tile-template.
*
* @param tileName The name of the tile from that the auto-tiles are retracted from.
*/
private void retractAutoTiles(String tileName) {
TextureRegion tr = tiledPlugin.getAPI().getSceneLoader().getRm().getTextureRegion(tileName);
tr.getTexture().getTextureData().prepare();
Pixmap pixmap = tr.getTexture().getTextureData().consumePixmap();
String name = tileName;
int tileW = tr.getRegionWidth() / TiledPlugin.AUTO_TILE_COLS;
int tileH = tr.getRegionHeight() / TiledPlugin.AUTO_TILE_ROWS;
int maxX = tr.getRegionWidth() + tr.getRegionX();
int maxY = tr.getRegionHeight() + tr.getRegionY();
//Create new atlas packing settings if doesn't exists
String atlasName = name + TiledPlugin.AUTO_TILE_ATLAS_SUFFIX;
TexturePackVO texturePackVO = tiledPlugin.getAPI().getCurrentProjectInfoVO().imagesPacks.get(atlasName);
if (texturePackVO == null) {
texturePackVO = new TexturePackVO();
texturePackVO.name = atlasName;
tiledPlugin.getAPI().getCurrentProjectInfoVO().imagesPacks.put(texturePackVO.name, texturePackVO);
}
int i = 0;
for (int x = tr.getRegionX(); x < maxX; x += tileW) {
for (int y = tr.getRegionY(); y < maxY; y += tileH) {
// skip non used
if (i != 4 && i != 9 && i != 14 && i != 19 && i != 49 && i != 50 && i != 51) {
int w = x + tileW <= pixmap.getWidth() ? tileW : pixmap.getWidth() - x;
int h = y + tileH <= pixmap.getHeight() ? tileH : pixmap.getHeight() - y;
Pixmap tilePixmap = new Pixmap(w, h, Pixmap.Format.RGBA8888);
tilePixmap.drawPixmap(pixmap, 0, 0, x, y, w, h);
String tilePngName = name + i;
String imagesPath = tiledPlugin.getCurrentRawImagesPath() + File.separator + tilePngName + ".png";
FileHandle path = new FileHandle(imagesPath);
PixmapIO.writePNG(path, tilePixmap);
tilePixmap.dispose();
texturePackVO.regions.add(tilePngName);
}
i++;
}
}
// create mini image
Pixmap tilePixmap = new Pixmap(tileW, tileH, Pixmap.Format.RGBA8888);
tilePixmap.drawPixmap(pixmap, tr.getRegionX(), tr.getRegionY(), tr.getRegionWidth(), tr.getRegionHeight(), 0, 0, tileW, tileH);
String miniImageName = name + TiledPlugin.AUTO_TILE_MINI_SUFFIX;
String imagesPath = tiledPlugin.getCurrentRawImagesPath() + File.separator + miniImageName + ".png";
FileHandle path = new FileHandle(imagesPath);
PixmapIO.writePNG(path, tilePixmap);
tilePixmap.dispose();
pixmap.dispose();
texturePackVO.regions.add(miniImageName);
facade.sendNotification(MsgAPI.ACTION_REPACK);
}
private Target initTarget(Target targetGrid, Table dropTable, boolean isAutoGridTarget) {
if (targetGrid != null)
tiledPlugin.facade.sendNotification(MsgAPI.REMOVE_TARGET, targetGrid);
targetGrid = new DragAndDrop.Target(dropTable) {
@Override
public boolean drag(DragAndDrop.Source source, DragAndDrop.Payload payload, float x, float y, int pointer) {
return true;
}
@Override
public void drop(DragAndDrop.Source source, DragAndDrop.Payload payload, float x, float y, int pointer) {
ResourcePayloadObject resourcePayloadObject = (ResourcePayloadObject) payload.getObject();
int type = mapClassNameToEntityType(resourcePayloadObject.className);
if (type == EntityFactory.UNKNOWN_TYPE) return; //only some resources can become a tile!
String tileName = resourcePayloadObject.name;
// we send a notifier even in the case when the tile is not already added
tiledPlugin.facade.sendNotification(TiledPlugin.TILE_ADDED, new Object[]{tileName, type, isAutoGridTarget});
if (type == EntityFactory.IMAGE_TYPE) {
// ensure that all selected images are dropped
// the respective listener is responsible for dropping one-by-one, since he tracks the selected ones
tiledPlugin.facade.sendNotification(MsgAPI.IMAGE_BUNDLE_DROP, new Object[]{tileName, type, isAutoGridTarget});
}
}
};
tiledPlugin.facade.sendNotification(MsgAPI.ADD_TARGET, targetGrid);
return targetGrid;
}
private int mapClassNameToEntityType(String className) {
if (className.endsWith(".ImageResource"))
return EntityFactory.IMAGE_TYPE;
@@ -18,6 +18,7 @@
package games.rednblack.editor.plugin.tiled;
import java.io.File;
import java.util.Set;
import com.badlogic.ashley.core.Entity;
@@ -29,6 +30,7 @@ import com.badlogic.gdx.utils.Array;
import com.kotcrab.vis.ui.VisUI;
import com.kotcrab.vis.ui.widget.VisImageButton;
import games.rednblack.editor.plugin.tiled.data.AutoTileVO;
import games.rednblack.editor.plugin.tiled.data.TileVO;
import games.rednblack.editor.plugin.tiled.manager.ResourcesManager;
import games.rednblack.editor.plugin.tiled.offset.OffsetPanel;
@@ -37,6 +39,7 @@ import games.rednblack.editor.plugin.tiled.save.DataToSave;
import games.rednblack.editor.plugin.tiled.save.SaveDataManager;
import games.rednblack.editor.plugin.tiled.tools.DeleteTileTool;
import games.rednblack.editor.plugin.tiled.tools.DrawTileTool;
import games.rednblack.editor.plugin.tiled.view.dialog.AlternativeAutoTileDialogMediator;
import games.rednblack.editor.plugin.tiled.view.dialog.ImportTileSetDialogMediator;
import games.rednblack.editor.renderer.components.MainItemComponent;
import games.rednblack.editor.renderer.components.TextureRegionComponent;
@@ -58,21 +61,38 @@ public class TiledPlugin extends H2DPluginAdapter {
public static final String CLASS_NAME = "games.rednblack.editor.plugin.tiled";
public static final String TILE_ADDED = CLASS_NAME + ".TILE_ADDED";
public static final String TILE_SELECTED = CLASS_NAME + ".TILE_SELECTED";
public static final String AUTO_TILE_SELECTED = CLASS_NAME + ".AUTO_TILE_SELECTED";
public static final String AUTO_FILL_TILES = CLASS_NAME + ".FILL_AUTO_TILE";
public static final String OPEN_DROP_DOWN = CLASS_NAME + ".OPEN_DROP_DOWN";
public static final String AUTO_OPEN_DROP_DOWN = CLASS_NAME + ".AUTO_OPEN_DROP_DOWN";
public static final String GRID_CHANGED = CLASS_NAME + ".GRID_CHANGED";
public static final String IMPORT_TILESET_PANEL_OPEN = CLASS_NAME + ".IMPORT_TILESET_PANEL_OPEN";
public static final String ACTION_DELETE_TILE = CLASS_NAME + ".ACTION_DELETE_TILE";
public static final String ACTION_DELETE_AUTO_TILE = CLASS_NAME + ".ACTION_DELETE_AUTO_TILE";
public static final String ACTION_DELETE_TILE_ALL = CLASS_NAME + ".ACTION_DELETE_TILE_ALL";
public static final String ACTION_SET_OFFSET = CLASS_NAME + ".ACTION_SET_OFFSET";
public static final String ACTION_OPEN_OFFSET_PANEL = CLASS_NAME + ".ACTION_OPEN_OFFSET_PANEL";
public static final String TILE_GRID_OFFSET_ADDED = CLASS_NAME + ".TILE_GRID_OFFSET_ADDED";
public static final String ACTION_SET_GRID_SIZE_FROM_ITEM = CLASS_NAME + ".ACTION_SET_GRID_SIZE_FROM_ITEM";
public static final String ACTION_SET_GRID_SIZE_FROM_LIST = CLASS_NAME + ".ACTION_SET_GRID_SIZE_FROM_LIST";
public static final String ACTION_SAVE_ALTERNATIVES_AUTO_TILE = CLASS_NAME + ".ACTION_SAVE_ALTERNATIVES_AUTO_TILE";
public static final String ACTION_SETUP_ALTERNATIVES_AUTO_TILE = CLASS_NAME + ".ACTION_SETUP_ALTERNATIVES_AUTO_TILE";
public static final String ACTION_RECALC_PERCENT_ALTERNATIVES_AUTO_TILE = CLASS_NAME + ".ACTION_RECALC_PERCENT_ALTERNATIVES_AUTO_TILE";
//-------end--------//
public static final String TILE_TAG = "TILE";
public static final String ROW = "ROW";
public static final String COLUMN = "COLUMN";
public static final String REGION = "REGION";
public static final String ORIG_AUTO_TILE = "ORIG_AUTO_TILE";
public static final String AUTO_TILE_TAG = "AUTO_TILE";
public static final String AUTO_TILE_ATLAS_SUFFIX = "-autotile";
public static final String AUTO_TILE_MINI_SUFFIX = "-mini";
public static final String AUTO_TILE_DRAW_SUFFIX = "18";
public static final int AUTO_TILE_ROWS = 5;
public static final int AUTO_TILE_COLS = 11;
public DataToSave dataToSave;
public SaveDataManager saveDataManager;
@@ -83,13 +103,17 @@ public class TiledPlugin extends H2DPluginAdapter {
public OffsetPanel offsetPanel;
private TileVO selectedTileVO;
private AutoTileVO selectedAutoTileVO;
private CustomVariables currentEntityCustomVariables;
private MainItemComponent currentEntityMainItemComponent;
private TransformComponent currentEntityTransformComponent;
private boolean isAutoGridTabSelected;
public TiledPlugin() {
super(CLASS_NAME);
selectedTileVO = new TileVO();
selectedAutoTileVO = new AutoTileVO();
currentEntityCustomVariables = new CustomVariables();
}
@@ -97,6 +121,7 @@ public class TiledPlugin extends H2DPluginAdapter {
public void initPlugin() {
facade.registerMediator(new TiledPanelMediator(this));
facade.registerMediator(new ImportTileSetDialogMediator(pluginAPI, facade));
facade.registerMediator(new AlternativeAutoTileDialogMediator(this));
pluginRM = new ResourcesManager(this);
offsetPanel = new OffsetPanel(this);
@@ -200,8 +225,20 @@ public class TiledPlugin extends H2DPluginAdapter {
}
public String getSelectedTileName() {
if (isAutoGridTabSelected) {
return selectedAutoTileVO.regionName;
}
return selectedTileVO.regionName;
}
/**
* Explicitly returns the selected auto tile name, regardless of whether the auto grid tab is shown or any other.
*
* @return The selected auto tile name.
*/
public String getSelectedAutoTileName() {
return selectedAutoTileVO.regionName;
}
public int getSelectedTileType() {
return selectedTileVO.entityType;
@@ -223,6 +260,14 @@ public class TiledPlugin extends H2DPluginAdapter {
this.selectedTileVO = selectedTileVO;
}
public AutoTileVO getSelectedAutoTileVO() {
return selectedAutoTileVO;
}
public void setSelectedAutoTileVO(AutoTileVO selectedAutoTileVO) {
this.selectedAutoTileVO = selectedAutoTileVO;
}
public void applySelectedTileGridOffset() {
pluginAPI.getProjectEntities().forEach(entity -> {
if (!(isTile(entity))) return;
@@ -236,8 +281,21 @@ public class TiledPlugin extends H2DPluginAdapter {
saveOffsetChanges();
}
public boolean isAutoGridTilesTabSelected() {
return isAutoGridTabSelected;
}
public void setAutoGridTilesTabSelected(boolean isAutoGridTabSelected) {
this.isAutoGridTabSelected = isAutoGridTabSelected;
}
private void saveOffsetChanges() {
dataToSave.setTileGridOffset(selectedTileVO);
saveDataManager.save();
}
public String getCurrentRawImagesPath() {
return getAPI().getProjectPath() + File.separator + "assets" + File.separator + "orig" + File.separator + "images";
}
}
@@ -0,0 +1,44 @@
package games.rednblack.editor.plugin.tiled.data;
/**
* This class represents an alternative to an auto-tile. It contains a region to paint when selected and a probabilty to be selected.
*
* @author Jan-Thierry Wegener
*/
public class AlternativeAutoTileVO {
/**
* The region to paint when selected.
*/
public String region = "";
/**
* The probability to be selected by the auto-tile drawing strategy.
*/
public Float percent = Float.valueOf(0.0f);
public AlternativeAutoTileVO() {
}
/**
* Creates a new alternative from the given region and probability.
*
* @param region The region to paint.
* @param percent The probability to be selected.
*/
public AlternativeAutoTileVO(String region, Float percent) {
this.region = region;
this.percent = percent;
}
/**
* Creates a new alternative from the given region and probability.
*
* @param region The region to paint.
* @param percent The probability to be selected.
*/
public AlternativeAutoTileVO(String region, String percent) {
this.region = region;
this.percent = Float.valueOf(percent);
}
}
@@ -0,0 +1,42 @@
package games.rednblack.editor.plugin.tiled.data;
import com.badlogic.gdx.math.Vector2;
import games.rednblack.editor.renderer.factory.EntityFactory;
public class AutoTileVO implements TextureRegionVO {
public String regionName = "";
public Vector2 gridOffset;
public int entityType = EntityFactory.IMAGE_TYPE;
/**
* The list of alternative auto-tiles.
*/
public final DefaultValueList<AlternativeAutoTileVO> alternativeAutoTileList = new DefaultValueList<>();
public AutoTileVO() {
gridOffset = new Vector2();
}
public AutoTileVO(String regionName) {
this.regionName = regionName;
gridOffset = new Vector2();
}
public AutoTileVO(String regionName, Vector2 offset) {
this.regionName = regionName;
this.gridOffset = offset;
}
@Override
public String getRegionName() {
return regionName;
}
@Override
public int getEntityType() {
return entityType;
}
}
@@ -0,0 +1,38 @@
package games.rednblack.editor.plugin.tiled.data;
import java.util.ArrayList;
/**
* A list that provides a default value when the index is out-of-upper-bound.
*
* @author Jan-Thierry Wegener
*
* @param <E> The list element type.
*/
public class DefaultValueList<E> extends ArrayList<E> {
/**
*
*/
private static final long serialVersionUID = 1L;
public DefaultValueList() {
super();
}
/**
* Returns the element at the given index or the default value if the index is greater than or equal to the size.
*
* @param index The index of the element.
* @param defaultValue The default element if the index is out-of-upper-bound.
*
* @return The element at the given index or the default value.
*/
public E get(int index, E defaultValue) {
if (index >= size()) {
return defaultValue;
}
return super.get(index);
}
}
@@ -0,0 +1,9 @@
package games.rednblack.editor.plugin.tiled.data;
public interface TextureRegionVO {
public String getRegionName();
public int getEntityType();
}
@@ -1,28 +1,40 @@
package games.rednblack.editor.plugin.tiled.data;
import com.badlogic.gdx.math.Vector2;
import games.rednblack.editor.renderer.factory.EntityFactory;
/**
* Created by mariam on 5/13/16.
*/
public class TileVO {
public class TileVO implements TextureRegionVO {
public String regionName = "";
public Vector2 gridOffset;
public int entityType = EntityFactory.IMAGE_TYPE;
public String regionName = "";
public Vector2 gridOffset;
public int entityType = EntityFactory.IMAGE_TYPE;
public TileVO() {
gridOffset = new Vector2();
}
public TileVO() {
gridOffset = new Vector2();
}
public TileVO(String regionName) {
this.regionName = regionName;
gridOffset = new Vector2();
}
public TileVO(String regionName) {
this.regionName = regionName;
gridOffset = new Vector2();
}
public TileVO(String regionName, Vector2 offset) {
this.regionName = regionName;
this.gridOffset = offset;
}
@Override
public String getRegionName() {
return regionName;
}
@Override
public int getEntityType() {
return entityType;
}
public TileVO(String regionName, Vector2 offset) {
this.regionName = regionName;
this.gridOffset = offset;
}
}
@@ -0,0 +1,241 @@
package games.rednblack.editor.plugin.tiled.manager;
import com.badlogic.ashley.core.Entity;
import games.rednblack.editor.plugin.tiled.TiledPlugin;
import games.rednblack.editor.renderer.components.MainItemComponent;
import games.rednblack.editor.renderer.utils.ComponentRetriever;
import games.rednblack.h2d.common.command.ReplaceRegionCommandBuilder;
public class AutoGridTileManager {
private static final int UL = 1;
private static final int U = 2;
private static final int UR = 4;
private static final int R = 8;
private static final int DR = 16;
private static final int D = 32;
private static final int DL = 64;
private static final int L = 128;
private final ReplaceRegionCommandBuilder replaceRegionCommandBuilder = new ReplaceRegionCommandBuilder();
private TiledPlugin tiledPlugin;
public AutoGridTileManager(TiledPlugin tiledPlugin) {
this.tiledPlugin = tiledPlugin;
}
public void autoFill() {
for (Entity entity : tiledPlugin.getAPI().getProjectEntities()) {
MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class);
if (!mainItemComponent.tags.contains(TiledPlugin.AUTO_TILE_TAG)) {
continue;
}
int col = mainItemComponent.customVariables.getIntegerVariable(TiledPlugin.COLUMN);
int row = mainItemComponent.customVariables.getIntegerVariable(TiledPlugin.ROW);
int c = 0;
int val = 0;
Entity ul = tiledPlugin.getPluginEntityWithParams(row + 1, col - 1);
if (ul != null) {
c++;
val += UL;
}
Entity u = tiledPlugin.getPluginEntityWithParams(row + 1, col);
if (u != null) {
c++;
val += U;
}
Entity ur = tiledPlugin.getPluginEntityWithParams(row + 1, col + 1);
if (ur != null) {
c++;
val += UR;
}
Entity r = tiledPlugin.getPluginEntityWithParams(row, col + 1);
if (r != null) {
c++;
val += R;
}
Entity dr = tiledPlugin.getPluginEntityWithParams(row - 1, col + 1);
if (dr != null) {
c++;
val += DR;
}
Entity d = tiledPlugin.getPluginEntityWithParams(row - 1, col);
if (d != null) {
c++;
val += D;
}
Entity dl = tiledPlugin.getPluginEntityWithParams(row - 1, col - 1);
if (dl != null) {
c++;
val += DL;
}
Entity l = tiledPlugin.getPluginEntityWithParams(row, col - 1);
if (l != null) {
c++;
val += L;
}
int index = getIndex(c, val);
String region = mainItemComponent.customVariables.getStringVariable(TiledPlugin.REGION) + index;
replaceRegionCommandBuilder.begin(entity);
replaceRegionCommandBuilder.setRegion(tiledPlugin.getAPI().getSceneLoader().getRm().getTextureRegion(region));
replaceRegionCommandBuilder.setRegionName(region);
replaceRegionCommandBuilder.execute(tiledPlugin.facade);
}
}
/**
* Test whether the tiles in the given direction ({@link #UL} to {@link #L}) are all occupied.
*
* @param tiles The tiles ({@link #UL} to {@link #L}).
* @param val The value for the surroundings.
*
* @return true, if the tiles are all occupied by another tile, false otherwise.
*/
private boolean isOccupied(int val, int ... tiles) {
for (int t : tiles) {
if ((t & val) == 0) {
return false;
}
}
return true;
}
/**
* Test whether the tiles in the given direction ({@link #UL} to {@link #L}) are all empty.
*
* @param tiles The tiles ({@link #UL} to {@link #L}).
* @param val The value for the surroundings.
*
* @return true, if the tiles are all empty, false otherwise.
*/
private boolean isEmpty(int val, int ... tiles) {
for (int t : tiles) {
if ((t & val) > 0) {
return false;
}
}
return true;
}
// 24
private int getIndex(int c, int val) {
switch (c) {
case 8:
return 6;
case 7:
if (isEmpty(val, DR)) {
return 26;
} else if (isEmpty(val, UR)) {
return 27;
} else if (isEmpty(val, DL)) {
return 31;
} else if (isEmpty(val, UL)) {
return 32;
}
case 6:
if (isOccupied(val, L, DL, D, R, U, UL) && isEmpty(val, DR, UR)) {
return 29;
} else if (isOccupied(val, L, U, UR, R, DR, D) && isEmpty(val, UL, DL)) {
return 34;
} else if (isOccupied(val, L, UL, U, UR, R, D) && isEmpty(val, DR, DL)) {
return 41;
} else if (isOccupied(val, L, U, R, DR, D, DL) && isEmpty(val, UR, UL)) {
return 42;
} else if (isOccupied(val, L, UL, U, R, DR, D) && isEmpty(val, DL, UR)) {
return 45;
} else if (isOccupied(val, D, DL, L, U, UR, R) && isEmpty(val, UL, DR)) {
return 46;
}
case 5:
if (isOccupied(val, U, UR, R, DR, D) && isEmpty(val, L)) {
return 1;
} else if (isOccupied(val, R, DR, D, DL, L) && isEmpty(val, U)) {
return 5;
} else if (isOccupied(val, L, UL, U, UR, R) && isEmpty(val, D)) {
return 7;
} else if (isOccupied(val, U, D, DL, L, UL) && isEmpty(val, R)) {
return 11;
} else if (isOccupied(val, L, U, R, DR, D) && isEmpty(val, DL, UL, UR)) {
return 47;
} else if (isOccupied(val, L, U, UR, R, D) && isEmpty(val, UL, DR, DL)) {
return 48;
} else if (isOccupied(val, L, U, R, D, DL) && isEmpty(val, UL, UR, DR)) {
return 52;
} else if (isOccupied(val, L, UL, U, R, D) && isEmpty(val, DL, UR, DR)) {
return 53;
}
case 4:
if (isOccupied(val, U, UR, R, D) && isEmpty(val, DR, L)) {
return 21;
} else if (isOccupied(val, U, R, DR, D) && isEmpty(val, UR, L)) {
return 22;
} else if (isOccupied(val, L, DL, D, R) && isEmpty(val, DR, U)) {
return 25;
} else if (isOccupied(val, L, UL, U, R) && isEmpty(val, UR, D)) {
return 28;
} else if (isOccupied(val, L, D, DR, R) && isEmpty(val, U, DL)) {
return 30;
} else if (isOccupied(val, L, U, UR, R) && isEmpty(val, UL, D)) {
return 33;
} else if (isOccupied(val, L, UL, U, D) && isEmpty(val, R, DL)) {
return 36;
} else if (isOccupied(val, U, D, DL, L) && isEmpty(val, UL, R)) {
return 37;
} else if (isOccupied(val, L, U, R, D) && isEmpty(val, DR, DL, UR, UL)) {
return 44;
}
case 3:
if (isOccupied(val, R, DR, D) && isEmpty(val, L, U)) {
return 0;
} else if (isOccupied(val, U, UR, R) && isEmpty(val, L, D)) {
return 2;
} else if (isOccupied(val, L, DL, D) && isEmpty(val, U, R)) {
return 10;
} else if (isOccupied(val, L, UL, U) && isEmpty(val, R, D)) {
return 12;
} else if (isOccupied(val, U, R, D) && isEmpty(val, L, UR, DR)) {
return 24;
} else if (isOccupied(val, U, D, L) && isEmpty(val, UL, R, DL)) {
return 39;
} else if (isOccupied(val, L, D, R) && isEmpty(val, DL, DR, U)) {
return 40;
} else if (isOccupied(val, L, U, R) && isEmpty(val, UL, UR, D)) {
return 43;
}
case 2:
if (isOccupied(val, L, R) && isEmpty(val, U, D)) {
return 8;
} else if (isOccupied(val, U, D) && isEmpty(val, L, R)) {
return 16;
} else if (isOccupied(val, R, D) && isEmpty(val, DR, U, L)) {
return 20;
} else if (isOccupied(val, U, R) && isEmpty(val, UR, D, L)) {
return 23;
} else if (isOccupied(val, L, U) && isEmpty(val, UL, R, D)) {
return 38;
} else if (isOccupied(val, L, D) && isEmpty(val, DL, U, R)) {
return 35;
}
case 1:
if (isOccupied(val, R) && isEmpty(val, U, D, L)) {
return 3;
} else if (isOccupied(val, L) && isEmpty(val, U, R, D)) {
return 13;
} else if (isOccupied(val, D) && isEmpty(val, L, U, R)) {
return 15;
} else if (isOccupied(val, U) && isEmpty(val, L, D, R)) {
return 17;
}
case 0:
return 18;
}
// default
return 54;
}
}
@@ -5,6 +5,7 @@ import java.util.stream.StreamSupport;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import games.rednblack.editor.plugin.tiled.data.AutoTileVO;
import games.rednblack.editor.plugin.tiled.data.ParameterVO;
import games.rednblack.editor.plugin.tiled.data.TileVO;
@@ -14,10 +15,12 @@ import games.rednblack.editor.plugin.tiled.data.TileVO;
public class DataToSave {
private Array<TileVO> tiles;
private Array<AutoTileVO> autoTiles;
private ParameterVO parameterVO;
public DataToSave() {
tiles = new Array<>();
autoTiles = new Array<>();
parameterVO = new ParameterVO();
}
@@ -75,6 +78,38 @@ public class DataToSave {
return StreamSupport.stream(tiles.spliterator(), false).anyMatch(tile -> tile.regionName.equals(regionName));
}
public void addAutoTile(String autoTileDrawableName, int type) {
AutoTileVO newTile = new AutoTileVO(autoTileDrawableName);
newTile.entityType = type;
if (!autoTiles.contains(newTile, false)) {
autoTiles.add(newTile);
}
}
public AutoTileVO getAutoTile(String regionName) {
return StreamSupport.stream(autoTiles.spliterator(), false)
.filter(tile -> tile.regionName.equals(regionName))
.findFirst()
.get();
}
public void removeAutoTile(String tileDrawableName) {
autoTiles.forEach(tile -> {
if (tile.regionName.equals(tileDrawableName)) {
autoTiles.removeValue(tile, false);
}
});
}
public Array<AutoTileVO> getAutoTiles() {
return autoTiles;
}
public boolean containsAutoTile(String regionName) {
return StreamSupport.stream(autoTiles.spliterator(), false).anyMatch(tile -> tile.regionName.equals(regionName));
}
public ParameterVO getParameterVO() {
return parameterVO;
}
@@ -1,17 +1,19 @@
package games.rednblack.editor.plugin.tiled.tools;
import java.util.HashSet;
import java.util.Set;
import org.puremvc.java.interfaces.INotification;
import com.badlogic.ashley.core.Entity;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import games.rednblack.editor.plugin.tiled.TiledPlugin;
import games.rednblack.h2d.common.MsgAPI;
import games.rednblack.h2d.common.view.tools.Tool;
import games.rednblack.h2d.common.vo.CursorData;
import org.puremvc.java.interfaces.INotification;
import java.util.HashSet;
import java.util.Set;
/**
* Created by mariam on 4/5/16.
@@ -51,6 +53,7 @@ public class DeleteTileTool implements Tool {
@Override
public void stageMouseUp(float x, float y) {
tiledPlugin.facade.sendNotification(TiledPlugin.AUTO_FILL_TILES);
}
@Override
@@ -71,12 +74,13 @@ public class DeleteTileTool implements Tool {
@Override
public boolean itemMouseDown(Entity entity, float x, float y) {
deleteEntityWithCoordinate(x, y);
tiledPlugin.facade.sendNotification(TiledPlugin.AUTO_FILL_TILES);
return true;
}
@Override
public void itemMouseUp(Entity entity, float x, float y) {
tiledPlugin.facade.sendNotification(TiledPlugin.AUTO_FILL_TILES);
}
@Override
@@ -1,24 +1,26 @@
package games.rednblack.editor.plugin.tiled.tools;
import org.puremvc.java.interfaces.INotification;
import com.badlogic.ashley.core.Entity;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.MathUtils;
import com.kotcrab.vis.ui.util.OsUtils;
import games.rednblack.editor.plugin.tiled.TiledPlugin;
import games.rednblack.editor.plugin.tiled.tools.drawStrategy.AutoTileDrawStrategy;
import games.rednblack.editor.plugin.tiled.tools.drawStrategy.IDrawStrategy;
import games.rednblack.editor.plugin.tiled.tools.drawStrategy.ImageDrawStrategy;
import games.rednblack.editor.plugin.tiled.tools.drawStrategy.SpineDrawStrategy;
import games.rednblack.editor.plugin.tiled.tools.drawStrategy.SpriteDrawStrategy;
import games.rednblack.editor.renderer.components.TextureRegionComponent;
import games.rednblack.editor.renderer.components.TransformComponent;
import games.rednblack.editor.renderer.factory.EntityFactory;
import games.rednblack.editor.renderer.utils.ComponentRetriever;
import games.rednblack.h2d.common.command.TransformCommandBuilder;
import games.rednblack.h2d.common.view.tools.Tool;
import games.rednblack.h2d.common.vo.CursorData;
import org.puremvc.java.interfaces.INotification;
/**
* Created by mariam on 3/29/16.
@@ -34,6 +36,7 @@ public class DrawTileTool implements Tool {
private final ImageDrawStrategy imageDrawStrategy;
private final SpriteDrawStrategy spriteDrawStrategy;
private final SpineDrawStrategy spineDrawStrategy;
private final AutoTileDrawStrategy autoTileDrawStrategy;
private IDrawStrategy currentDrawStrategy;
public DrawTileTool(TiledPlugin tiledPlugin) {
@@ -41,6 +44,7 @@ public class DrawTileTool implements Tool {
imageDrawStrategy = new ImageDrawStrategy(tiledPlugin);
spriteDrawStrategy = new SpriteDrawStrategy(tiledPlugin);
spineDrawStrategy = new SpineDrawStrategy(tiledPlugin);
autoTileDrawStrategy = new AutoTileDrawStrategy(tiledPlugin);
}
@Override
@@ -68,6 +72,7 @@ public class DrawTileTool implements Tool {
@Override
public void stageMouseUp(float x, float y) {
tiledPlugin.facade.sendNotification(TiledPlugin.AUTO_FILL_TILES);
}
@Override
@@ -97,6 +102,7 @@ public class DrawTileTool implements Tool {
@Override
public void itemMouseUp(Entity entity, float x, float y) {
tiledPlugin.facade.sendNotification(TiledPlugin.AUTO_FILL_TILES);
}
@Override
@@ -154,19 +160,23 @@ public class DrawTileTool implements Tool {
}
private void chooseDrawStrategy() {
switch (tiledPlugin.getSelectedTileType()) {
case EntityFactory.IMAGE_TYPE:
currentDrawStrategy = imageDrawStrategy;
break;
case EntityFactory.SPRITE_TYPE:
currentDrawStrategy = spriteDrawStrategy;
break;
case EntityFactory.SPINE_TYPE:
currentDrawStrategy = spineDrawStrategy;
break;
default:
currentDrawStrategy = null;
}
if (tiledPlugin.isAutoGridTilesTabSelected()) {
currentDrawStrategy = autoTileDrawStrategy;
} else {
switch (tiledPlugin.getSelectedTileType()) {
case EntityFactory.IMAGE_TYPE:
currentDrawStrategy = imageDrawStrategy;
break;
case EntityFactory.SPRITE_TYPE:
currentDrawStrategy = spriteDrawStrategy;
break;
case EntityFactory.SPINE_TYPE:
currentDrawStrategy = spineDrawStrategy;
break;
default:
currentDrawStrategy = null;
}
}
}
private void drawTile(float x, float y) {
@@ -0,0 +1,106 @@
package games.rednblack.editor.plugin.tiled.tools.drawStrategy;
import com.badlogic.ashley.core.Entity;
import games.rednblack.editor.plugin.tiled.TiledPlugin;
import games.rednblack.editor.plugin.tiled.data.AutoTileVO;
import games.rednblack.editor.renderer.components.MainItemComponent;
import games.rednblack.editor.renderer.components.TextureRegionComponent;
import games.rednblack.editor.renderer.utils.ComponentRetriever;
import games.rednblack.h2d.common.command.ReplaceRegionCommandBuilder;
import games.rednblack.h2d.common.factory.IFactory;
public class AutoTileDrawStrategy extends BasicDrawStrategy {
private final ReplaceRegionCommandBuilder replaceRegionCommandBuilder = new ReplaceRegionCommandBuilder();
private String tileToDraw;
public AutoTileDrawStrategy(TiledPlugin plugin) {
super(plugin);
}
@Override
public void drawTile(float x, float y, int row, int column) {
Entity underneathTile = tiledPlugin.getPluginEntityWithParams(row, column);
if (underneathTile != null) {
updateTile(underneathTile);
return;
}
IFactory itemFactory = tiledPlugin.getAPI().getItemFactory();
temp.set(x, y);
tileToDraw = selectTileToDraw();
if (itemFactory.createSimpleImage(tileToDraw + TiledPlugin.AUTO_TILE_DRAW_SUFFIX, temp)) {
Entity imageEntity = itemFactory.getCreatedEntity();
postProcessEntity(imageEntity, x, y, row, column);
}
}
private String selectTileToDraw() {
String retval;
AutoTileVO selectedAutoTileVO = tiledPlugin.getSelectedAutoTileVO();
if (selectedAutoTileVO.alternativeAutoTileList.isEmpty()) {
retval = selectedAutoTileVO.regionName;
} else {
retval = null;
double d = 0d;
double rnd = Math.random();
int i = 0;
while (i < selectedAutoTileVO.alternativeAutoTileList.size() && retval == null) {
d += selectedAutoTileVO.alternativeAutoTileList.get(i).percent;
if (rnd < d) {
retval = selectedAutoTileVO.alternativeAutoTileList.get(i).region;
}
i++;
}
if (retval == null) {
retval = selectedAutoTileVO.alternativeAutoTileList.get(i - 1).region;
}
}
return retval;
}
@Override
public void updateTile(Entity entity) {
if (!checkValidTile(entity)) return;
MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class);
if (tiledPlugin.getSelectedAutoTileName().equals(mainItemComponent.customVariables.getStringVariable(TiledPlugin.ORIG_AUTO_TILE))) {
// we only allow an update when the auto-tiles is different
// firstly, it does not make any sense to randomly reselect another alternative tile
// secondly, when dragging it constantly reselects between the alternative, making rare tiles even rarer
return;
}
TextureRegionComponent textureRegionComponent = ComponentRetriever.get(entity, TextureRegionComponent.class);
if (textureRegionComponent != null && textureRegionComponent.regionName != null) {
// there is already other tile under this one
String selectedAutoTileName = selectTileToDraw();
String region = selectedAutoTileName + TiledPlugin.AUTO_TILE_DRAW_SUFFIX;
if (!textureRegionComponent.regionName.equals(region)) {
replaceRegionCommandBuilder.begin(entity);
replaceRegionCommandBuilder.setRegion(tiledPlugin.getAPI().getSceneLoader().getRm().getTextureRegion(region));
replaceRegionCommandBuilder.setRegionName(region);
replaceRegionCommandBuilder.execute(tiledPlugin.facade);
mainItemComponent.tags.add(TiledPlugin.AUTO_TILE_TAG);
mainItemComponent.setCustomVars(TiledPlugin.REGION, selectedAutoTileName);
mainItemComponent.setCustomVars(TiledPlugin.ORIG_AUTO_TILE, tiledPlugin.getSelectedAutoTileName());
}
}
}
@Override
protected void postProcessEntity(Entity entity, float x, float y, int row, int column) {
super.postProcessEntity(entity, x, y, row, column);
MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class);
mainItemComponent.tags.add(TiledPlugin.AUTO_TILE_TAG);
mainItemComponent.setCustomVars(TiledPlugin.REGION, tileToDraw);
mainItemComponent.setCustomVars(TiledPlugin.ORIG_AUTO_TILE, tiledPlugin.getSelectedAutoTileName());
}
}
@@ -1,7 +1,9 @@
package games.rednblack.editor.plugin.tiled.tools.drawStrategy;
import com.badlogic.ashley.core.Entity;
import games.rednblack.editor.plugin.tiled.TiledPlugin;
import games.rednblack.editor.renderer.components.MainItemComponent;
import games.rednblack.editor.renderer.components.TextureRegionComponent;
import games.rednblack.editor.renderer.utils.ComponentRetriever;
import games.rednblack.h2d.common.command.ReplaceRegionCommandBuilder;
@@ -43,6 +45,10 @@ public class ImageDrawStrategy extends BasicDrawStrategy {
replaceRegionCommandBuilder.setRegion(tiledPlugin.getAPI().getSceneLoader().getRm().getTextureRegion(region));
replaceRegionCommandBuilder.setRegionName(region);
replaceRegionCommandBuilder.execute(tiledPlugin.facade);
MainItemComponent mainItemComponent = ComponentRetriever.get(entity, MainItemComponent.class);
mainItemComponent.tags.remove(TiledPlugin.AUTO_TILE_TAG);
mainItemComponent.removeCustomVars(TiledPlugin.REGION);
}
}
}
@@ -0,0 +1,187 @@
package games.rednblack.editor.plugin.tiled.view.dialog;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.SelectBox;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Align;
import com.kotcrab.vis.ui.util.Validators.FloatValidator;
import com.kotcrab.vis.ui.widget.VisImageButton;
import com.kotcrab.vis.ui.widget.VisSelectBox;
import com.kotcrab.vis.ui.widget.VisTable;
import com.kotcrab.vis.ui.widget.VisTextButton;
import com.kotcrab.vis.ui.widget.VisValidatableTextField;
import games.rednblack.editor.plugin.tiled.TiledPlugin;
import games.rednblack.editor.plugin.tiled.data.AlternativeAutoTileVO;
import games.rednblack.editor.plugin.tiled.data.AutoTileVO;
import games.rednblack.editor.renderer.factory.EntityFactory;
import games.rednblack.h2d.common.UIDraggablePanel;
import games.rednblack.h2d.common.view.ui.StandardWidgetsFactory;
/**
* The dialog that handles the alternatives.
*
* @author Jan-Thierry Wegener
*/
public class AlternativeAutoTileDialog extends UIDraggablePanel {
public AutoTileVO openingAutoTileVO;
private TiledPlugin tiledPlugin;
public VisSelectBox<String>[] alternativeSelectBoxArray;
public VisValidatableTextField[] alternativePercentTextFieldArray;
public AlternativeAutoTileDialog(TiledPlugin tiledPlugin) {
super("Setup alternatives");
this.tiledPlugin = tiledPlugin;
}
/**
* Initiates the view of the dialog.
*/
public void initView() {
clear();
String[] allAutoTileVOArray = new String[tiledPlugin.dataToSave.getAutoTiles().size];
int index = 0;
// add a "none" to the drop down list
allAutoTileVOArray[index++] = "";
for (int i = 0; i < tiledPlugin.dataToSave.getAutoTiles().size; i++) {
AutoTileVO next = tiledPlugin.dataToSave.getAutoTiles().get(i);
if (!openingAutoTileVO.equals(next)) {
allAutoTileVOArray[index++] = next.regionName;
}
}
alternativeSelectBoxArray = new VisSelectBox[allAutoTileVOArray.length - 1];
alternativePercentTextFieldArray = new VisValidatableTextField[allAutoTileVOArray.length + 0];
VisTable table = new VisTable();
table.row().padTop(20);
table.add(getVisImageButton(openingAutoTileVO.regionName)).maxHeight(32);
table.add(StandardWidgetsFactory.createLabel(openingAutoTileVO.regionName, Align.left)).padLeft(5).left();//.width(115);
alternativePercentTextFieldArray[0] = StandardWidgetsFactory.createValidableTextField(new FloatValidator());
alternativePercentTextFieldArray[0].setText(openingAutoTileVO.alternativeAutoTileList.get(0, new AlternativeAutoTileVO()).percent.toString());
table.add(alternativePercentTextFieldArray[0]).padLeft(5).padRight(5).fillX().left();
table.row();
for (int i = 0; i < allAutoTileVOArray.length - 1; i++) {
String region = openingAutoTileVO.alternativeAutoTileList.get(i + 1, new AlternativeAutoTileVO()).region;
VisImageButton imgButton = getVisImageButton(region);
table.add(imgButton).maxHeight(32);
alternativeSelectBoxArray[i] = StandardWidgetsFactory.createSelectBox(String.class);
alternativeSelectBoxArray[i].setItems(allAutoTileVOArray);
alternativeSelectBoxArray[i].setSelected(openingAutoTileVO.alternativeAutoTileList.get(i + 1, new AlternativeAutoTileVO()).region);
alternativeSelectBoxArray[i].addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
updateVisImageButton(imgButton, ((SelectBox<String>) actor).getSelected());
pack();
}
});
table.add(alternativeSelectBoxArray[i]).padLeft(5).left();
alternativePercentTextFieldArray[i + 1] = StandardWidgetsFactory.createValidableTextField(new FloatValidator());
alternativePercentTextFieldArray[i + 1].setText(openingAutoTileVO.alternativeAutoTileList.get(i + 1, new AlternativeAutoTileVO()).percent.toString());
table.add(alternativePercentTextFieldArray[i + 1]).padLeft(5).padRight(5).fillX().left();
table.row().padTop(5).padBottom(5);
}
VisTextButton saveButton = StandardWidgetsFactory.createTextButton("Save");
saveButton.addListener(new ClickListener() {
@Override
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
tiledPlugin.facade.sendNotification(TiledPlugin.ACTION_SAVE_ALTERNATIVES_AUTO_TILE);
hide();
}
});
VisTextButton cancelButton = StandardWidgetsFactory.createTextButton("Cancel");
cancelButton.addListener(new ClickListener() {
@Override
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
hide();
}
});
row();
add(table);
row();
add(saveButton).center().padLeft(5).padRight(5);
add(cancelButton).center().padLeft(5).padRight(5);
row();
pack();
}
/**
* Returns a button with the given region as image.
*
* @param regionName The name of the image.
*
* @return An image button.
*/
private VisImageButton getVisImageButton(String regionName) {
VisImageButton.VisImageButtonStyle imageBoxStyle = new VisImageButton.VisImageButtonStyle();
Drawable tileDrawable = null;
if (!"".equals(regionName)) {
tileDrawable = new TextureRegionDrawable(tiledPlugin.pluginRM.getTextureRegion(regionName, EntityFactory.IMAGE_TYPE));
}
imageBoxStyle.imageUp = tileDrawable;
imageBoxStyle.imageDown = tileDrawable;
imageBoxStyle.imageChecked = tileDrawable;
imageBoxStyle.imageOver = tileDrawable;
VisImageButton ct = new VisImageButton(imageBoxStyle);
return ct;
}
/**
* Updates the given button with the given image.
*
* @param button The button to update.
* @param regionName The name of the new image.
*/
private void updateVisImageButton(VisImageButton button, String regionName) {
VisImageButton.VisImageButtonStyle imageBoxStyle = button.getStyle();
Drawable tileDrawable = null;
if (!"".equals(regionName)) {
tileDrawable = new TextureRegionDrawable(tiledPlugin.pluginRM.getTextureRegion(regionName, EntityFactory.IMAGE_TYPE));
}
imageBoxStyle.imageUp = tileDrawable;
imageBoxStyle.imageDown = tileDrawable;
imageBoxStyle.imageChecked = tileDrawable;
imageBoxStyle.imageOver = tileDrawable;
button.setStyle(imageBoxStyle);
}
/**
* Returns the currently set auto-tile.
*
* @return The currently set auto-tile.
*/
public AutoTileVO getOpeningAutoTileVO() {
return openingAutoTileVO;
}
/**
* Sets the current auto-tile.
*
* @param openingAutoTileVO The new auto-tile.
*/
public void setOpeningAutoTileVO(AutoTileVO openingAutoTileVO) {
this.openingAutoTileVO = openingAutoTileVO;
}
}
@@ -0,0 +1,99 @@
package games.rednblack.editor.plugin.tiled.view.dialog;
import org.puremvc.java.interfaces.INotification;
import org.puremvc.java.patterns.mediator.Mediator;
import games.rednblack.editor.plugin.tiled.TiledPlugin;
import games.rednblack.editor.plugin.tiled.data.AlternativeAutoTileVO;
import games.rednblack.editor.plugin.tiled.data.AutoTileVO;
/**
* The mediator for messages for the alternatives.
*
* @author Jan-Thierry Wegener
*/
public class AlternativeAutoTileDialogMediator extends Mediator<AlternativeAutoTileDialog> {
public static final String NAME = AlternativeAutoTileDialogMediator.class.getName();
private TiledPlugin tiledPlugin;
public AlternativeAutoTileDialogMediator(TiledPlugin tiledPlugin) {
super(NAME, new AlternativeAutoTileDialog(tiledPlugin));
this.tiledPlugin = tiledPlugin;
}
@Override
public String[] listNotificationInterests() {
return new String[] {
TiledPlugin.ACTION_SETUP_ALTERNATIVES_AUTO_TILE,
TiledPlugin.ACTION_SAVE_ALTERNATIVES_AUTO_TILE,
TiledPlugin.ACTION_RECALC_PERCENT_ALTERNATIVES_AUTO_TILE
};
}
@Override
public void handleNotification(INotification notification) {
switch (notification.getName()) {
case TiledPlugin.ACTION_SETUP_ALTERNATIVES_AUTO_TILE:
AutoTileVO autoTileVO = tiledPlugin.dataToSave.getAutoTile(notification.getBody());
viewComponent.setOpeningAutoTileVO(autoTileVO);
viewComponent.initView();
viewComponent.show(tiledPlugin.getAPI().getUIStage());
break;
case TiledPlugin.ACTION_SAVE_ALTERNATIVES_AUTO_TILE:
viewComponent.openingAutoTileVO.alternativeAutoTileList.clear();
AlternativeAutoTileVO alternativeAutoTileVO = new AlternativeAutoTileVO(viewComponent.openingAutoTileVO.regionName, viewComponent.alternativePercentTextFieldArray[0].getText());
viewComponent.openingAutoTileVO.alternativeAutoTileList.add(alternativeAutoTileVO);
for (int i = 0; i < viewComponent.alternativeSelectBoxArray.length; i++) {
String region = viewComponent.alternativeSelectBoxArray[i].getSelected();
Float percent = Float.valueOf(viewComponent.alternativePercentTextFieldArray[i + 1].getText());
viewComponent.openingAutoTileVO.alternativeAutoTileList.add(new AlternativeAutoTileVO(region, percent));
}
tiledPlugin.facade.sendNotification(TiledPlugin.ACTION_RECALC_PERCENT_ALTERNATIVES_AUTO_TILE, viewComponent.openingAutoTileVO.regionName);
break;
case TiledPlugin.ACTION_RECALC_PERCENT_ALTERNATIVES_AUTO_TILE:
String deletedAutoTileRegion = notification.getBody();
if (deletedAutoTileRegion == null) {
for (AutoTileVO at : tiledPlugin.dataToSave.getAutoTiles()) {
recalculatePercent(at);
}
} else {
recalculatePercent(tiledPlugin.dataToSave.getAutoTile(deletedAutoTileRegion));
}
tiledPlugin.saveDataManager.save();
break;
}
}
/**
* Recalculates the probabilities of the alternatives of all or the given auto-tile.
*
* @param at The auto-tile to recalculate, or if <code>null</code> then all auto-tiles.
*/
private void recalculatePercent(AutoTileVO at) {
float total = 0;
for (AlternativeAutoTileVO aat : at.alternativeAutoTileList) {
if (!"".equals(aat.region)) {
total += Math.abs(aat.percent);
}
}
if (total < 0.00001f) {
// kind of 0
at.alternativeAutoTileList.get(0).percent = 1f;
} else {
for (AlternativeAutoTileVO aat : at.alternativeAutoTileList) {
if ("".equals(aat.region)) {
aat.percent = 0f;
} else {
aat.percent = Math.abs(aat.percent) / total;
}
}
}
}
}
@@ -0,0 +1,241 @@
package games.rednblack.editor.plugin.tiled.view.tabs;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Array;
import com.kotcrab.vis.ui.widget.VisImageButton;
import com.kotcrab.vis.ui.widget.VisLabel;
import com.kotcrab.vis.ui.widget.VisScrollPane;
import com.kotcrab.vis.ui.widget.VisTable;
import games.rednblack.editor.plugin.tiled.TiledPanel;
import games.rednblack.editor.plugin.tiled.TiledPlugin;
import games.rednblack.editor.plugin.tiled.data.TextureRegionVO;
import games.rednblack.editor.plugin.tiled.manager.ResourcesManager;
import games.rednblack.editor.plugin.tiled.view.SpineDrawable;
import games.rednblack.editor.plugin.tiled.view.tabs.listener.GridTabInputListener;
import games.rednblack.editor.renderer.factory.EntityFactory;
import games.rednblack.h2d.common.view.ui.StandardWidgetsFactory;
public abstract class AbstractGridTilesTab<T extends TextureRegionVO> extends DefaultTab {
public boolean isDrop;
private int tilesCount = 19;
protected Array<VisImageButton> tiles;
protected Array<T> savedTiles;
private int tileIndex;
protected VisScrollPane pane;
private boolean isBottomEdge;
protected TiledPlugin tiledPlugin;
private ResourcesManager resourcesManager;
public AbstractGridTilesTab(TiledPanel panel, String title, int tabIndex) {
super(panel, title, tabIndex);
tiledPlugin = panel.tiledPlugin;
resourcesManager = tiledPlugin.pluginRM;
tiles = new Array<>();
savedTiles = initSavedTiles();
tileIndex = savedTiles.size;
}
protected abstract Array<T> initSavedTiles();
@Override
public void initView() {
if (isDrop = savedTiles.size == 0) {
VisImageButton.VisImageButtonStyle dropBoxStyle = new VisImageButton.VisImageButtonStyle();
dropBoxStyle.up = new TextureRegionDrawable(resourcesManager.getTextureRegion("tiles-drop-here-normal", -1));
dropBoxStyle.imageOver = new TextureRegionDrawable(resourcesManager.getTextureRegion("tiles-drop-here-over", -1));
VisImageButton dropRegion = new VisImageButton(dropBoxStyle);
content.clear();
content.add(dropRegion)
.center()
.padRight(6)
.padBottom(6)
.padTop(10)
.row();
content.add(new VisLabel("Drop an image from resources box"))
.expandX()
.center()
.padBottom(5);
content.pack();
} else {
if (tileIndex > tilesCount) {
tilesCount = tileIndex;
}
initTiles();
}
}
public void addTile(String tileName, int type) {
if (pane != null) isBottomEdge = pane.isBottomEdge();
if (tileIndex == 0) {
setGridSizeToFirstTileSize(tileName, type);
isDrop = false;
panel.reInitTabTable(this);
}
initTiles(tileName, type);
panel.pack();
scrollTiles();
tiles.get(tileIndex).setChecked(true);
tiledPlugin.facade.sendNotification(TiledPlugin.TILE_SELECTED, getTextureRegionVO(tileName));
tileIndex++;
}
public void removeTile() {
if (pane != null) isBottomEdge = pane.isBottomEdge();
tileIndex = --tileIndex < 0 ? 0 : tileIndex;
tilesCount = --tilesCount < 19 ? 19 : tilesCount;
tiles.clear();
initView();
}
public void removeAllTiles() {
if (pane != null) isBottomEdge = pane.isBottomEdge();
tileIndex = 0;
tilesCount = 19;
tiles.clear();
initView();
}
public void scrollTiles() {
if(savedTiles.size + 1 >= tilesCount) {
pane.layout();
pane.setSmoothScrolling(!isBottomEdge);
pane.setScrollY(100);
}
}
protected void setGridSizeToFirstTileSize(String tileName, int type) {
float width = 0;
float height = 0;
if (type == EntityFactory.SPINE_TYPE) {
SpineDrawable spineDrawable = tiledPlugin.pluginRM.getSpineDrawable(tileName);
width = spineDrawable.width;
height = spineDrawable.height;
} else {
TextureRegion r = tiledPlugin.pluginRM.getTextureRegion(tileName, type);
width = r.getRegionWidth();
height = r.getRegionHeight();
}
float gridWidth = width / tiledPlugin.getPixelToWorld();
float gridHeight = height / tiledPlugin.getPixelToWorld();
tiledPlugin.dataToSave.setGrid(gridWidth, gridHeight);
tiledPlugin.facade.sendNotification(TiledPlugin.GRID_CHANGED);
}
private void initTiles(String tileName, int type) {
content.clear();
tiles.clear();
VisTable listTable = new VisTable();
pane = StandardWidgetsFactory.createScrollPane(listTable);
pane.setScrollingDisabled(true, false);
content.add(pane)
.padTop(10);
listTable.top();
if(tileIndex >= tilesCount && !tileName.equals("")) {
tilesCount = tileIndex + 1;
}
for (int i = 0; i < tilesCount + 1; i++) {
VisImageButton ct;
VisImageButton.VisImageButtonStyle imageBoxStyle = new VisImageButton.VisImageButtonStyle();
NinePatchDrawable inactive = new NinePatchDrawable(new NinePatch(resourcesManager.getPluginNinePatch("image-Box-inactive")));
NinePatchDrawable active = new NinePatchDrawable(new NinePatch(resourcesManager.getPluginNinePatch("image-Box-active")));
imageBoxStyle.up = inactive;
imageBoxStyle.down = active;
imageBoxStyle.checked = active;
imageBoxStyle.over = active;
Drawable tileDrawable = null;
if (i < savedTiles.size) {
int t = savedTiles.get(i).getEntityType();
if (t == EntityFactory.SPINE_TYPE) {
tileDrawable = resourcesManager.getSpineDrawable(savedTiles.get(i).getRegionName());
} else {
tileDrawable = new TextureRegionDrawable(resourcesManager.getTextureRegion(savedTiles.get(i).getRegionName(), t));
}
} else if (!tileName.equals("")) {
if (i == tileIndex) {
if (type == EntityFactory.SPINE_TYPE) {
tileDrawable = resourcesManager.getSpineDrawable(tileName);
} else {
tileDrawable = new TextureRegionDrawable(resourcesManager.getTextureRegion(tileName, type));
}
}
}
imageBoxStyle.imageUp = tileDrawable;
imageBoxStyle.imageDown = tileDrawable;
imageBoxStyle.imageChecked = tileDrawable;
imageBoxStyle.imageOver = tileDrawable;
ct = new VisImageButton(imageBoxStyle);
if (i < savedTiles.size) {
ct.setUserObject(savedTiles.get(i).getRegionName());
}
int index = i;
ct.addListener(getGridTabInputListener(index));
listTable.add(ct)
.width(40)
.height(40)
.pad(3);
if((i+1) % 4 == 0) {
listTable.row();
}
tiles.add(ct);
}
content.pack();
}
public void initTiles() {
initTiles("", -1);
}
/**
* Returns the newly initialized input listener for the given tile index.
*
* @param index The index of the tile.
*
* @return The new input listener.
*/
protected abstract GridTabInputListener<T> getGridTabInputListener(int index);
/**
* Returns the notification string to send when selecting a tile.
*
* @return The notification when selecting a tile.
*/
protected abstract String getTileSelectedNotification();
/**
* Returns the notification string to send when opening a drop down.
*
* @return The notification when opening a drop down.
*/
protected abstract String getTiledOpenDropDownNotification();
/**
* Selects the given tile.
*
* @param tileVO The tile to select
*/
public abstract void selectTile(T tileVO);
/**
* Returns the corresponding {@link TextureRegionVO} for the given tile name.
*
* @param tileName The tilename for the texture region.
*
* @return The texture region.
*/
protected abstract T getTextureRegionVO(String tileName);
}
@@ -0,0 +1,52 @@
package games.rednblack.editor.plugin.tiled.view.tabs;
import com.badlogic.gdx.utils.Array;
import com.kotcrab.vis.ui.widget.VisTable;
import games.rednblack.editor.plugin.tiled.TiledPanel;
import games.rednblack.editor.plugin.tiled.TiledPlugin;
import games.rednblack.editor.plugin.tiled.data.AutoTileVO;
import games.rednblack.editor.plugin.tiled.view.tabs.listener.GridTabInputListener;
public class AutoGridTilesTab extends AbstractGridTilesTab<AutoTileVO> {
public AutoGridTilesTab(TiledPanel panel, String tabTitle, int tabIndex) {
super(panel, tabTitle, tabIndex);
}
@Override
protected GridTabInputListener<AutoTileVO> getGridTabInputListener(int index) {
return new GridTabInputListener<AutoTileVO>(this, index, tiledPlugin, (VisTable) pane.getActor(), getTileSelectedNotification(), getTiledOpenDropDownNotification(), savedTiles, tiles);
}
@Override
protected Array<AutoTileVO> initSavedTiles() {
return tiledPlugin.dataToSave.getAutoTiles();
}
@Override
protected String getTileSelectedNotification() {
return TiledPlugin.AUTO_TILE_SELECTED;
}
@Override
protected String getTiledOpenDropDownNotification() {
return TiledPlugin.AUTO_OPEN_DROP_DOWN;
}
@Override
public void selectTile(AutoTileVO tileVO) {
tiledPlugin.setSelectedAutoTileVO(tileVO);
}
@Override
protected void setGridSizeToFirstTileSize(String tileName, int type) {
super.setGridSizeToFirstTileSize(tileName + TiledPlugin.AUTO_TILE_MINI_SUFFIX, type);
}
@Override
protected AutoTileVO getTextureRegionVO(String tileName) {
return new AutoTileVO(tileName);
}
}
@@ -1,306 +1,50 @@
package games.rednblack.editor.plugin.tiled.view.tabs;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.scenes.scene2d.utils.NinePatchDrawable;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Array;
import com.kotcrab.vis.ui.widget.VisImageButton;
import com.kotcrab.vis.ui.widget.VisLabel;
import com.kotcrab.vis.ui.widget.VisScrollPane;
import com.kotcrab.vis.ui.widget.VisTable;
import games.rednblack.editor.plugin.tiled.TiledPanel;
import games.rednblack.editor.plugin.tiled.TiledPlugin;
import games.rednblack.editor.plugin.tiled.data.TileVO;
import games.rednblack.editor.plugin.tiled.manager.ResourcesManager;
import games.rednblack.editor.plugin.tiled.view.SpineDrawable;
import games.rednblack.editor.renderer.factory.EntityFactory;
import games.rednblack.h2d.common.view.ui.StandardWidgetsFactory;
import games.rednblack.editor.plugin.tiled.view.tabs.listener.GridTabInputListener;
/**
* Created by mariam on 2/11/16.
*/
public class GridTilesTab extends DefaultTab {
public static boolean isDrop;
private int tilesCount = 19;
private Array<VisImageButton> tiles;
private Array<TileVO> savedTiles;
private int tileIndex;
private VisScrollPane pane;
private boolean isBottomEdge;
private TiledPlugin tiledPlugin;
private ResourcesManager resourcesManager;
public class GridTilesTab extends AbstractGridTilesTab<TileVO> {
public GridTilesTab(TiledPanel panel, int tabIndex) {
super(panel, "Tiles", tabIndex);
tiledPlugin = panel.tiledPlugin;
resourcesManager = tiledPlugin.pluginRM;
tiles = new Array<>();
savedTiles = tiledPlugin.dataToSave.getTiles();
tileIndex = savedTiles.size;
super(panel, "Tiles", tabIndex);
}
@Override
public void initView() {
if (isDrop = savedTiles.size == 0) {
VisImageButton.VisImageButtonStyle dropBoxStyle = new VisImageButton.VisImageButtonStyle();
dropBoxStyle.up = new TextureRegionDrawable(resourcesManager.getTextureRegion("tiles-drop-here-normal", -1));
dropBoxStyle.imageOver = new TextureRegionDrawable(resourcesManager.getTextureRegion("tiles-drop-here-over", -1));
VisImageButton dropRegion = new VisImageButton(dropBoxStyle);
content.clear();
content.add(dropRegion)
.center()
.padRight(6)
.padBottom(6)
.padTop(10)
.row();
content.add(new VisLabel("Drop an image from resources box"))
.expandX()
.center()
.padBottom(5);
content.pack();
} else {
if (tileIndex > tilesCount) {
tilesCount = tileIndex;
}
initTiles();
}
protected Array<TileVO> initSavedTiles() {
return tiledPlugin.dataToSave.getTiles();
}
public void addTile(String tileName, int type) {
if (pane != null) isBottomEdge = pane.isBottomEdge();
if (tileIndex == 0) {
setGridSizeToFirstTileSize(tileName, type);
isDrop = false;
panel.reInitTabTable();
}
initTiles(tileName, type);
panel.pack();
scrollTiles();
tiles.get(tileIndex).setChecked(true);
tiledPlugin.facade.sendNotification(TiledPlugin.TILE_SELECTED, new TileVO(tileName));
tileIndex++;
@Override
protected GridTabInputListener<TileVO> getGridTabInputListener(int index) {
return new GridTabInputListener<TileVO>(this, index, tiledPlugin, (VisTable) pane.getActor(), getTileSelectedNotification(), getTiledOpenDropDownNotification(), savedTiles, tiles);
}
public void selectTile(TileVO tileVO) {
@Override
protected String getTileSelectedNotification() {
return TiledPlugin.TILE_SELECTED;
}
@Override
protected String getTiledOpenDropDownNotification() {
return TiledPlugin.OPEN_DROP_DOWN;
}
@Override
public void selectTile(TileVO tileVO) {
tiledPlugin.setSelectedTileVO(tileVO);
}
public void removeTile() {
if (pane != null) isBottomEdge = pane.isBottomEdge();
tileIndex = --tileIndex < 0 ? 0 : tileIndex;
tilesCount = --tilesCount < 19 ? 19 : tilesCount;
tiles.clear();
initView();
}
public void removeAllTiles() {
if (pane != null) isBottomEdge = pane.isBottomEdge();
tileIndex = 0;
tilesCount = 19;
tiles.clear();
initView();
}
@Override
protected TileVO getTextureRegionVO(String tileName) {
return new TileVO(tileName);
}
public void scrollTiles() {
if(savedTiles.size + 1 >= tilesCount) {
pane.layout();
pane.setSmoothScrolling(!isBottomEdge);
pane.setScrollY(100);
}
}
private void setGridSizeToFirstTileSize(String tileName, int type) {
float width = 0;
float height = 0;
if (type == EntityFactory.SPINE_TYPE) {
SpineDrawable spineDrawable = tiledPlugin.pluginRM.getSpineDrawable(tileName);
width = spineDrawable.width;
height = spineDrawable.height;
} else {
TextureRegion r = tiledPlugin.pluginRM.getTextureRegion(tileName, type);
width = r.getRegionWidth();
height = r.getRegionHeight();
}
float gridWidth = width / tiledPlugin.getPixelToWorld();
float gridHeight = height / tiledPlugin.getPixelToWorld();
tiledPlugin.dataToSave.setGrid(gridWidth, gridHeight);
tiledPlugin.facade.sendNotification(TiledPlugin.GRID_CHANGED);
}
private void initTiles(String tileName, int type) {
content.clear();
tiles.clear();
VisTable listTable = new VisTable();
pane = StandardWidgetsFactory.createScrollPane(listTable);
pane.setScrollingDisabled(true, false);
content.add(pane)
.padTop(10);
listTable.top();
if(tileIndex >= tilesCount && !tileName.equals("")) {
tilesCount = tileIndex + 1;
}
for (int i = 0; i < tilesCount + 1; i++) {
VisImageButton ct;
VisImageButton.VisImageButtonStyle imageBoxStyle = new VisImageButton.VisImageButtonStyle();
NinePatchDrawable inactive = new NinePatchDrawable(new NinePatch(resourcesManager.getPluginNinePatch("image-Box-inactive")));
NinePatchDrawable active = new NinePatchDrawable(new NinePatch(resourcesManager.getPluginNinePatch("image-Box-active")));
imageBoxStyle.up = inactive;
imageBoxStyle.down = active;
imageBoxStyle.checked = active;
imageBoxStyle.over = active;
Drawable tileDrawable = null;
if (i < savedTiles.size) {
int t = savedTiles.get(i).entityType;
if (t == EntityFactory.SPINE_TYPE) {
tileDrawable = resourcesManager.getSpineDrawable(savedTiles.get(i).regionName);
} else {
tileDrawable = new TextureRegionDrawable(resourcesManager.getTextureRegion(savedTiles.get(i).regionName, t));
}
} else if (!tileName.equals("")) {
if (i == tileIndex) {
if (type == EntityFactory.SPINE_TYPE) {
tileDrawable = resourcesManager.getSpineDrawable(tileName);
} else {
tileDrawable = new TextureRegionDrawable(resourcesManager.getTextureRegion(tileName, type));
}
}
}
imageBoxStyle.imageUp = tileDrawable;
imageBoxStyle.imageDown = tileDrawable;
imageBoxStyle.imageChecked = tileDrawable;
imageBoxStyle.imageOver = tileDrawable;
ct = new VisImageButton(imageBoxStyle);
if (i < savedTiles.size) {
ct.setUserObject(savedTiles.get(i).regionName);
}
int index = i;
ct.addListener(new InputListener() {
private boolean isDragging = false;
private Actor draggingSource;
@Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
if (button == Input.Buttons.LEFT) {
draggingSource = event.getListenerActor();
}
if (index >= savedTiles.size) return true;
for (VisImageButton tile : tiles) {
if (tile.isChecked()) {
tile.setChecked(false);
}
}
return true;
}
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
if (isDragging && button == Input.Buttons.LEFT && draggingSource != null) {
// finished dragging
isDragging = false;
handleDrop(x, y);
} else {
if(button == Input.Buttons.RIGHT && index < savedTiles.size) {
tiledPlugin.facade.sendNotification(TiledPlugin.OPEN_DROP_DOWN, savedTiles.get(index).regionName);
return;
}
if (index >= savedTiles.size) {
tiles.get(index).setChecked(false);
return;
}
tiledPlugin.facade.sendNotification(TiledPlugin.TILE_SELECTED, savedTiles.get(index));
}
}
@Override
public void touchDragged (InputEvent event, float x, float y, int pointer) {
isDragging = true;
if (draggingSource != null)
draggingSource.setColor(new Color(0 / 255f, 0 / 255f, 0f / 255f, 0.5f));
}
/**
* Handles the drop of a VisImageButton.
*
* @param x The coordinates relative to the source. Comes from the touchUp event.
* @param y The coordinates relative to the source. Comes from the touchUp event.
*/
private void handleDrop(float x, float y) {
VisTable t = (VisTable) pane.getActor();
Actor draggingTarget = t.hit(draggingSource.getX() + x, draggingSource.getY() + y, false);
if (draggingTarget instanceof Image) {
for (VisImageButton imgButton : tiles) {
if (imgButton.getImage() == draggingTarget) {
draggingTarget = imgButton;
break;
}
}
}
if (draggingTarget != null && !draggingTarget.equals(draggingSource)) {
String sourceRegionName = String.valueOf(draggingSource.getUserObject());
String targetRegionName = String.valueOf(draggingTarget.getUserObject());
int sourceIndex = -1;
int targetIndex = -1;
for (int i = 0; i < savedTiles.size; i++) {
if (sourceRegionName.equals(savedTiles.get(i).regionName)) {
sourceIndex = i;
}
if (targetRegionName.equals(savedTiles.get(i).regionName)) {
targetIndex = i;
}
}
// if targetIndex < 0 we dropped at the end
// we already know that we hit another VisImageButton but could not find the name
// thus, an empty button, which are always after the ones with an image
if (targetIndex < 0) {
targetIndex = savedTiles.size - 1;
}
if (sourceIndex >= 0) {
TileVO sourceTileVO = savedTiles.removeIndex(sourceIndex);
savedTiles.insert(targetIndex, sourceTileVO);
initTiles();
}
}
}
});
listTable.add(ct)
.width(40)
.height(40)
.pad(3);
if((i+1) % 4 == 0) {
listTable.row();
}
tiles.add(ct);
}
content.pack();
}
private void initTiles() {
initTiles("", -1);
}
}
@@ -0,0 +1,143 @@
package games.rednblack.editor.plugin.tiled.view.tabs.listener;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.utils.Array;
import com.kotcrab.vis.ui.widget.VisImageButton;
import com.kotcrab.vis.ui.widget.VisTable;
import games.rednblack.editor.plugin.tiled.TiledPlugin;
import games.rednblack.editor.plugin.tiled.data.TextureRegionVO;
import games.rednblack.editor.plugin.tiled.view.tabs.AbstractGridTilesTab;
public class GridTabInputListener<T extends TextureRegionVO> extends InputListener {
private final int index;
private AbstractGridTilesTab<T> tab;
private String tileSelectedNotification;
private String openDropDownNotification;
private TiledPlugin tiledPlugin;
private VisTable table;
private Array<VisImageButton> tiles;
private boolean isDragging = false;
private Actor draggingSource;
private Array<T> savedTiles;
public GridTabInputListener(AbstractGridTilesTab<T> tab, int index, TiledPlugin tiledPlugin, VisTable table, String tileSelectedNotification, String openDropDownNotification, Array<T> savedTiles, Array<VisImageButton> tiles) {
this.tab = tab;
this.index = index;
this.tiledPlugin = tiledPlugin;
this.tileSelectedNotification = tileSelectedNotification;
this.openDropDownNotification = openDropDownNotification;
this.table = table;
this.savedTiles = savedTiles;
this.tiles = tiles;
}
@Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
if (button == Input.Buttons.LEFT) {
draggingSource = event.getListenerActor();
}
if (index >= savedTiles.size) return true;
for (VisImageButton tile : tiles) {
if (tile.isChecked()) {
tile.setChecked(false);
}
}
return true;
}
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
if (isDragging && button == Input.Buttons.LEFT && draggingSource != null) {
// finished dragging
isDragging = false;
handleDrop(x, y);
} else {
if(button == Input.Buttons.RIGHT && index < savedTiles.size) {
tiledPlugin.facade.sendNotification(openDropDownNotification, savedTiles.get(index).getRegionName());
return;
}
if (index >= savedTiles.size) {
tiles.get(index).setChecked(false);
return;
}
tiledPlugin.facade.sendNotification(tileSelectedNotification, savedTiles.get(index));
}
}
@Override
public void touchDragged (InputEvent event, float x, float y, int pointer) {
isDragging = true;
if (draggingSource != null) {
// draggingSource can be null when dragging with the right mouse button
draggingSource.setColor(new Color(0 / 255f, 0 / 255f, 0f / 255f, 0.5f));
}
}
/**
* Handles the drop of a VisImageButton.
*
* @param x The coordinates relative to the source. Comes from the touchUp event.
* @param y The coordinates relative to the source. Comes from the touchUp event.
*/
private void handleDrop(float x, float y) {
Actor draggingTarget = table.hit(draggingSource.getX() + x, draggingSource.getY() + y, false);
if (draggingTarget instanceof Image) {
for (VisImageButton imgButton : tiles) {
if (imgButton.getImage() == draggingTarget) {
draggingTarget = imgButton;
break;
}
}
}
if (draggingTarget != null) {
String sourceRegionName = String.valueOf(draggingSource.getUserObject());
String targetRegionName = String.valueOf(draggingTarget.getUserObject());
int sourceIndex = -1;
int targetIndex = -1;
for (int i = 0; i < savedTiles.size; i++) {
if (sourceRegionName.equals(savedTiles.get(i).getRegionName())) {
sourceIndex = i;
}
if (targetRegionName.equals(savedTiles.get(i).getRegionName())) {
targetIndex = i;
}
}
// if targetIndex < 0 we dropped at the end
// we already know that we hit another VisImageButton but could not find the name
// thus, an empty button, which are always after the ones with an image
if (targetIndex < 0) {
targetIndex = savedTiles.size - 1;
}
if (sourceIndex >= 0) {
T sourceTileVO = savedTiles.removeIndex(sourceIndex);
savedTiles.insert(targetIndex, sourceTileVO);
tab.initTiles();
// select the dropped button
tiledPlugin.facade.sendNotification(TiledPlugin.TILE_SELECTED, sourceTileVO);
tiles.get(targetIndex).setChecked(true);
}
}
}
}
@@ -95,7 +95,7 @@ public class BoxItemResourceSelectionUIMediator extends Mediator<BoxItemResource
namesOrdered.addAll(nameSet.toArray(String[]::new));
namesOrdered.sort();
for (String name : namesOrdered) {
HyperLap2DFacade.getInstance().sendNotification(MsgAPI.IMAGE_BUNDLE_DROP_SINGLE, new Object[] {name, payloadBody[1]});
HyperLap2DFacade.getInstance().sendNotification(MsgAPI.IMAGE_BUNDLE_DROP_SINGLE, new Object[] {name, payloadBody[1], false});
}
break;
case UIResourcesBoxMediator.ADD_RESOURCES_BOX_TABLE_SELECTION_MANAGEMENT:
@@ -103,7 +103,6 @@ public class ImagesPackDialogMediator extends Mediator<AtlasesPackDialog> {
);
projectManager.currentProjectInfoVO.imagesPacks.remove(packToRemove);
viewComponent.updateMainPack(projectManager.currentProjectInfoVO.imagesPacks.get("main").regions);
viewComponent.updateCurrentPack(projectManager.currentProjectInfoVO.imagesPacks.get(viewComponent.getSelectedTab()).regions);
viewComponent.clearCurrentPack();
projectManager.saveCurrentProject();
break;