mirror of
https://github.com/jlengrand/korge-intellij-plugin.git
synced 2026-03-10 08:31:19 +00:00
Some tilemap editor improvements
This commit is contained in:
10
README.md
10
README.md
@@ -18,7 +18,7 @@ Download from releases:
|
|||||||
|
|
||||||
Output: `build/distributions/KorgePlugin.zip`
|
Output: `build/distributions/KorgePlugin.zip`
|
||||||
|
|
||||||
### Testing
|
### Executing from Source
|
||||||
|
|
||||||
```
|
```
|
||||||
./gradlew runIde
|
./gradlew runIde
|
||||||
@@ -26,4 +26,10 @@ Output: `build/distributions/KorgePlugin.zip`
|
|||||||
|
|
||||||
This should launch a new intelliJ Community Edition with the KorGE plugin.
|
This should launch a new intelliJ Community Edition with the KorGE plugin.
|
||||||
You can open this project with IDEA and launch the `runIde` task via debugger
|
You can open this project with IDEA and launch the `runIde` task via debugger
|
||||||
to be able to debug the plugin.
|
to be able to debug the plugin.
|
||||||
|
|
||||||
|
### Trying the Tiled Editor
|
||||||
|
|
||||||
|
```
|
||||||
|
./gradlew runDebugTilemap
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
package com.soywiz.korge.intellij.editor.tile
|
package com.soywiz.korge.intellij.editor.tile
|
||||||
|
|
||||||
|
import com.intellij.ui.components.*
|
||||||
import com.intellij.uiDesigner.core.*
|
import com.intellij.uiDesigner.core.*
|
||||||
import com.soywiz.korge.tiled.*
|
import com.soywiz.korge.tiled.*
|
||||||
import com.soywiz.korim.awt.*
|
import com.soywiz.korim.awt.*
|
||||||
import com.soywiz.korim.bitmap.*
|
import com.soywiz.korim.bitmap.*
|
||||||
|
import com.soywiz.korim.color.*
|
||||||
import com.soywiz.korio.file.std.*
|
import com.soywiz.korio.file.std.*
|
||||||
import com.soywiz.korma.geom.*
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import java.awt.*
|
import java.awt.*
|
||||||
import java.awt.image.*
|
import java.awt.event.*
|
||||||
import javax.swing.*
|
import javax.swing.*
|
||||||
|
|
||||||
class MyTileMapEditorPanel(val tmx: TiledMap) : JPanel(BorderLayout()) {
|
class MyTileMapEditorPanel(val tmx: TiledMap) : JPanel(BorderLayout()) {
|
||||||
@@ -16,105 +17,153 @@ class MyTileMapEditorPanel(val tmx: TiledMap) : JPanel(BorderLayout()) {
|
|||||||
|
|
||||||
val maxTileGid = tmx.tilesets.map { it.firstgid + it.tileset.textures.size }.max() ?: 0
|
val maxTileGid = tmx.tilesets.map { it.firstgid + it.tileset.textures.size }.max() ?: 0
|
||||||
|
|
||||||
data class TileInfo(val image: Bitmap32, val awt: BufferedImage, val area: RectangleInt) {
|
data class TileInfo(val bmp32: Bitmap32) {
|
||||||
val miniImage = awt.getSubimage(area.x, area.y, area.width, area.height)
|
val miniSlice = bmp32.slice()
|
||||||
val miniBmp32 = image.copySliceWithSize(area.x, area.y, area.width, area.height)
|
|
||||||
val miniSlice = miniBmp32.sliceWithSize(0, 0, area.width, area.height)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val emptyImage = Bitmaps.transparent.bmp
|
val tiles = Array<TileInfo?>(maxTileGid) { null }.also { tiles ->
|
||||||
private val emptyImageAwt = emptyImage.toAwt()
|
|
||||||
val dummyTile = TileInfo(emptyImage, emptyImageAwt, Bitmaps.transparent.bounds)
|
|
||||||
val tiles: Array<TileInfo> = Array(maxTileGid) { dummyTile }.also { tiles ->
|
|
||||||
for (tileset in tmx.tilesets) {
|
for (tileset in tmx.tilesets) {
|
||||||
val tex = tileset.tileset.base.toBMP32()
|
|
||||||
val tex2 = tex.toAwt()
|
|
||||||
for (tileIdx in tileset.tileset.textures.indices) {
|
for (tileIdx in tileset.tileset.textures.indices) {
|
||||||
val tile = tileset.tileset.textures[tileIdx]
|
val tile = tileset.tileset.textures[tileIdx]
|
||||||
if (tile != null) {
|
if (tile != null) {
|
||||||
tiles[tileset.firstgid + tileIdx] = TileInfo(tex, tex2, (tile as BitmapSlice<*>).bounds)
|
val miniSlice = (tile as BitmapSlice<*>).extract().toBMP32()
|
||||||
|
tiles[tileset.firstgid + tileIdx] = when {
|
||||||
|
miniSlice.allFixed { it.a == 0 } -> null // Transparent
|
||||||
|
else -> TileInfo(miniSlice)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val realPanel = tileMapEditor.contentPanel
|
val realPanel = tileMapEditor.contentPanel
|
||||||
|
var scale = 2.0
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
mapComponent.updateSize()
|
||||||
|
mapComponent.revalidate()
|
||||||
|
mapComponentScroll.revalidate()
|
||||||
|
mapComponentScroll.repaint()
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
inner class MapComponent : JComponent() {
|
||||||
add(realPanel, BorderLayout.CENTER)
|
init {
|
||||||
|
updateSize()
|
||||||
|
addMouseMotionListener(object : MouseMotionAdapter() {
|
||||||
|
override fun mouseDragged(e: MouseEvent) {
|
||||||
|
println("mouseDragged: $e")
|
||||||
|
onPressMouse(e.point)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
addMouseListener(object : MouseAdapter() {
|
||||||
|
override fun mousePressed(e: MouseEvent) {
|
||||||
|
println("mousePressed: $e")
|
||||||
|
if (e.button == MouseEvent.BUTTON1) {
|
||||||
|
onPressMouse(e.point)
|
||||||
|
} else {
|
||||||
|
onRightPressMouse(e.point)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
tileMapEditor.mapPanel.add(JScrollPane(object : JComponent() {
|
var currentTileSelected = 1
|
||||||
init {
|
|
||||||
this.preferredSize = Dimension(tmx.pixelWidth, tmx.pixelHeight)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun paintComponent(g: Graphics) {
|
fun onPressMouse(point: Point) {
|
||||||
val g = (g as Graphics2D)
|
val tileIndex = getTileIndex(point)
|
||||||
|
tmx.patternLayers[0].map[tileIndex.x, tileIndex.y] = RGBA(currentTileSelected)
|
||||||
|
repaint()
|
||||||
|
//println(tileIndex)
|
||||||
|
}
|
||||||
|
|
||||||
val TILE_WIDTH = tmx.tilewidth
|
fun onRightPressMouse(point: Point) {
|
||||||
val TILE_HEIGHT = tmx.tileheight
|
val tileIndex = getTileIndex(point)
|
||||||
|
currentTileSelected = tmx.patternLayers[0].map[tileIndex.x, tileIndex.y].value
|
||||||
|
}
|
||||||
|
|
||||||
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
|
fun updateSize() {
|
||||||
val clipBounds = g.clipBounds
|
this.preferredSize = Dimension((tmx.pixelWidth * scale).toInt(), (tmx.pixelHeight * scale).toInt())
|
||||||
val displayTilesX = (clipBounds.width / TILE_WIDTH) + 2
|
}
|
||||||
val displayTilesY = (clipBounds.height / TILE_HEIGHT) + 2
|
|
||||||
val temp = Bitmap32(displayTilesX * TILE_WIDTH, displayTilesY * TILE_HEIGHT)
|
|
||||||
|
|
||||||
val offsetX = clipBounds.x / TILE_WIDTH
|
fun getTileIndex(coords: Point): Point = Point((coords.x / tmx.tilewidth / scale).toInt(), (coords.y / tmx.tileheight / scale).toInt())
|
||||||
val offsetY = clipBounds.y / TILE_HEIGHT
|
|
||||||
|
|
||||||
for (layer in tmx.allLayers) {
|
override fun paintComponent(g: Graphics) {
|
||||||
when (layer) {
|
val g = (g as Graphics2D)
|
||||||
is TiledMap.Layer.Patterns -> {
|
|
||||||
for (x in 0 until displayTilesX) {
|
|
||||||
for (y in 0 until displayTilesY) {
|
|
||||||
val rx = x + offsetX
|
|
||||||
val ry = y + offsetY
|
|
||||||
|
|
||||||
if (rx < 0 || rx >= layer.map.width) continue
|
val TILE_WIDTH = tmx.tilewidth
|
||||||
if (ry < 0 || ry >= layer.map.height) continue
|
val TILE_HEIGHT = tmx.tileheight
|
||||||
|
|
||||||
val tileIdx = layer.map[rx, ry].value
|
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
|
||||||
val tile = tiles.getOrElse(tileIdx) { dummyTile }
|
val clipBounds = g.clipBounds
|
||||||
val px0 = x * TILE_WIDTH
|
val displayTilesX = ((clipBounds.width / TILE_WIDTH / scale) + 3).toInt()
|
||||||
val py0 = y * TILE_HEIGHT
|
val displayTilesY = ((clipBounds.height / TILE_HEIGHT / scale) + 3).toInt()
|
||||||
val px = rx * TILE_WIDTH
|
val temp = Bitmap32((displayTilesX * TILE_WIDTH), (displayTilesY * TILE_HEIGHT))
|
||||||
val py = ry * TILE_HEIGHT
|
|
||||||
|
|
||||||
temp._draw(tile.miniSlice, px0, py0, mix = true)
|
val offsetX = (clipBounds.x / TILE_WIDTH / scale).toInt()
|
||||||
//temp.draw(tile.miniBmp32, px0, py0)
|
val offsetY = (clipBounds.y / TILE_HEIGHT / scale).toInt()
|
||||||
//g.drawImage(tile.miniImage, px, py, null)
|
|
||||||
/*
|
for (layer in tmx.allLayers) {
|
||||||
g.drawImage(
|
when (layer) {
|
||||||
tile.image,
|
is TiledMap.Layer.Patterns -> {
|
||||||
px, py, px + TILE_WIDTH, py + TILE_HEIGHT,
|
for (x in 0 until displayTilesX) {
|
||||||
tile.area.left, tile.area.top, tile.area.right, tile.area.bottom,
|
for (y in 0 until displayTilesY) {
|
||||||
null
|
val rx = x + offsetX
|
||||||
)
|
val ry = y + offsetY
|
||||||
*/
|
|
||||||
//g.color = Color.RED
|
if (rx < 0 || rx >= layer.map.width) continue
|
||||||
//g.drawRect(px, py, TILE_WIDTH, TILE_HEIGHT)
|
if (ry < 0 || ry >= layer.map.height) continue
|
||||||
|
|
||||||
|
val tileIdx = layer.map[rx, ry].value
|
||||||
|
val tile = tiles.getOrNull(tileIdx)
|
||||||
|
if (tile != null) {
|
||||||
|
temp._draw(tile.miniSlice, x * TILE_WIDTH, y * TILE_HEIGHT, mix = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g.drawImage(temp.toAwt(), offsetX * TILE_WIDTH, offsetY * TILE_HEIGHT, null)
|
|
||||||
|
|
||||||
for (x in 0 until displayTilesX) {
|
|
||||||
for (y in 0 until displayTilesY) {
|
|
||||||
val rx = x + offsetX
|
|
||||||
val ry = y + offsetY
|
|
||||||
val px = rx * TILE_WIDTH
|
|
||||||
val py = ry * TILE_HEIGHT
|
|
||||||
g.color = Color.BLACK
|
|
||||||
g.drawRect(px, py, TILE_WIDTH, TILE_HEIGHT)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}), GridConstraints().also { it.fill = GridConstraints.FILL_BOTH })
|
|
||||||
|
|
||||||
|
//val oldTransform = g.transform
|
||||||
|
g.translate(offsetX * TILE_WIDTH * scale, offsetY * TILE_HEIGHT * scale)
|
||||||
|
g.scale(scale, scale)
|
||||||
|
g.drawImage(temp.toAwt(), 0, 0, null)
|
||||||
|
|
||||||
|
//g.transform = oldTransform
|
||||||
|
|
||||||
|
g.stroke = BasicStroke((1f / scale).toFloat())
|
||||||
|
g.color = Color.BLACK
|
||||||
|
//g.translate(offsetX * TILE_WIDTH * scale, offsetY * TILE_HEIGHT * scale)
|
||||||
|
for (y in 0 until displayTilesY) g.drawLine(0, y * TILE_HEIGHT, displayTilesX * TILE_WIDTH, y * TILE_HEIGHT)
|
||||||
|
for (x in 0 until displayTilesX) g.drawLine(x * TILE_WIDTH, 0, x * TILE_WIDTH, displayTilesY * TILE_HEIGHT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val mapComponent = MapComponent()
|
||||||
|
val mapComponentScroll = JBScrollPane(mapComponent).also { scroll ->
|
||||||
|
//scroll.verticalScrollBar.unitIncrement = 16
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updatedSize() {
|
||||||
|
tileMapEditor.leftSplitPane.dividerLocation = 200
|
||||||
|
tileMapEditor.rightSplitPane.dividerLocation = tileMapEditor.rightSplitPane.width - 200
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
|
||||||
|
add(realPanel, BorderLayout.CENTER)
|
||||||
|
|
||||||
|
tileMapEditor.mapPanel.add(mapComponentScroll, GridConstraints().also { it.fill = GridConstraints.FILL_BOTH })
|
||||||
|
|
||||||
|
tileMapEditor.zoomInButton.addActionListener { scale *= 1.5 }
|
||||||
|
tileMapEditor.zoomOutButton.addActionListener { scale /= 1.5 }
|
||||||
|
|
||||||
|
updatedSize()
|
||||||
|
addComponentListener(object : ComponentAdapter() {
|
||||||
|
override fun componentResized(e: ComponentEvent) {
|
||||||
|
updatedSize()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,3 +184,6 @@ class MyTileMapEditorFrame(val tmx: TiledMap) : JFrame() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun Bitmap32.anyFixed(callback: (RGBA) -> Boolean): Boolean = (0 until area).any { callback(data[it]) }
|
||||||
|
inline fun Bitmap32.allFixed(callback: (RGBA) -> Boolean): Boolean = (0 until area).all { callback(data[it]) }
|
||||||
|
|||||||
@@ -53,6 +53,18 @@
|
|||||||
<text value="Settings"/>
|
<text value="Settings"/>
|
||||||
</properties>
|
</properties>
|
||||||
</component>
|
</component>
|
||||||
|
<component id="81436" class="javax.swing.JButton" binding="zoomInButton">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<text value="Zoom +"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
|
<component id="9b93c" class="javax.swing.JButton" binding="zoomOutButton">
|
||||||
|
<constraints/>
|
||||||
|
<properties>
|
||||||
|
<text value="Zoom -"/>
|
||||||
|
</properties>
|
||||||
|
</component>
|
||||||
</children>
|
</children>
|
||||||
</grid>
|
</grid>
|
||||||
<vspacer id="ce228">
|
<vspacer id="ce228">
|
||||||
@@ -60,7 +72,7 @@
|
|||||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</vspacer>
|
</vspacer>
|
||||||
<splitpane id="19a4f">
|
<splitpane id="19a4f" binding="leftSplitPane">
|
||||||
<constraints>
|
<constraints>
|
||||||
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
|
<grid row="1" column="1" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
|
||||||
<preferred-size width="200" height="200"/>
|
<preferred-size width="200" height="200"/>
|
||||||
@@ -121,7 +133,7 @@
|
|||||||
</tabbedpane>
|
</tabbedpane>
|
||||||
</children>
|
</children>
|
||||||
</splitpane>
|
</splitpane>
|
||||||
<splitpane id="e4503">
|
<splitpane id="e4503" binding="rightSplitPane">
|
||||||
<constraints>
|
<constraints>
|
||||||
<splitpane position="right"/>
|
<splitpane position="right"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
|||||||
@@ -18,4 +18,8 @@ public class TileMapEditor {
|
|||||||
public JPanel mapPanel;
|
public JPanel mapPanel;
|
||||||
public JTabbedPane tabbedPane4;
|
public JTabbedPane tabbedPane4;
|
||||||
public JTabbedPane tabbedPane5;
|
public JTabbedPane tabbedPane5;
|
||||||
|
public JButton zoomInButton;
|
||||||
|
public JButton zoomOutButton;
|
||||||
|
public JSplitPane rightSplitPane;
|
||||||
|
public JSplitPane leftSplitPane;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user