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_UNITf = 0.5f
|
||||
|
||||
const val PIXELS_IN_STARBOUND_UNIT = 8.0
|
||||
const val PIXELS_IN_STARBOUND_UNITf = 8.0f
|
||||
const val PIXELS_IN_STARBOUND_UNITi = 8
|
||||
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 ->
|
||||
// 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 ->
|
||||
|
@ -2,7 +2,8 @@ package ru.dbotthepony.kstarbound.io
|
||||
|
||||
import org.lwjgl.stb.STBImage
|
||||
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.Vector4i
|
||||
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> {
|
||||
when (amountOfChannels) {
|
||||
3 -> TODO()
|
||||
4 -> TODO()
|
||||
else -> throw IllegalStateException("Can not check world space taken by image with $amountOfChannels color channels")
|
||||
operator fun get(x: Int, y: Int, flip: Boolean): Int {
|
||||
require(x in 0 until width) { "X out of bounds: $x" }
|
||||
require(y in 0 until height) { "Y out of bounds: $y" }
|
||||
|
||||
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 {
|
||||
if (amountOfChannels == 4) {
|
||||
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) {
|
||||
for (x in 0 until width) {
|
||||
if (this[x, y] and 0x000000FF != 0x0) {
|
||||
if (this[x, y] and 0xFF != 0x0) {
|
||||
x0 = x
|
||||
y0 = y
|
||||
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) {
|
||||
for (x in width - 1 downTo x0) {
|
||||
if (this[x, y] and 0x000000FF != 0x0) {
|
||||
if (this[x, y] and 0xFF != 0x0) {
|
||||
x1 = x
|
||||
y1 = y
|
||||
break@search
|
||||
@ -86,4 +138,8 @@ class ImageData(val data: ByteBuffer, val width: Int, val height: Int, val amoun
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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]
|
||||
*
|
||||
@ -354,13 +377,13 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
|
||||
return this.getValue(limit = limit)
|
||||
}
|
||||
|
||||
fun loadTableValue(stackIndex: Int = -2) {
|
||||
fun loadTableValue(stackIndex: Int = -2, allowNothing: Boolean = false) {
|
||||
val abs = this.absStackIndex(stackIndex)
|
||||
|
||||
if (!this.isTable(abs))
|
||||
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")
|
||||
}
|
||||
|
||||
@ -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)}")
|
||||
}
|
||||
|
||||
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? {
|
||||
check(position in 1 ..this.top) { "JVM code error: Invalid argument position: $position" }
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user