root.imageSpaces
This commit is contained in:
parent
ca23dd2b95
commit
22c39ba497
@ -3,5 +3,6 @@ package ru.dbotthepony.kstarbound
|
|||||||
const val METRES_IN_STARBOUND_UNIT = 0.5
|
const val METRES_IN_STARBOUND_UNIT = 0.5
|
||||||
const val METRES_IN_STARBOUND_UNITf = 0.5f
|
const val METRES_IN_STARBOUND_UNITf = 0.5f
|
||||||
|
|
||||||
const val PIXELS_IN_STARBOUND_UNIT = 8.0
|
const val PIXELS_IN_STARBOUND_UNITi = 8
|
||||||
const val PIXELS_IN_STARBOUND_UNITf = 8.0f
|
const val PIXELS_IN_STARBOUND_UNIT = PIXELS_IN_STARBOUND_UNITi.toDouble()
|
||||||
|
const val PIXELS_IN_STARBOUND_UNITf = PIXELS_IN_STARBOUND_UNITi.toFloat()
|
||||||
|
@ -375,7 +375,18 @@ class Starbound : ISBFileLocator {
|
|||||||
|
|
||||||
state.setTableFunction("imageSpaces", this) { args ->
|
state.setTableFunction("imageSpaces", this) { args ->
|
||||||
// List<Vec2I> root.imageSpaces(String imagePath, Vec2F worldPosition, float spaceScan, bool flip)
|
// List<Vec2I> root.imageSpaces(String imagePath, Vec2F worldPosition, float spaceScan, bool flip)
|
||||||
TODO()
|
val values = imageData(args.getString()).worldSpaces(args.getVector2i(), args.getDouble(), args.getBool())
|
||||||
|
|
||||||
|
args.lua.pushTable(arraySize = values.size)
|
||||||
|
val table = args.lua.stackTop
|
||||||
|
|
||||||
|
for ((i, value) in values.withIndex()) {
|
||||||
|
args.lua.push(i)
|
||||||
|
args.lua.push(value)
|
||||||
|
args.lua.setTableValue(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
state.setTableFunction("nonEmptyRegion", this) { args ->
|
state.setTableFunction("nonEmptyRegion", this) { args ->
|
||||||
|
@ -2,7 +2,8 @@ package ru.dbotthepony.kstarbound.io
|
|||||||
|
|
||||||
import org.lwjgl.stb.STBImage
|
import org.lwjgl.stb.STBImage
|
||||||
import org.lwjgl.system.MemoryUtil.memAddress
|
import org.lwjgl.system.MemoryUtil.memAddress
|
||||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT
|
||||||
|
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITi
|
||||||
import ru.dbotthepony.kvector.vector.nint.Vector2i
|
import ru.dbotthepony.kvector.vector.nint.Vector2i
|
||||||
import ru.dbotthepony.kvector.vector.nint.Vector4i
|
import ru.dbotthepony.kvector.vector.nint.Vector4i
|
||||||
import java.lang.ref.Cleaner
|
import java.lang.ref.Cleaner
|
||||||
@ -45,14 +46,65 @@ class ImageData(val data: ByteBuffer, val width: Int, val height: Int, val amoun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun worldSpaces(pos: Vector2d, spaceScan: Double, flip: Boolean): List<Vector2i> {
|
operator fun get(x: Int, y: Int, flip: Boolean): Int {
|
||||||
when (amountOfChannels) {
|
require(x in 0 until width) { "X out of bounds: $x" }
|
||||||
3 -> TODO()
|
require(y in 0 until height) { "Y out of bounds: $y" }
|
||||||
4 -> TODO()
|
|
||||||
else -> throw IllegalStateException("Can not check world space taken by image with $amountOfChannels color channels")
|
if (flip) {
|
||||||
|
return this[width - x - 1, y]
|
||||||
|
} else {
|
||||||
|
return this[x, y]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isTransparent(x: Int, y: Int, flip: Boolean): Boolean {
|
||||||
|
if (x !in 0 until width) return true
|
||||||
|
if (y !in 0 until height) return true
|
||||||
|
if (amountOfChannels != 4) return false
|
||||||
|
return this[x, y, flip] and 0xFF != 0x0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun worldSpaces(pixelOffset: Vector2i, spaceScan: Double, flip: Boolean): List<Vector2i> {
|
||||||
|
if (amountOfChannels != 3 && amountOfChannels != 4) throw IllegalStateException("Can not check world space taken by image with $amountOfChannels color channels")
|
||||||
|
|
||||||
|
val xDivL = pixelOffset.x % PIXELS_IN_STARBOUND_UNITi
|
||||||
|
val yDivB = pixelOffset.y % PIXELS_IN_STARBOUND_UNITi
|
||||||
|
|
||||||
|
val xDivR = (pixelOffset.x + width) % PIXELS_IN_STARBOUND_UNITi
|
||||||
|
val yDivT = (pixelOffset.y + height) % PIXELS_IN_STARBOUND_UNITi
|
||||||
|
|
||||||
|
val leftMostX = pixelOffset.x / PIXELS_IN_STARBOUND_UNITi - (if (xDivL != 0) 1 else 0)
|
||||||
|
val bottomMostY = pixelOffset.y / PIXELS_IN_STARBOUND_UNITi - (if (yDivB != 0) 1 else 0)
|
||||||
|
|
||||||
|
val rightMostX = (pixelOffset.x + width) / PIXELS_IN_STARBOUND_UNITi + (if (xDivR != 0) 1 else 0)
|
||||||
|
val topMostY = (pixelOffset.y + height) / PIXELS_IN_STARBOUND_UNITi + (if (yDivT != 0) 1 else 0)
|
||||||
|
|
||||||
|
val result = ArrayList<Vector2i>()
|
||||||
|
|
||||||
|
for (y in bottomMostY .. topMostY) {
|
||||||
|
for (x in leftMostX .. rightMostX) {
|
||||||
|
val left = x * PIXELS_IN_STARBOUND_UNITi
|
||||||
|
val bottom = y * PIXELS_IN_STARBOUND_UNITi
|
||||||
|
|
||||||
|
var transparentPixels = 0
|
||||||
|
|
||||||
|
for (sX in 0 until PIXELS_IN_STARBOUND_UNITi) {
|
||||||
|
for (sY in 0 until PIXELS_IN_STARBOUND_UNITi) {
|
||||||
|
if (isTransparent(xDivL + sX + left, yDivB + sY + bottom, flip)) {
|
||||||
|
transparentPixels++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transparentPixels * FILL_RATIO >= spaceScan) {
|
||||||
|
result.add(Vector2i(x, y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
val nonEmptyRegion by lazy {
|
val nonEmptyRegion by lazy {
|
||||||
if (amountOfChannels == 4) {
|
if (amountOfChannels == 4) {
|
||||||
var x0 = 0
|
var x0 = 0
|
||||||
@ -60,7 +112,7 @@ class ImageData(val data: ByteBuffer, val width: Int, val height: Int, val amoun
|
|||||||
|
|
||||||
search@for (y in 0 until height) {
|
search@for (y in 0 until height) {
|
||||||
for (x in 0 until width) {
|
for (x in 0 until width) {
|
||||||
if (this[x, y] and 0x000000FF != 0x0) {
|
if (this[x, y] and 0xFF != 0x0) {
|
||||||
x0 = x
|
x0 = x
|
||||||
y0 = y
|
y0 = y
|
||||||
break@search
|
break@search
|
||||||
@ -73,7 +125,7 @@ class ImageData(val data: ByteBuffer, val width: Int, val height: Int, val amoun
|
|||||||
|
|
||||||
search@for (y in height - 1 downTo y0) {
|
search@for (y in height - 1 downTo y0) {
|
||||||
for (x in width - 1 downTo x0) {
|
for (x in width - 1 downTo x0) {
|
||||||
if (this[x, y] and 0x000000FF != 0x0) {
|
if (this[x, y] and 0xFF != 0x0) {
|
||||||
x1 = x
|
x1 = x
|
||||||
y1 = y
|
y1 = y
|
||||||
break@search
|
break@search
|
||||||
@ -86,4 +138,8 @@ class ImageData(val data: ByteBuffer, val width: Int, val height: Int, val amoun
|
|||||||
|
|
||||||
Vector4i(0, 0, width, height)
|
Vector4i(0, 0, width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val FILL_RATIO = 1 / (PIXELS_IN_STARBOUND_UNIT * PIXELS_IN_STARBOUND_UNIT)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,6 +311,29 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
|
|||||||
return pairs
|
return pairs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getVector2i(stackIndex: Int = -1): Vector2i? {
|
||||||
|
val abs = this.absStackIndex(stackIndex)
|
||||||
|
|
||||||
|
if (!this.isTable(abs))
|
||||||
|
return null
|
||||||
|
|
||||||
|
push(1)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val x = getLong(abs + 1)
|
||||||
|
pop()
|
||||||
|
x ?: return null
|
||||||
|
|
||||||
|
push(2)
|
||||||
|
loadTableValue(abs)
|
||||||
|
|
||||||
|
val y = getLong(abs + 1)
|
||||||
|
pop()
|
||||||
|
y ?: return null
|
||||||
|
|
||||||
|
return Vector2i(x.toInt(), y.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Пропуски заполняются [JsonNull.INSTANCE]
|
* Пропуски заполняются [JsonNull.INSTANCE]
|
||||||
*
|
*
|
||||||
@ -354,13 +377,13 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
|
|||||||
return this.getValue(limit = limit)
|
return this.getValue(limit = limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadTableValue(stackIndex: Int = -2) {
|
fun loadTableValue(stackIndex: Int = -2, allowNothing: Boolean = false) {
|
||||||
val abs = this.absStackIndex(stackIndex)
|
val abs = this.absStackIndex(stackIndex)
|
||||||
|
|
||||||
if (!this.isTable(abs))
|
if (!this.isTable(abs))
|
||||||
throw IllegalArgumentException("Attempt to index an ${this.typeAt(abs)} value")
|
throw IllegalArgumentException("Attempt to index an ${this.typeAt(abs)} value")
|
||||||
|
|
||||||
if (LuaJNR.INSTANCE.lua_gettable(this.pointer, abs) == LUA_TNONE)
|
if (LuaJNR.INSTANCE.lua_gettable(this.pointer, abs) == LUA_TNONE && !allowNothing)
|
||||||
throw IllegalStateException("loaded TNONE from Lua table")
|
throw IllegalStateException("loaded TNONE from Lua table")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -508,6 +531,18 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
|
|||||||
?: throw IllegalArgumentException("Lua code error: Bad argument #$position: double expected, got ${this@LuaState.typeAt(position)}")
|
?: throw IllegalArgumentException("Lua code error: Bad argument #$position: double expected, got ${this@LuaState.typeAt(position)}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getInt(position: Int = this.position++): Int {
|
||||||
|
check(position in 1 ..this.top) { "JVM code error: Invalid argument position: $position" }
|
||||||
|
return this@LuaState.getLong(position)?.toInt()
|
||||||
|
?: throw IllegalArgumentException("Lua code error: Bad argument #$position: integer expected, got ${this@LuaState.typeAt(position)}")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getVector2i(position: Int = this.position++): Vector2i {
|
||||||
|
check(position in 1 ..this.top) { "JVM code error: Invalid argument position: $position" }
|
||||||
|
return this@LuaState.getVector2i(position)
|
||||||
|
?: throw IllegalArgumentException("Lua code error: Bad argument #$position: Vector2i expected, got ${this@LuaState.typeAt(position)}")
|
||||||
|
}
|
||||||
|
|
||||||
fun getBoolOrNil(position: Int = this.position++): Boolean? {
|
fun getBoolOrNil(position: Int = this.position++): Boolean? {
|
||||||
check(position in 1 ..this.top) { "JVM code error: Invalid argument position: $position" }
|
check(position in 1 ..this.top) { "JVM code error: Invalid argument position: $position" }
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user