Make it compile against updated box2d and kvector

This commit is contained in:
DBotThePony 2023-09-02 20:51:15 +07:00
parent 48e1cd5263
commit 96e782c264
Signed by: DBot
GPG Key ID: DCC23B5715498507
66 changed files with 442 additions and 1022 deletions

View File

@ -2,7 +2,7 @@
import org.gradle.internal.jvm.Jvm
plugins {
kotlin("jvm") version "1.9.0"
kotlin("jvm") version "1.9.10"
java
application
}
@ -80,8 +80,8 @@ dependencies {
implementation("net.java.dev.jna:jna:5.13.0")
implementation("com.github.jnr:jnr-ffi:2.2.13")
implementation("ru.dbotthepony:kbox2d:2.4.1.+")
implementation("ru.dbotthepony:kvector:1.3.2")
implementation("ru.dbotthepony:kbox2d:2.4.1.2")
implementation("ru.dbotthepony:kvector:2.2.3")
implementation("com.github.ben-manes.caffeine:caffeine:3.1.5")
}

View File

@ -1,7 +1,7 @@
package ru.dbotthepony.kstarbound.client.freetype.struct;
import com.sun.jna.Structure;
import ru.dbotthepony.kvector.vector.nint.Vector2i;
import ru.dbotthepony.kvector.vector.Vector2i;
@Structure.FieldOrder({"x", "y"})
public class FT_Vector extends Structure {

View File

@ -8,17 +8,16 @@ import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.render.Animator
import ru.dbotthepony.kstarbound.defs.animation.AnimationDefinition
import ru.dbotthepony.kstarbound.io.BTreeDB
import ru.dbotthepony.kstarbound.lua.LuaState
import ru.dbotthepony.kstarbound.lua.LuaType
import ru.dbotthepony.kstarbound.player.Avatar
import ru.dbotthepony.kstarbound.player.Player
import ru.dbotthepony.kstarbound.player.QuestDescriptor
import ru.dbotthepony.kstarbound.player.QuestInstance
import ru.dbotthepony.kstarbound.util.JVMTimeSource
import ru.dbotthepony.kstarbound.world.ChunkPos
import ru.dbotthepony.kstarbound.world.TileState
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
import ru.dbotthepony.kstarbound.world.entities.PlayerEntity
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector2f
import java.io.ByteArrayInputStream
import java.io.DataInputStream
import java.io.File
@ -87,66 +86,12 @@ fun main() {
reader.skipBytes(3)
var hitTile = false
t = System.currentTimeMillis()
for (y in 0 .. 31) {
for (x in 0 .. 31) {
val materialID = reader.readUnsignedShort()
val getMat = starbound.tilesByID[materialID]
if (getMat != null) {
chunk.foreground[x, y].material = getMat.value
hitTile = true
}
// reader.skipBytes(1) // Foreground hue shift
// reader.skipBytes(1) // Foreground color variant
val colorShift = reader.readUnsignedByte()
val colorVariant = reader.readUnsignedByte()
val modifier = reader.readUnsignedShort()
val getModifier = starbound.tileModifiersByID[modifier]
chunk.foreground[x, y].color = colorVariant
chunk.foreground[x, y].setHueShift(colorShift)
if (getModifier != null && getMat != null) {
chunk.foreground[x, y].modifier = getModifier.value
}
val modifierHueShift = reader.readUnsignedByte()
chunk.foreground[x, y].setModifierHueShift(modifierHueShift)
val materialID2 = reader.readUnsignedShort()
val getMat2 = starbound.tilesByID[materialID2]
if (getMat2 != null) {
chunk.background[x, y].material = getMat2.value
hitTile = true
}
// reader.skipBytes(1) // Background hue shift
// reader.skipBytes(1) // Background color variant
val colorShift2 = reader.readUnsignedByte()
val colorVariant2 = reader.readUnsignedByte()
val modifier2 = reader.readUnsignedShort()
val getModifier2 = starbound.tileModifiersByID[modifier2]
if (getModifier2 != null && getMat2 != null) {
chunk.background[x, y].modifier = getModifier2.value
}
chunk.background[x, y].color = colorVariant2
chunk.background[x, y].setHueShift(colorShift2)
val modifierHueShift2 = reader.readUnsignedByte()
chunk.background[x, y].setModifierHueShift(modifierHueShift2)
chunk.foreground.setTile(x, y, TileState.read(starbound.tilesByID::get, starbound.tileModifiersByID::get, reader))
chunk.background.setTile(x, y, TileState.read(starbound.tilesByID::get, starbound.tileModifiersByID::get, reader))
val liquid = reader.readUnsignedByte()
val liquidLevel = reader.readFloat()
@ -172,11 +117,6 @@ fun main() {
}
set += System.currentTimeMillis() - t
if (hitTile) {
//println(chunk.chunk.posVector2d)
// ent.position = chunk.chunk.posVector2d + Vector2d(16.0, 34.0)
}
}
}
}
@ -227,8 +167,7 @@ fun main() {
//ent.position += Vector2d(y = 14.0, x = -10.0)
ent.position = Vector2d(600.0 + 16.0, 721.0 + 48.0)
client.camera.pos.x = 578f
client.camera.pos.y = 695f
client.camera.pos = Vector2f(578f, 695f)
client.onDrawGUI {
client.gl.font.render("${ent.position}", y = 100f, scale = 0.25f)
@ -315,11 +254,10 @@ fun main() {
//client.camera.pos.x = ent.position.x.toFloat()
//client.camera.pos.y = ent.position.y.toFloat()
client.camera.pos.x += if (client.input.KEY_LEFT_DOWN || client.input.KEY_A_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.zoom else 0f
client.camera.pos.x += if (client.input.KEY_RIGHT_DOWN || client.input.KEY_D_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.zoom else 0f
client.camera.pos.y += if (client.input.KEY_UP_DOWN || client.input.KEY_W_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.zoom else 0f
client.camera.pos.y += if (client.input.KEY_DOWN_DOWN || client.input.KEY_S_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.zoom else 0f
client.camera.pos += Vector2f(
(if (client.input.KEY_LEFT_DOWN || client.input.KEY_A_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.zoom else 0f) + (if (client.input.KEY_RIGHT_DOWN || client.input.KEY_D_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.zoom else 0f),
(if (client.input.KEY_UP_DOWN || client.input.KEY_W_DOWN) client.frameRenderTime.toFloat() * 32f / client.settings.zoom else 0f) + (if (client.input.KEY_DOWN_DOWN || client.input.KEY_S_DOWN) -client.frameRenderTime.toFloat() * 32f / client.settings.zoom else 0f)
)
//println(client.camera.velocity.toDoubleVector() * client.frameRenderTime * 0.1)

View File

@ -51,6 +51,7 @@ import ru.dbotthepony.kstarbound.util.JsonArrayCollector
import ru.dbotthepony.kstarbound.io.*
import ru.dbotthepony.kstarbound.io.json.AABBTypeAdapter
import ru.dbotthepony.kstarbound.io.json.AABBiTypeAdapter
import ru.dbotthepony.kstarbound.io.json.ColorTypeAdapter
import ru.dbotthepony.kstarbound.io.json.EitherTypeAdapter
import ru.dbotthepony.kstarbound.io.json.InternedJsonElementAdapter
import ru.dbotthepony.kstarbound.io.json.InternedStringAdapter
@ -79,7 +80,7 @@ import ru.dbotthepony.kstarbound.util.WriteOnce
import ru.dbotthepony.kstarbound.util.filterNotNull
import ru.dbotthepony.kstarbound.util.set
import ru.dbotthepony.kstarbound.util.traverseJsonPath
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kvector.vector.Vector2i
import java.io.*
import java.lang.ref.ReferenceQueue
import java.lang.ref.WeakReference

View File

@ -15,12 +15,12 @@ import ru.dbotthepony.kstarbound.client.render.TileLayerList
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
import ru.dbotthepony.kstarbound.world.*
import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kvector.matrix.Matrix4fStack
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
import ru.dbotthepony.kvector.arrays.Matrix4fStack
import ru.dbotthepony.kvector.arrays.Matrix4f
import ru.dbotthepony.kvector.util2d.intersectCircleRectangle
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
import ru.dbotthepony.kvector.vector.nfloat.Vector3f
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector2f
import ru.dbotthepony.kvector.vector.Vector3f
import java.io.Closeable
import java.util.LinkedList
@ -52,7 +52,7 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
layers.clear()
for ((pos, tile) in view.posToTile) {
for ((pos, tile) in view.iterate()) {
val material = tile.material
if (material != null) {
@ -68,7 +68,7 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
}
fun loadRenderers(view: ITileChunk) {
for ((_, tile) in view.posToTile) {
for ((_, tile) in view.iterate()) {
val material = tile.material
val modifier = tile.modifier
@ -93,7 +93,7 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
}
fun render(stack: Matrix4fStack) {
val transform = stack.last
val transform = stack.last()
for (mesh in bakedMeshes) {
mesh.first.render(transform)
@ -199,20 +199,20 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
for (x in this.x * SHADOW_GEOMETRY_SQUARE_SIZE until (this.x + 1) * SHADOW_GEOMETRY_SQUARE_SIZE) {
for (y in this.y * SHADOW_GEOMETRY_SQUARE_SIZE until (this.y + 1) * SHADOW_GEOMETRY_SQUARE_SIZE) {
if (foreground[x, y].material?.renderParameters?.lightTransparent == false) {
if (x == 0 || foreground[x - 1, y].material?.renderParameters?.lightTransparent != true) {
if (foreground.getTile(x, y).material?.renderParameters?.lightTransparent == false) {
if (x == 0 || foreground.getTile(x - 1, y).material?.renderParameters?.lightTransparent != true) {
line(builder, x.toFloat(), y + 1f, x.toFloat(), y.toFloat())
}
if (x == CHUNK_SIZE - 1 || foreground[x + 1, y].material?.renderParameters?.lightTransparent != true) {
if (x == CHUNK_SIZE - 1 || foreground.getTile(x + 1, y).material?.renderParameters?.lightTransparent != true) {
line(builder, x + 1f, y.toFloat(), x + 1f, y + 1f)
}
if (y == 0 || foreground[x, y - 1].material?.renderParameters?.lightTransparent != true) {
if (y == 0 || foreground.getTile(x, y - 1).material?.renderParameters?.lightTransparent != true) {
line(builder, x.toFloat(), y.toFloat(), x + 1f, y.toFloat())
}
if (y == CHUNK_SIZE - 1 || foreground[x, y + 1].material?.renderParameters?.lightTransparent != true) {
if (y == CHUNK_SIZE - 1 || foreground.getTile(x, y + 1).material?.renderParameters?.lightTransparent != true) {
line(builder, x + 1f, y + 1f, x.toFloat(), y + 1f)
}
}
@ -302,7 +302,7 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
) {
if (!setOnce) {
program.localToWorldTransform =
Matrix4f.IDENTITY.translateWithMultiplication(
Matrix4f.identity().translateWithMultiplication(
Vector3f(x = renderOrigin.x * CHUNK_SIZEf,
y = renderOrigin.y * CHUNK_SIZEf))
@ -338,7 +338,7 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
) {
if (!setOnce) {
program.localToWorldTransform =
Matrix4f.IDENTITY.translateWithMultiplication(
Matrix4f.identity().translateWithMultiplication(
Vector3f(x = renderOrigin.x * CHUNK_SIZEf,
y = renderOrigin.y * CHUNK_SIZEf))
@ -353,7 +353,7 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
fun addLayers(layers: LayeredRenderer) {
for ((baked, zLevel) in backgroundRenderer.bakedMeshes) {
layers.add(zLevel + Z_LEVEL_BACKGROUND) {
it.push().translateWithMultiplication(renderOrigin.x * CHUNK_SIZEf, renderOrigin.y * CHUNK_SIZEf)
it.push().last().translateWithMultiplication(renderOrigin.x * CHUNK_SIZEf, renderOrigin.y * CHUNK_SIZEf)
baked.renderStacked(it)
it.pop()
}
@ -361,7 +361,7 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
for ((baked, zLevel) in foregroundRenderer.bakedMeshes) {
layers.add(zLevel) {
it.push().translateWithMultiplication(renderOrigin.x * CHUNK_SIZEf, renderOrigin.y * CHUNK_SIZEf)
it.push().last().translateWithMultiplication(renderOrigin.x * CHUNK_SIZEf, renderOrigin.y * CHUNK_SIZEf)
baked.renderStacked(it)
it.pop()
}
@ -370,14 +370,14 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
for (renderer in entityRenderers.values) {
layers.add(renderer.layer) {
val relative = renderer.renderPos - posVector2d
it.push().translateWithMultiplication(renderOrigin.x * CHUNK_SIZEf + relative.x.toFloat(), renderOrigin.y * CHUNK_SIZEf + relative.y.toFloat())
it.push().last().translateWithMultiplication(renderOrigin.x * CHUNK_SIZEf + relative.x.toFloat(), renderOrigin.y * CHUNK_SIZEf + relative.y.toFloat())
renderer.render(it)
it.pop()
}
}
layers.add(Z_LEVEL_LIQUID) {
it.push().translateWithMultiplication(renderOrigin.x * CHUNK_SIZEf, renderOrigin.y * CHUNK_SIZEf)
it.push().last().translateWithMultiplication(renderOrigin.x * CHUNK_SIZEf, renderOrigin.y * CHUNK_SIZEf)
val types = ArrayList<LiquidDefinition>()
for (x in 0 until CHUNK_SIZE) {
@ -393,7 +393,7 @@ class ClientChunk(world: ClientWorld, pos: ChunkPos) : Chunk<ClientWorld, Client
val program = state.programs.liquid
program.use()
program.transform = it.last
program.transform = it.last()
val builder = program.builder

View File

@ -63,7 +63,7 @@ class ClientWorld(
client.gl.blendFunc = old
*/
val pos = client.screenToWorld(client.mouseCoordinatesF).toDoubleVector()
val pos = client.screenToWorld(client.mouseCoordinatesF)
/*val lightsize = 16

View File

@ -12,7 +12,6 @@ import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.client.gl.BlendFunc
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
import ru.dbotthepony.kstarbound.client.gl.ScissorRect
import ru.dbotthepony.kstarbound.client.input.UserInput
import ru.dbotthepony.kstarbound.client.render.Camera
import ru.dbotthepony.kstarbound.client.render.GPULightRenderer
@ -22,12 +21,12 @@ import ru.dbotthepony.kstarbound.client.render.TileRenderers
import ru.dbotthepony.kstarbound.util.JVMTimeSource
import ru.dbotthepony.kstarbound.util.PausableTimeSource
import ru.dbotthepony.kstarbound.util.formatBytesShort
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
import ru.dbotthepony.kvector.arrays.Matrix4f
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
import ru.dbotthepony.kvector.vector.nfloat.Vector3f
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector2f
import ru.dbotthepony.kvector.vector.Vector3f
import java.io.Closeable
import java.nio.ByteBuffer
import java.nio.ByteOrder
@ -51,12 +50,14 @@ class StarboundClient(val starbound: Starbound) : Closeable {
*/
var viewportMatrixScreen: Matrix4f
private set
get() = Matrix4f.unmodifiable(field)
/**
* Матрица преобразования мировых координат в нормализованные координаты
*/
var viewportMatrixWorld: Matrix4f
private set
get() = Matrix4f.unmodifiable(field)
private val startupTextList = ArrayList<String>()
private var finishStartupRendering = System.currentTimeMillis() + 4000L
@ -76,11 +77,11 @@ class StarboundClient(val starbound: Starbound) : Closeable {
}
private fun updateViewportMatrixScreen(): Matrix4f {
return Matrix4f.ortho(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 0.1f, 100f).translate(Vector3f(z = 2f)).toMatrix4f()
return Matrix4f.ortho(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 0.1f, 100f).translate(Vector3f(z = 2f))
}
private fun updateViewportMatrixWorld(): Matrix4f {
return Matrix4f.orthoDirect(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 1f, 100f).toMatrix4f()
return Matrix4f.orthoDirect(0f, viewportWidth.toFloat(), 0f, viewportHeight.toFloat(), 1f, 100f)
}
private val xMousePos = ByteBuffer.allocateDirect(8).also { it.order(ByteOrder.LITTLE_ENDIAN) }.asDoubleBuffer()
@ -238,7 +239,7 @@ class StarboundClient(val starbound: Starbound) : Closeable {
init {
putDebugLog("Initialized OpenGL context")
gl.clearColor = Color.SLATE_GREY
gl.clearColor = RGBAColor.SLATE_GRAY
gl.blend = true
gl.blendFunc = BlendFunc.MULTIPLY_WITH_ALPHA
@ -317,11 +318,11 @@ class StarboundClient(val starbound: Starbound) : Closeable {
if (frameRenderTime != 0.0 && starbound.initialized)
world.think(frameRenderTime)
gl.clearColor = Color.SLATE_GREY
gl.clearColor = RGBAColor.SLATE_GRAY
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
gl.matrixStack.clear(viewportMatrixWorld.toMutableMatrix4f())
gl.matrixStack.clear(viewportMatrixWorld)
gl.matrixStack.push()
gl.matrixStack.push().last()
.translateWithMultiplication(viewportWidth / 2f, viewportHeight / 2f, 2f) // центр экрана + координаты отрисовки мира
.scale(x = settings.zoom * PIXELS_IN_STARBOUND_UNITf, y = settings.zoom * PIXELS_IN_STARBOUND_UNITf) // масштабируем до нужного размера
.translateWithMultiplication(-camera.pos.x, -camera.pos.y) // перемещаем вид к камере
@ -351,7 +352,7 @@ class StarboundClient(val starbound: Starbound) : Closeable {
gl.matrixStack.pop()
}
gl.matrixStack.clear(viewportMatrixScreen.toMutableMatrix4f())
gl.matrixStack.clear(viewportMatrixScreen)
val thisTime = System.currentTimeMillis()
@ -363,12 +364,12 @@ class StarboundClient(val starbound: Starbound) : Closeable {
}
gl.matrixStack.push()
gl.matrixStack.translateWithMultiplication(y = viewportHeight.toFloat())
gl.matrixStack.last().translateWithMultiplication(y = viewportHeight.toFloat())
var shade = 255
for (i in startupTextList.size - 1 downTo 0) {
val size = gl.font.render(startupTextList[i], alignY = TextAlignY.BOTTOM, scale = 0.4f, color = Color.SHADES_OF_GRAY[shade].copy(a = alpha))
gl.matrixStack.translateWithMultiplication(y = -size.height * 1.2f)
val size = gl.font.render(startupTextList[i], alignY = TextAlignY.BOTTOM, scale = 0.4f, color = RGBAColor(shade / 255f, shade / 255f, shade / 255f, alpha))
gl.matrixStack.last().translateWithMultiplication(y = -size.height * 1.2f)
if (shade > 120) {
shade -= 10

View File

@ -19,15 +19,13 @@ import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
import ru.dbotthepony.kstarbound.client.render.Box2DRenderer
import ru.dbotthepony.kstarbound.client.render.Font
import ru.dbotthepony.kvector.api.IStruct4f
import ru.dbotthepony.kvector.matrix.Matrix4fStack
import ru.dbotthepony.kvector.arrays.Matrix4fStack
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.RGBAColor
import java.io.File
import java.lang.ref.Cleaner
import java.lang.ref.WeakReference
import java.time.Duration
import java.util.*
import java.util.concurrent.locks.LockSupport
import kotlin.collections.ArrayList
import kotlin.math.roundToInt
import kotlin.properties.ReadWriteProperty
@ -333,7 +331,7 @@ class GLStateTracker(val client: StarboundClient) {
var texture2D: GLTexture2D? by TexturesTracker(80)
var clearColor by GLStateGenericTracker<IStruct4f>(Color.WHITE) {
var clearColor by GLStateGenericTracker<IStruct4f>(RGBAColor.WHITE) {
val (r, g, b, a) = it
glClearColor(r, g, b, a)
}
@ -501,7 +499,7 @@ class GLStateTracker(val client: StarboundClient) {
return obj
}
inline fun quadWireframe(color: Color = Color.WHITE, lambda: (VertexBuilder) -> Unit) {
inline fun quadWireframe(color: RGBAColor = RGBAColor.WHITE, lambda: (VertexBuilder) -> Unit) {
val builder = quadWireframe
builder.builder.begin()
@ -510,7 +508,7 @@ class GLStateTracker(val client: StarboundClient) {
programs.flat.use()
programs.flat.color = color
programs.flat.transform = matrixStack.last
programs.flat.transform = matrixStack.last()
builder.draw(GL_LINES)
}
@ -523,12 +521,12 @@ class GLStateTracker(val client: StarboundClient) {
builder.upload()
programs.flatColor.use()
programs.flatColor.transform = matrixStack.last
programs.flatColor.transform = matrixStack.last()
builder.draw(GL_TRIANGLES)
}
inline fun quadWireframe(value: AABB, color: Color = Color.WHITE, chain: (VertexBuilder) -> Unit = {}) {
inline fun quadWireframe(value: AABB, color: RGBAColor = RGBAColor.WHITE, chain: (VertexBuilder) -> Unit = {}) {
quadWireframe(color) {
it.quad(value.mins.x.toFloat(), value.mins.y.toFloat(), value.maxs.x.toFloat(), value.maxs.y.toFloat())
chain(it)

View File

@ -4,7 +4,7 @@ import org.apache.logging.log4j.LogManager
import org.lwjgl.opengl.GL46.*
import org.lwjgl.stb.STBImage
import ru.dbotthepony.kstarbound.io.ImageData
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kvector.vector.Vector2i
import java.io.File
import java.io.FileNotFoundException
import java.nio.ByteBuffer

View File

@ -4,27 +4,20 @@ import it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap
import it.unimi.dsi.fastutil.objects.Object2BooleanFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.ObjectArraySet
import org.lwjgl.opengl.GL46.*
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
import ru.dbotthepony.kvector.api.IFloatMatrix
import ru.dbotthepony.kvector.api.IStruct2f
import ru.dbotthepony.kvector.api.IStruct3f
import ru.dbotthepony.kvector.api.IStruct4f
import ru.dbotthepony.kvector.api.concrete.IMatrix3f
import ru.dbotthepony.kvector.api.concrete.IMatrix4f
import ru.dbotthepony.kvector.matrix.nfloat.Matrix3f
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
import ru.dbotthepony.kvector.vector.nfloat.Vector3f
import ru.dbotthepony.kvector.vector.nfloat.Vector4f
import ru.dbotthepony.kvector.arrays.Matrix4f
import ru.dbotthepony.kvector.arrays.Matrix3f
import ru.dbotthepony.kvector.vector.Vector2f
import ru.dbotthepony.kvector.vector.Vector3f
import ru.dbotthepony.kvector.vector.Vector4f
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import java.util.*
import java.util.stream.Stream
import kotlin.NoSuchElementException
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
@ -178,32 +171,32 @@ open class GLShaderProgram(val state: GLStateTracker, shaders: Iterable<GLStateT
private val buff3x3: FloatBuffer = ByteBuffer.allocateDirect(4 * 3 * 3).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer()
private val buff4x4: FloatBuffer = ByteBuffer.allocateDirect(4 * 4 * 4).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer()
inner class F3x3Uniform(name: String) : Uniform<IMatrix3f<*>>(name) {
override var value: IMatrix3f<*> = Matrix3f.ZERO
inner class F3x3Uniform(name: String) : Uniform<Matrix3f>(name) {
override var value: Matrix3f = Matrix3f.zero()
set(value) {
state.ensureSameThread()
if (field != value) {
buff3x3.position(0)
value.write(buff3x3)
value.storeColumnRow(buff3x3)
buff3x3.position(0)
glProgramUniformMatrix3fv(pointer, location, false, buff3x3)
checkForGLError()
field = value.toMatrix3f()
field = value.copy()
}
}
}
inner class F4x4Uniform(name: String) : Uniform<IMatrix4f<*>>(name) {
inner class F4x4Uniform(name: String) : Uniform<Matrix4f>(name) {
private val _value = ByteBuffer.allocate(4 * 4 * 4).also { it.order(ByteOrder.nativeOrder()) }.asFloatBuffer()
override var value: IMatrix4f<*> = Matrix4f.ZERO
override var value: Matrix4f = Matrix4f.zero()
set(value) {
state.ensureSameThread()
buff4x4.position(0)
value.write(buff4x4)
value.storeColumnRow(buff4x4)
buff4x4.position(0)
_value.position(0)
@ -212,7 +205,7 @@ open class GLShaderProgram(val state: GLStateTracker, shaders: Iterable<GLStateT
checkForGLError()
buff4x4.position(0)
_value.put(buff4x4)
field = value.toMatrix4f()
field = Matrix4f.unmodifiable(value)
}
}
}

View File

@ -8,8 +8,8 @@ import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
import ru.dbotthepony.kstarbound.client.render.GPULightRenderer
import ru.dbotthepony.kvector.matrix.nfloat.Matrix4f
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.arrays.Matrix4f
import ru.dbotthepony.kvector.vector.RGBAColor
private fun GLStateTracker.shaders(name: String): List<GLStateTracker.Shader> {
return listOf(internalVertex("shaders/$name.vsh"), internalFragment("shaders/$name.fsh"))
@ -103,7 +103,7 @@ class GLColorQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state.s
state.blendFunc = oldFunc
}
fun clearColor(color: Color = Color.WHITE) {
fun clearColor(color: RGBAColor = RGBAColor.WHITE) {
use()
this.color = color
@ -117,7 +117,7 @@ class GLColorQuadProgram(state: GLStateTracker) : GLShaderProgram(state, state.s
companion object {
val FORMAT = GLAttributeList.Builder().push(GLType.VEC2F).build()
val ALPHA = Color(0f, 0f, 0f, 1f)
val ALPHA = RGBAColor(0f, 0f, 0f, 1f)
}
}
@ -187,8 +187,8 @@ class GLTileProgram(state: GLStateTracker) : GLShaderProgram(state, state.shader
var texture by IUniform("texture0")
init {
transform = Matrix4f.IDENTITY
color = Color.WHITE
transform = Matrix4f.identity()
color = RGBAColor.WHITE
}
}
@ -198,8 +198,8 @@ class GLFontProgram(state: GLStateTracker) : GLShaderProgram(state, state.shader
var texture by IUniform("texture0")
init {
transform = Matrix4f.IDENTITY
color = Color.WHITE
transform = Matrix4f.identity()
color = RGBAColor.WHITE
}
}
@ -208,7 +208,7 @@ class GLFlatProgram(state: GLStateTracker) : GLShaderProgram(state, state.shader
var color by F4Uniform("color")
init {
color = Color.WHITE
color = RGBAColor.WHITE
}
}
@ -217,7 +217,7 @@ class GLTexturedProgram(state: GLStateTracker) : GLShaderProgram(state, listOf(s
var texture by IUniform("texture0")
init {
transform = Matrix4f.IDENTITY
transform = Matrix4f.identity()
}
}
@ -227,8 +227,8 @@ class GLTexturedColoredProgram(state: GLStateTracker) : GLShaderProgram(state, l
var color by F4Uniform("color")
init {
transform = Matrix4f.IDENTITY
color = Color.WHITE
transform = Matrix4f.identity()
color = RGBAColor.WHITE
}
}

View File

@ -49,7 +49,6 @@ private fun indexSize(type: Int): Int {
*
* Загрузка в память видеокарты происходит напрямую из буферов, через метод [upload]
*/
@Suppress("unchecked_cast")
class VertexBuilder(
val attributes: GLAttributeList,
val type: GeometryType,

View File

@ -3,8 +3,8 @@ package ru.dbotthepony.kstarbound.client.render
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
import ru.dbotthepony.kstarbound.client.ClientWorld
import ru.dbotthepony.kstarbound.defs.animation.AnimationDefinition
import ru.dbotthepony.kvector.matrix.Matrix4fStack
import ru.dbotthepony.kvector.vector.nfloat.Vector3f
import ru.dbotthepony.kvector.arrays.Matrix4fStack
import ru.dbotthepony.kvector.vector.Vector3f
class Animator(
val world: ClientWorld,
@ -38,10 +38,10 @@ class Animator(
val sprite = mainSprite?.update() ?: return
sprite.texture.bind()
stack.push().translateWithMultiplication(Vector3f(world.client.camera.pos))
stack.push().last().translateWithMultiplication(Vector3f(world.client.camera.pos))
state.programs.textured.use()
state.programs.textured.transform = stack.last
state.programs.textured.transform = stack.last()
state.activeTexture = 0
state.programs.textured.texture = 0

View File

@ -5,8 +5,8 @@ import ru.dbotthepony.kbox2d.api.IDebugDraw
import ru.dbotthepony.kbox2d.api.Transform
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNIT
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2d
import kotlin.math.cos
import kotlin.math.sin
@ -17,7 +17,7 @@ class Box2DRenderer(val state: GLStateTracker) : IDebugDraw {
override var drawPairs: Boolean = false
override var drawCenterOfMess: Boolean = false
override fun drawPolygon(vertices: List<Vector2d>, color: Color) {
override fun drawPolygon(vertices: List<Vector2d>, color: RGBAColor) {
require(vertices.size > 1) { "Vertex list had only ${vertices.size} namings in it" }
val builder = state.flat2DLines
@ -35,12 +35,12 @@ class Box2DRenderer(val state: GLStateTracker) : IDebugDraw {
state.programs.flat.use()
state.programs.flat.color = color
state.programs.flat.transform = state.matrixStack.last
state.programs.flat.transform = state.matrixStack.last()
builder.draw(GL_LINES)
}
private fun drawSolid(vertices: List<Vector2d>, color: Color) {
private fun drawSolid(vertices: List<Vector2d>, color: RGBAColor) {
require(vertices.size >= 3) { "Vertex list had only ${vertices.size} namings in it" }
val builder = state.flat2DTriangles
@ -61,17 +61,17 @@ class Box2DRenderer(val state: GLStateTracker) : IDebugDraw {
state.programs.flat.use()
state.programs.flat.color = color
state.programs.flat.transform = state.matrixStack.last
state.programs.flat.transform = state.matrixStack.last()
builder.draw(GL_TRIANGLES)
}
override fun drawSolidPolygon(vertices: List<Vector2d>, color: Color) {
drawSolid(vertices, color.copy(a = 0.5f))
override fun drawSolidPolygon(vertices: List<Vector2d>, color: RGBAColor) {
drawSolid(vertices, color.copy(alpha = 0.5f))
drawPolygon(vertices, color)
}
override fun drawCircle(center: Vector2d, radius: Double, color: Color) {
override fun drawCircle(center: Vector2d, radius: Double, color: RGBAColor) {
val vertexList = ArrayList<Vector2d>()
for (i in 0 until 360 step 15) {
@ -88,7 +88,7 @@ class Box2DRenderer(val state: GLStateTracker) : IDebugDraw {
drawPolygon(vertexList, color)
}
override fun drawSolidCircle(center: Vector2d, radius: Double, axis: Vector2d, color: Color) {
override fun drawSolidCircle(center: Vector2d, radius: Double, axis: Vector2d, color: RGBAColor) {
val vertexList = ArrayList<Vector2d>()
for (i in 0 until 360 step 15) {
@ -102,12 +102,12 @@ class Box2DRenderer(val state: GLStateTracker) : IDebugDraw {
))
}
drawSolidPolygon(vertexList, color.copy(a = 0.5f))
drawSolidPolygon(vertexList, color.copy(alpha = 0.5f))
drawPolygon(vertexList, color)
drawPolygon(listOf(center, center + axis * radius), color)
}
override fun drawSegment(p1: Vector2d, p2: Vector2d, color: Color) {
override fun drawSegment(p1: Vector2d, p2: Vector2d, color: RGBAColor) {
drawPolygon(listOf(p1, p2), color)
}
@ -115,7 +115,7 @@ class Box2DRenderer(val state: GLStateTracker) : IDebugDraw {
TODO("Not yet implemented")
}
override fun drawPoint(p: Vector2d, size: Double, color: Color) {
override fun drawPoint(p: Vector2d, size: Double, color: RGBAColor) {
drawSolid(listOf(
Vector2d(x = p.x - size / (PIXELS_IN_STARBOUND_UNIT * 2.0), y = p.y - size / (PIXELS_IN_STARBOUND_UNIT * 2.0)),
Vector2d(x = p.x + size / (PIXELS_IN_STARBOUND_UNIT * 2.0), y = p.y - size / (PIXELS_IN_STARBOUND_UNIT * 2.0)),

View File

@ -2,13 +2,13 @@ package ru.dbotthepony.kstarbound.client.render
import org.lwjgl.glfw.GLFW.*
import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kvector.vector.nfloat.MutableVector2f
import ru.dbotthepony.kvector.vector.Vector2f
class Camera(val client: StarboundClient) {
/**
* Позиция этой камеры в Starbound Unit'ах
*/
val pos = MutableVector2f()
var pos = Vector2f()
var pressedLeft = false
private set
@ -43,30 +43,31 @@ class Camera(val client: StarboundClient) {
}
}
val velocity: MutableVector2f get() {
val vec = MutableVector2f()
val velocity: Vector2f get() {
var x = 0f
var y = 0f
if (pressedLeft) {
vec.x -= (FREEVIEW_SENS).toFloat()
x -= (FREEVIEW_SENS).toFloat()
}
if (pressedRight) {
vec.x += (FREEVIEW_SENS).toFloat()
x += (FREEVIEW_SENS).toFloat()
}
if (pressedUp) {
vec.y += (FREEVIEW_SENS).toFloat()
y += (FREEVIEW_SENS).toFloat()
}
if (pressedDown) {
vec.y -= (FREEVIEW_SENS).toFloat()
y -= (FREEVIEW_SENS).toFloat()
}
return vec
return Vector2f(x, y)
}
fun think(delta: Double) {
pos + velocity * delta.toFloat()
pos += velocity * delta.toFloat()
}
companion object {

View File

@ -5,9 +5,8 @@ import ru.dbotthepony.kstarbound.client.gl.shader.GLShaderProgram
import ru.dbotthepony.kstarbound.client.gl.VertexArrayObject
import ru.dbotthepony.kstarbound.client.gl.checkForGLError
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
import ru.dbotthepony.kvector.api.IFloatMatrix
import ru.dbotthepony.kvector.api.concrete.IMatrix4f
import ru.dbotthepony.kvector.matrix.Matrix4fStack
import ru.dbotthepony.kvector.arrays.Matrix4f
import ru.dbotthepony.kvector.arrays.Matrix4fStack
/**
* Служит для быстрой настройки состояния для будущей отрисовки
@ -24,7 +23,7 @@ open class ConfiguredShaderProgram<T : GLShaderProgram>(
) {
private val transformLocation = program.getUniform("transform") as? GLShaderProgram.F4x4Uniform
open fun setTransform(value: IMatrix4f<*>) {
open fun setTransform(value: Matrix4f) {
transformLocation?.value = value
}
@ -74,7 +73,7 @@ class ConfiguredStaticMesh(
ebo.unbind()
}
fun render(transform: IMatrix4f<*>? = null) {
fun render(transform: Matrix4f? = null) {
check(isValid) { "$this is no longer valid" }
programState.setup()
@ -87,7 +86,7 @@ class ConfiguredStaticMesh(
checkForGLError()
}
fun renderStacked(transform: Matrix4fStack) = render(transform.last)
fun renderStacked(transform: Matrix4fStack) = render(transform.last())
var isValid = true
private set

View File

@ -10,8 +10,8 @@ import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
import ru.dbotthepony.kstarbound.client.gl.vertex.VertexBuilder
import ru.dbotthepony.kvector.matrix.Matrix4fStack
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.arrays.Matrix4fStack
import ru.dbotthepony.kvector.vector.RGBAColor
private fun breakLines(text: String): List<String> {
var nextLineBreak = text.indexOf('\n', 0)
@ -87,7 +87,7 @@ class Font(
alignX: TextAlignX = TextAlignX.LEFT,
alignY: TextAlignY = TextAlignY.TOP,
color: Color = Color.WHITE,
color: RGBAColor = RGBAColor.WHITE,
scale: Float = 1f,
stack: Matrix4fStack = state.matrixStack,
@ -104,13 +104,13 @@ class Font(
stack.push()
when (alignY) {
TextAlignY.TOP -> stack.translateWithMultiplication(x = x, y = lineHeight * scale + y)
TextAlignY.CENTER -> stack.translateWithMultiplication(x = x, y = lineHeight * scale - totalY * scale / 2f + y)
TextAlignY.BOTTOM -> stack.translateWithMultiplication(x = x, y = lineHeight * scale - totalY * scale + y)
TextAlignY.TOP -> stack.last().translateWithMultiplication(x = x, y = lineHeight * scale + y)
TextAlignY.CENTER -> stack.last().translateWithMultiplication(x = x, y = lineHeight * scale - totalY * scale / 2f + y)
TextAlignY.BOTTOM -> stack.last().translateWithMultiplication(x = x, y = lineHeight * scale - totalY * scale + y)
}
if (scale != 1f)
stack.scale(x = scale, y = scale)
stack.last().scale(x = scale, y = scale)
state.programs.font.use()
state.programs.font.color = color
@ -122,7 +122,7 @@ class Font(
for (line in text) {
if (line == "") {
stack.translateWithMultiplication(y = lineHeight)
stack.last().translateWithMultiplication(y = lineHeight)
continue
}
@ -133,12 +133,12 @@ class Font(
TextAlignX.CENTER -> {
movedX = totalX / 2f - lineWidth(line, space) / 2f
stack.translateWithMultiplication(x = movedX)
stack.last().translateWithMultiplication(x = movedX)
}
TextAlignX.RIGHT -> {
movedX = -lineWidth(line, space)
stack.translateWithMultiplication(x = movedX)
stack.last().translateWithMultiplication(x = movedX)
}
}
@ -149,10 +149,10 @@ class Font(
if (chr == '\t') {
if (lineGlyphs % 4 == 0) {
advancedX += space.advanceX * 4
stack.translateWithMultiplication(x = space.advanceX * 4)
stack.last().translateWithMultiplication(x = space.advanceX * 4)
} else {
advancedX += space.advanceX * (lineGlyphs % 4)
stack.translateWithMultiplication(x = space.advanceX * (lineGlyphs % 4))
stack.last().translateWithMultiplication(x = space.advanceX * (lineGlyphs % 4))
}
lineGlyphs += lineGlyphs % 4
@ -166,7 +166,7 @@ class Font(
}
advancedX = advancedX.coerceAtLeast(lineWidth)
stack.translateWithMultiplication(x = -lineWidth - movedX, y = lineHeight)
stack.last().translateWithMultiplication(x = -lineWidth - movedX, y = lineHeight)
}
state.VAO = null
@ -184,7 +184,7 @@ class Font(
alignX: TextAlignX = TextAlignX.LEFT,
alignY: TextAlignY = TextAlignY.TOP,
color: Color = Color.WHITE,
color: RGBAColor = RGBAColor.WHITE,
scale: Float = 1f,
stack: Matrix4fStack = state.matrixStack,
@ -209,10 +209,10 @@ class Font(
if (chr == '\t') {
if (lineGlyphs % 4 == 0) {
lineWidth += space.advanceX * 4
state.matrixStack.translateWithMultiplication(x = space.advanceX * 4)
state.matrixStack.last().translateWithMultiplication(x = space.advanceX * 4)
} else {
lineWidth += space.advanceX * (lineGlyphs % 4)
state.matrixStack.translateWithMultiplication(x = space.advanceX * (lineGlyphs % 4))
state.matrixStack.last().translateWithMultiplication(x = space.advanceX * (lineGlyphs % 4))
}
lineGlyphs += lineGlyphs % 4
@ -334,20 +334,20 @@ class Font(
fun render(stack: Matrix4fStack) {
if (isEmpty) {
stack.translateWithMultiplication(advanceX)
stack.last().translateWithMultiplication(advanceX)
return
}
vao!!.bind()
stack.translateWithMultiplication(bearingX, -bearingY)
stack.last().translateWithMultiplication(bearingX, -bearingY)
texture!!.bind()
state.programs.font.transform = stack.last
state.programs.font.transform = stack.last()
glDrawElements(GL_TRIANGLES, indexCount, elementIndexType, 0L)
checkForGLError()
stack.translateWithMultiplication(advanceX - bearingX, bearingY)
stack.last().translateWithMultiplication(advanceX - bearingX, bearingY)
}
override fun close() {

View File

@ -16,10 +16,10 @@ import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
import ru.dbotthepony.kstarbound.client.gl.vertex.GeometryType
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
import ru.dbotthepony.kstarbound.client.gl.vertex.StreamVertexBuilder
import ru.dbotthepony.kvector.matrix.Matrix4fStack
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
import ru.dbotthepony.kvector.vector.nfloat.Vector3f
import ru.dbotthepony.kvector.arrays.Matrix4fStack
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2f
import ru.dbotthepony.kvector.vector.Vector3f
// Huge thanks to articles by Scott [slembcke] Lembcke!
// https://slembcke.github.io/SuperFastHardShadows
@ -70,7 +70,7 @@ class GPULightRenderer(val state: GLStateTracker) {
}
val old = state.clearColor
state.clearColor = Color.BLACK
state.clearColor = RGBAColor.BLACK
framebufferRender.bind()
glClear(GL_COLOR_BUFFER_BIT)
@ -137,7 +137,7 @@ class GPULightRenderer(val state: GLStateTracker) {
fun renderHardLight(
position: Vector2f,
color: Color = Color.WHITE,
color: RGBAColor = RGBAColor.WHITE,
radius: Float = 10f,
lightPenetration: Float = 0.1f,
stack: Matrix4fStack = state.matrixStack
@ -164,7 +164,7 @@ class GPULightRenderer(val state: GLStateTracker) {
state.clearColor = old
state.programs.hardLightGeometry.use()
state.programs.hardLightGeometry.transform = (stack.last)
state.programs.hardLightGeometry.transform = (stack.last())
state.programs.hardLightGeometry.lightPosition = (position)
state.programs.hardLightGeometry.lightPenetration = (1f - lightPenetration)
@ -175,7 +175,7 @@ class GPULightRenderer(val state: GLStateTracker) {
}
state.programs.light.use()
state.programs.light.transform = (stack.last)
state.programs.light.transform = (stack.last())
state.programs.light.baselineColor = (color)
// Свет
@ -197,7 +197,7 @@ class GPULightRenderer(val state: GLStateTracker) {
fun renderSoftLight(
position: Vector2f,
color: Color = Color.WHITE,
color: RGBAColor = RGBAColor.WHITE,
radius: Float = 10f,
innerRadius: Float = radius / 3f,
lightPenetration: Float = 0.5f,
@ -225,7 +225,7 @@ class GPULightRenderer(val state: GLStateTracker) {
state.clearColor = old
state.programs.softLightGeometry.use()
state.programs.softLightGeometry.transform = (stack.last)
state.programs.softLightGeometry.transform = (stack.last())
state.programs.softLightGeometry.lightPositionAndSize = (Vector3f(position, innerRadius))
state.programs.softLightGeometry.lightPenetration = (lightPenetration)
@ -241,7 +241,7 @@ class GPULightRenderer(val state: GLStateTracker) {
state.cull = false
state.programs.light.use()
state.programs.light.transform = (stack.last)
state.programs.light.transform = (stack.last())
state.programs.light.baselineColor = (color)
// Свет
@ -283,8 +283,8 @@ class GPULightRenderer(val state: GLStateTracker) {
}
companion object {
val CLEAR_COLOR_HARD = Color(0f, 0f, 0f, 0f)
val CLEAR_COLOR_SOFT = Color(0f, 0f, 0f, 0f)
val CLEAR_COLOR_HARD = RGBAColor(0f, 0f, 0f, 0f)
val CLEAR_COLOR_SOFT = RGBAColor(0f, 0f, 0f, 0f)
val BLEND_MODE = BlendFunc(
BlendFunc.Func.DST_ALPHA,

View File

@ -1,9 +1,8 @@
package ru.dbotthepony.kstarbound.client.render
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.ints.Int2ObjectFunction
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import ru.dbotthepony.kvector.matrix.Matrix4fStack
import ru.dbotthepony.kvector.arrays.Matrix4fStack
/**
* Позволяет вызывать отрисовщики в определённой (послойной) последовательности

View File

@ -12,9 +12,10 @@ import ru.dbotthepony.kstarbound.client.gl.vertex.GLAttributeList
import ru.dbotthepony.kstarbound.client.gl.vertex.*
import ru.dbotthepony.kstarbound.defs.tile.*
import ru.dbotthepony.kstarbound.world.ITileChunk
import ru.dbotthepony.kstarbound.world.ITileState
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kstarbound.world.TileColor
import ru.dbotthepony.kstarbound.world.TileState
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2i
import kotlin.collections.HashMap
data class TileLayer(
@ -152,15 +153,15 @@ class TileRenderers(val client: StarboundClient) {
}
/**
* Возвращает запечённое состояние шейдера shaderVertexTextureColor с данной текстурой
* Возвращает запечённое состояние шейдера shaderVertexTextureRGBAColor с данной текстурой
*/
fun background(texture: GLTexture2D): ConfiguredShaderProgram<GLTileProgram> {
return backgroundTilePrograms.computeIfAbsent(texture, ::BackgroundTileProgram)
}
companion object {
val BACKGROUND_COLOR = Color(0.4f, 0.4f, 0.4f)
val FOREGROUND_COLOR = Color(1f, 1f, 1f)
val BACKGROUND_COLOR = RGBAColor(0.4f, 0.4f, 0.4f)
val FOREGROUND_COLOR = RGBAColor(1f, 1f, 1f)
}
}
@ -173,13 +174,13 @@ private enum class TileRenderTesselateResult {
private fun vertexTextureBuilder() = VertexBuilder(GLAttributeList.TILE, GeometryType.QUADS)
private class TileEqualityTester(val definition: TileDefinition) : EqualityRuleTester {
override fun test(thisTile: ITileState, otherTile: ITileState): Boolean {
override fun test(thisTile: TileState, otherTile: TileState): Boolean {
return otherTile.material == definition && thisTile.hueShift == otherTile.hueShift
}
}
private class ModifierEqualityTester(val definition: MaterialModifier) : EqualityRuleTester {
override fun test(thisTile: ITileState, otherTile: ITileState): Boolean {
override fun test(thisTile: TileState, otherTile: TileState): Boolean {
return otherTile.modifier == definition
}
}
@ -200,7 +201,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
val bakedBackgroundProgramState = renderers.background(texture)
// private var notifiedDepth = false
private fun tesselateAt(self: ITileState, piece: RenderPiece, getter: ITileChunk, builder: VertexBuilder, pos: Vector2i, offset: Vector2i = Vector2i.ZERO, isModifier: Boolean) {
private fun tesselateAt(self: TileState, piece: RenderPiece, getter: ITileChunk, builder: VertexBuilder, pos: Vector2i, offset: Vector2i = Vector2i.ZERO, isModifier: Boolean) {
val fx = pos.x.toFloat()
val fy = pos.y.toFloat()
@ -230,9 +231,9 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
maxs += piece.variantStride * variant
}
if (def.renderParameters.multiColored && piece.colorStride != null && self.color != 0) {
mins += piece.colorStride * self.color
maxs += piece.colorStride * self.color
if (def.renderParameters.multiColored && piece.colorStride != null && self.color != TileColor.DEFAULT) {
mins += piece.colorStride * self.color.ordinal
maxs += piece.colorStride * self.color.ordinal
}
val (u0, v0) = texture.pixelToUV(mins)
@ -242,7 +243,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
}
private fun tesselatePiece(
self: ITileState,
self: TileState,
matchPiece: RenderMatch,
getter: ITileChunk,
layers: TileLayerList,
@ -293,7 +294,7 @@ class TileRenderer(val renderers: TileRenderers, val def: IRenderableTile) {
*
* Тесселирует тайлы в нужный VertexBuilder с масштабом согласно константе [PIXELS_IN_STARBOUND_UNITf]
*/
fun tesselate(self: ITileState, getter: ITileChunk, layers: TileLayerList, pos: Vector2i, background: Boolean = false, isModifier: Boolean = false) {
fun tesselate(self: TileState, getter: ITileChunk, layers: TileLayerList, pos: Vector2i, background: Boolean = false, isModifier: Boolean = false) {
// если у нас нет renderTemplate
// то мы просто не можем его отрисовать
val template = def.renderTemplate.value ?: return

View File

@ -5,8 +5,8 @@ import ru.dbotthepony.kstarbound.client.ClientChunk
import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kvector.matrix.Matrix4fStack
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.arrays.Matrix4fStack
import ru.dbotthepony.kvector.vector.Vector2d
import java.io.Closeable
/**

View File

@ -5,7 +5,7 @@ import ru.dbotthepony.kstarbound.client.ClientChunk
import ru.dbotthepony.kstarbound.client.StarboundClient
import ru.dbotthepony.kstarbound.client.render.RebindableSprite
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
import ru.dbotthepony.kvector.matrix.Matrix4fStack
import ru.dbotthepony.kvector.arrays.Matrix4fStack
class ItemRenderer(client: StarboundClient, entity: ItemEntity, chunk: ClientChunk?) : EntityRenderer(client, entity, chunk) {
private val def = entity.def
@ -16,7 +16,7 @@ class ItemRenderer(client: StarboundClient, entity: ItemEntity, chunk: ClientChu
return
state.programs.textured.use()
state.programs.textured.transform = stack.last
state.programs.textured.transform = stack.last()
state.activeTexture = 0
state.programs.textured.texture = 0

View File

@ -10,12 +10,10 @@ import com.google.gson.reflect.TypeToken
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.io.json.InternedJsonElementAdapter
import ru.dbotthepony.kstarbound.io.json.builder.EnumAdapter
import ru.dbotthepony.kstarbound.io.json.builder.IStringSerializable
import ru.dbotthepony.kstarbound.io.json.Vector2dTypeAdapter
import ru.dbotthepony.kvector.util.linearInterpolation
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
enum class JsonFunctionInterpolation {
LINEAR {

View File

@ -2,7 +2,7 @@ package ru.dbotthepony.kstarbound.defs
import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
@JsonFactory
data class MovementParameters(

View File

@ -5,7 +5,7 @@ import com.google.common.collect.ImmutableMap
import ru.dbotthepony.kstarbound.defs.image.ImageReference
import ru.dbotthepony.kstarbound.defs.particle.ParticleEmitter
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
@JsonFactory
data class AnimationDefinition(

View File

@ -14,8 +14,8 @@ import ru.dbotthepony.kstarbound.api.ISBFileLocator
import ru.dbotthepony.kstarbound.client.gl.GLTexture2D
import ru.dbotthepony.kstarbound.io.json.stream
import ru.dbotthepony.kstarbound.util.PathStack
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kvector.vector.nint.Vector4i
import ru.dbotthepony.kvector.vector.Vector2i
import ru.dbotthepony.kvector.vector.Vector4i
import java.util.concurrent.ConcurrentHashMap
/**

View File

@ -1,7 +1,7 @@
package ru.dbotthepony.kstarbound.defs.item.api
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2d
interface IFlashlightDefinition : IItemDefinition, IItemInHandDefinition {
/**
@ -9,7 +9,7 @@ interface IFlashlightDefinition : IItemDefinition, IItemInHandDefinition {
*/
val lightPosition: Vector2d
val lightColor: Color
val lightColor: RGBAColor
val beamLevel: Int

View File

@ -1,7 +1,6 @@
package ru.dbotthepony.kstarbound.defs.item.api
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
interface IItemInHandDefinition : IItemDefinition {
/**

View File

@ -4,8 +4,8 @@ import ru.dbotthepony.kstarbound.defs.item.api.IFlashlightDefinition
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.io.json.builder.JsonFlat
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2d
@JsonFactory
class FlashlightDefinition(
@ -13,7 +13,7 @@ class FlashlightDefinition(
val parent: IItemDefinition,
override val lightPosition: Vector2d,
override val lightColor: Color,
override val lightColor: RGBAColor,
override val beamLevel: Int,
override val beamAmbience: Double,
override val handPosition: Vector2d,

View File

@ -3,10 +3,9 @@ package ru.dbotthepony.kstarbound.defs.item.impl
import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.defs.item.api.IHarvestingToolDefinition
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
import ru.dbotthepony.kstarbound.io.json.builder.JsonBuilder
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.io.json.builder.JsonFlat
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
@JsonFactory
class HarvestingToolPrototype(

View File

@ -5,7 +5,7 @@ import ru.dbotthepony.kstarbound.defs.animation.DestructionAction
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation
import ru.dbotthepony.kstarbound.util.VirtualProperty
import ru.dbotthepony.kstarbound.util.SBPattern
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
@JsonImplementation(ParticleConfig::class)
interface IParticleConfig : IParticleVariance {

View File

@ -3,9 +3,9 @@ package ru.dbotthepony.kstarbound.defs.particle
import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.io.json.builder.JsonImplementation
import ru.dbotthepony.kstarbound.util.VirtualProperty
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.ndouble.Vector4d
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector4d
@JsonImplementation(ParticleVariance::class)
interface IParticleVariance {
@ -16,7 +16,7 @@ interface IParticleVariance {
val approach: Vector2d?
val angularVelocity: Double?
val size: Double?
val color: Color?
val color: RGBAColor?
companion object {
fun chain(vararg particles: IParticleVariance): IParticleVariance {

View File

@ -6,9 +6,9 @@ import ru.dbotthepony.kstarbound.defs.animation.DestructionAction
import ru.dbotthepony.kstarbound.defs.image.ImageReference
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.util.SBPattern
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.ndouble.Vector4d
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector4d
@JsonFactory
data class ParticleConfig(
@ -29,6 +29,6 @@ data class ParticleConfig(
override val layer: ParticleLayer? = null,
override val timeToLive: Double? = null,
override val variance: IParticleVariance? = null,
override val color: Color? = null,
override val color: RGBAColor? = null,
override val text: SBPattern? = null,
) : IParticleConfig

View File

@ -4,9 +4,9 @@ import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.defs.animation.DestructionAction
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.util.SBPattern
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.ndouble.Vector4d
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector4d
@JsonFactory
data class ParticleEmitter(
@ -30,6 +30,6 @@ data class ParticleEmitter(
override val layer: ParticleLayer? = null,
override val timeToLive: Double? = null,
override val variance: IParticleVariance? = null,
override val color: Color? = null,
override val color: RGBAColor? = null,
override val text: SBPattern? = null,
) : IParticleConfig

View File

@ -1,9 +1,9 @@
package ru.dbotthepony.kstarbound.defs.particle
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.ndouble.Vector4d
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector4d
@JsonFactory
data class ParticleVariance(
@ -14,5 +14,5 @@ data class ParticleVariance(
override val approach: Vector2d? = null,
override val angularVelocity: Double? = null,
override val size: Double? = null,
override val color: Color? = null,
override val color: RGBAColor? = null,
) : IParticleVariance

View File

@ -2,7 +2,7 @@ package ru.dbotthepony.kstarbound.defs.player
import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
@JsonFactory
data class MatterManipulatorConfig(

View File

@ -13,8 +13,8 @@ import ru.dbotthepony.kstarbound.defs.animation.AnimationDefinition
import ru.dbotthepony.kstarbound.defs.item.api.IItemDefinition
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2d
@JsonFactory
data class PlayerDefinition(
@ -24,7 +24,7 @@ data class PlayerDefinition(
val collectableUnlock: SBPattern,
val species: ImmutableSet<RegistryReference<Species>>,
val nametagColor: Color,
val nametagColor: RGBAColor,
val ageItemsEvery: Int,
val defaultItems: ImmutableSet<RegistryReference<IItemDefinition>>,

View File

@ -1,8 +1,8 @@
package ru.dbotthepony.kstarbound.defs.player
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.RGBAColor
import ru.dbotthepony.kvector.vector.Vector2d
@JsonFactory
data class SplashConfig(
@ -21,7 +21,7 @@ data class SplashConfig(
val position: Vector2d,
val finalVelocity: Vector2d,
val approach: Vector2d,
val color: Color,
val color: RGBAColor,
val size: Double,
val timeToLive: Double,
val destructionAction: String,

View File

@ -3,7 +3,7 @@ package ru.dbotthepony.kstarbound.defs.player
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableMap
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
@JsonFactory
data class StatusControllerSettings(

View File

@ -4,7 +4,7 @@ import com.google.common.collect.ImmutableList
import ru.dbotthepony.kstarbound.defs.RegistryReference
import ru.dbotthepony.kstarbound.defs.StatusEffectDefinition
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.RGBAColor
@JsonFactory
data class LiquidDefinition(
@ -12,12 +12,12 @@ data class LiquidDefinition(
val liquidId: Int,
val description: String = "...",
val tickDelta: Int = 1,
val color: Color,
val color: RGBAColor,
val itemDrop: String? = null,
val statusEffects: ImmutableList<RegistryReference<StatusEffectDefinition>> = ImmutableList.of(),
val interactions: ImmutableList<Interaction> = ImmutableList.of(),
val texture: String,
val bottomLightMix: Color,
val bottomLightMix: RGBAColor,
val textureMovementFactor: Double,
) {
@JsonFactory

View File

@ -1,13 +1,8 @@
package ru.dbotthepony.kstarbound.defs.tile
import com.google.gson.GsonBuilder
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.defs.image.ImageReference
import ru.dbotthepony.kstarbound.io.json.builder.FactoryAdapter
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
const val TILE_COLOR_VARIANTS = 9
@JsonFactory
data class RenderParameters(
val texture: ImageReference,

View File

@ -7,8 +7,8 @@ import org.apache.logging.log4j.LogManager
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.util.WriteOnce
import ru.dbotthepony.kstarbound.world.ITileGetter
import ru.dbotthepony.kstarbound.world.ITileState
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kstarbound.world.TileState
import ru.dbotthepony.kvector.vector.Vector2i
@JsonFactory
data class RenderPiece(
@ -20,7 +20,7 @@ data class RenderPiece(
)
fun interface EqualityRuleTester {
fun test(thisTile: ITileState, otherTile: ITileState): Boolean
fun test(thisTile: TileState, otherTile: TileState): Boolean
}
@JsonFactory
@ -40,8 +40,8 @@ data class RenderRuleList(
) {
private fun doTest(getter: ITileGetter, equalityTester: EqualityRuleTester, thisPos: Vector2i, offsetPos: Vector2i): Boolean {
return when (type) {
"EqualsSelf" -> equalityTester.test(getter[thisPos], getter[thisPos + offsetPos])
"Connects" -> getter[thisPos + offsetPos].material != null
"EqualsSelf" -> equalityTester.test(getter.getTile(thisPos), getter.getTile(thisPos + offsetPos))
"Connects" -> getter.getTile(thisPos + offsetPos).material != null
else -> {
if (LOGGED.add(type)) {

View File

@ -6,13 +6,13 @@ import ru.dbotthepony.kstarbound.defs.IThingWithDescription
import ru.dbotthepony.kstarbound.defs.ThingDescription
import ru.dbotthepony.kstarbound.io.json.builder.JsonFactory
import ru.dbotthepony.kstarbound.io.json.builder.JsonFlat
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.RGBAColor
@JsonFactory
data class TileDefinition(
val materialId: Int,
val materialName: String,
val particleColor: Color? = null,
val particleColor: RGBAColor? = null,
val itemDrop: String? = null,
val footstepSound: String? = null,
val miningSounds: ImmutableList<String> = ImmutableList.of(),

View File

@ -4,8 +4,8 @@ import org.lwjgl.stb.STBImage
import org.lwjgl.system.MemoryUtil.memAddress
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 ru.dbotthepony.kvector.vector.Vector2i
import ru.dbotthepony.kvector.vector.Vector4i
import java.lang.ref.Cleaner
import java.nio.ByteBuffer

View File

@ -5,8 +5,8 @@ import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.util2d.AABBi
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector2i
object AABBTypeAdapter : TypeAdapter<AABB>() {
override fun write(out: JsonWriter, value: AABB) {

View File

@ -1,17 +1,17 @@
package ru.dbotthepony.kstarbound.io
package ru.dbotthepony.kstarbound.io.json
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kvector.vector.Color
import ru.dbotthepony.kvector.vector.RGBAColor
object ColorTypeAdapter : TypeAdapter<Color>() {
override fun write(out: JsonWriter, value: Color) {
object ColorTypeAdapter : TypeAdapter<RGBAColor>() {
override fun write(out: JsonWriter, value: RGBAColor) {
TODO("Not yet implemented")
}
override fun read(`in`: JsonReader): Color {
override fun read(`in`: JsonReader): RGBAColor {
when (val type = `in`.peek()) {
JsonToken.BEGIN_ARRAY -> {
`in`.beginArray()
@ -23,7 +23,7 @@ object ColorTypeAdapter : TypeAdapter<Color>() {
val alpha = `in`.peek().let { if (it == JsonToken.END_ARRAY) 255.0 else `in`.nextDouble() }
`in`.endArray()
return Color(
return RGBAColor(
red.toFloat() / 255f,
green.toFloat() / 255f,
blue.toFloat() / 255f,
@ -33,7 +33,7 @@ object ColorTypeAdapter : TypeAdapter<Color>() {
val alpha = `in`.peek().let { if (it == JsonToken.END_ARRAY) 1.0 else `in`.nextDouble() }
`in`.endArray()
return Color(
return RGBAColor(
red.toFloat(),
green.toFloat(),
blue.toFloat(),
@ -63,18 +63,18 @@ object ColorTypeAdapter : TypeAdapter<Color>() {
`in`.endObject()
if (values == 0) {
throw IllegalArgumentException("Object is not a color")
throw IllegalArgumentException("Object is not a RGBAColor")
}
if (red % 1.0 == 0.0 && green % 1.0 == 0.0 && blue % 1.0 == 0.0 && alpha % 1.0 == 0.0) {
return Color(
return RGBAColor(
red.toFloat() / 255f,
green.toFloat() / 255f,
blue.toFloat() / 255f,
alpha.toFloat() / 255f,
)
} else {
return Color(
return RGBAColor(
red.toFloat(),
green.toFloat(),
blue.toFloat(),
@ -83,10 +83,11 @@ object ColorTypeAdapter : TypeAdapter<Color>() {
}
}
JsonToken.NUMBER -> return Color(`in`.nextInt())
JsonToken.NUMBER -> return RGBAColor.rgb(`in`.nextInt())
JsonToken.STRING -> {
val name = `in`.nextString()
return Color.PRE_DEFINED_MAP[name] ?: throw IllegalArgumentException("Unknown pre defined color name $name")
//return RGBAColor.PRE_DEFINED_MAP[name] ?: throw IllegalArgumentException("Unknown pre defined RGBAColor name $name")
TODO()
}
else -> throw IllegalArgumentException("Expected array, object or number; got $type")

View File

@ -3,11 +3,11 @@ package ru.dbotthepony.kstarbound.io.json
import com.google.gson.TypeAdapter
import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.ndouble.Vector4d
import ru.dbotthepony.kvector.vector.nfloat.Vector2f
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kvector.vector.nint.Vector4i
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector4d
import ru.dbotthepony.kvector.vector.Vector2f
import ru.dbotthepony.kvector.vector.Vector2i
import ru.dbotthepony.kvector.vector.Vector4i
object Vector4iTypeAdapter : TypeAdapter<Vector4i>() {
override fun write(out: JsonWriter, value: Vector4i) {

View File

@ -13,8 +13,6 @@ import com.kenai.jffi.ClosureManager
import com.kenai.jffi.MemoryIO
import com.kenai.jffi.Type
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import jnr.ffi.Memory
import jnr.ffi.NativeType
import jnr.ffi.Pointer
import org.apache.logging.log4j.LogManager
import org.lwjgl.system.MemoryStack
@ -22,9 +20,10 @@ import org.lwjgl.system.MemoryUtil
import ru.dbotthepony.kstarbound.RegistryObject
import ru.dbotthepony.kstarbound.Starbound
import ru.dbotthepony.kstarbound.io.json.InternedJsonElementAdapter
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kvector.vector.nint.Vector3i
import ru.dbotthepony.kvector.vector.nint.Vector4i
import ru.dbotthepony.kvector.api.IStruct2i
import ru.dbotthepony.kvector.api.IStruct3i
import ru.dbotthepony.kvector.api.IStruct4i
import ru.dbotthepony.kvector.vector.Vector2i
import java.io.Closeable
import java.lang.ref.Cleaner
import java.lang.ref.WeakReference
@ -758,7 +757,7 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
LuaJNR.INSTANCE.lua_pushboolean(this.pointer, if (value) 1 else 0)
}
fun push(value: Vector4i) {
fun push(value: IStruct4i) {
pushTable(arraySize = 4)
val table = stackTop
val (x, y, z, w) = value
@ -780,7 +779,7 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
setTableValue(table)
}
fun push(value: Vector3i) {
fun push(value: IStruct3i) {
pushTable(arraySize = 3)
val table = stackTop
val (x, y, z) = value
@ -798,7 +797,7 @@ class LuaState private constructor(private val pointer: Pointer, val stringInter
setTableValue(table)
}
fun push(value: Vector2i) {
fun push(value: IStruct2i) {
pushTable(arraySize = 2)
val table = stackTop
val (x, y) = value

View File

@ -3,7 +3,7 @@ package ru.dbotthepony.kstarbound.math
import ru.dbotthepony.kstarbound.world.ChunkPos
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.util2d.AABBi
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kvector.vector.Vector2i
fun AABB.encasingIntAABB(): AABBi {
return AABBi(

View File

@ -6,7 +6,7 @@ import com.google.gson.stream.JsonReader
import com.google.gson.stream.JsonToken
import com.google.gson.stream.JsonWriter
import ru.dbotthepony.kstarbound.io.json.Vector2dTypeAdapter
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
class Poly(vararg points: Vector2d) {
val points: List<Vector2d> = ImmutableList.copyOf(points)

View File

@ -5,28 +5,17 @@ import ru.dbotthepony.kbox2d.api.FixtureDef
import ru.dbotthepony.kbox2d.collision.shapes.PolygonShape
import ru.dbotthepony.kbox2d.dynamics.B2Fixture
import ru.dbotthepony.kstarbound.defs.tile.LiquidDefinition
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
import ru.dbotthepony.kstarbound.defs.tile.TILE_COLOR_VARIANTS
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
import ru.dbotthepony.kstarbound.util.NotNullTwoDimensionalArray
import ru.dbotthepony.kstarbound.util.TwoDimensionalArray
import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kstarbound.world.phys.RectTileFlooderDepthFirst
import ru.dbotthepony.kstarbound.world.phys.RectTileFlooderSizeFirst
import ru.dbotthepony.kvector.arrays.Object2DArray
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashSet
private fun ccwSortScore(point: Vector2d, axis: Vector2d): Double {
if (point.x > 0.0) {
return point.dot(axis)
} else {
return -2 - point.dot(axis)
}
}
/**
* Чанк мира
*
@ -111,117 +100,6 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
}
inner class TileLayer : IMutableTileChunk {
inner class TileState(def: TileDefinition? = null) : IMutableTileState {
override var material: TileDefinition? = def
set(value) {
if (value !== field) {
field = value
color = 0
hueShift = 0f
collisionChangeset++
this@TileLayer.changeset++
this@Chunk.changeset++
this@Chunk.tileChangeset++
markPhysicsDirty()
}
}
override var color = 0
set(value) {
val material = material
if (material == null) {
field = 0
return
}
if (value != field) {
if (!material.renderParameters.multiColored) {
throw IllegalStateException("${material.materialName} can't be colored")
}
if (value !in 0 until TILE_COLOR_VARIANTS) {
throw IndexOutOfBoundsException("Tile variant $value is out of possible range 0 to $TILE_COLOR_VARIANTS")
}
field = value
this@TileLayer.changeset++
this@Chunk.changeset++
this@Chunk.tileChangeset++
}
}
override var hueShift = 0f
set(value) {
var newValue = value % 360f
if (newValue < 0f) {
newValue += 360f
}
if (newValue != field) {
field = newValue
this@TileLayer.changeset++
this@Chunk.changeset++
this@Chunk.tileChangeset++
}
}
override var modifierHueShift = 0f
set(value) {
var newValue = value % 360f
if (newValue < 0f) {
newValue += 360f
}
if (newValue != field) {
field = newValue
this@TileLayer.changeset++
this@Chunk.changeset++
this@Chunk.tileChangeset++
}
}
override var modifier: MaterialModifier? = null
set(value) {
if (value != field) {
field = value
modifierHueShift = 0f
this@TileLayer.changeset++
this@Chunk.changeset++
this@Chunk.tileChangeset++
}
}
override fun equals(other: Any?): Boolean {
return other is Chunk<*, *>.TileLayer.TileState &&
other.color == color &&
other.modifier === modifier &&
other.modifierHueShift == modifierHueShift &&
other.hueShift == hueShift &&
other.material === material
}
override fun toString(): String {
return "TileState[${this@TileLayer}, material = ${material?.materialName}, color = $color, modifier = ${modifier?.modName}]"
}
override fun hashCode(): Int {
var result = this@TileLayer.hashCode()
result = 31 * result + material.hashCode()
result = 31 * result + color
result = 31 * result + (modifier?.hashCode() ?: 0)
return result
}
}
/**
* Возвращает счётчик изменений этого слоя
*/
@ -284,100 +162,6 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
}
}
}
/*
val seen = BooleanArray(CHUNK_SIZE * CHUNK_SIZE)
for (y in 0 .. CHUNK_SIZE_FF) {
for (x in 0 .. CHUNK_SIZE_FF) {
if (!seen[x or (y shl CHUNK_SHIFT)] && tiles[x or (y shl CHUNK_SHIFT)] != null) {
val exposed = TileFlooder(tiles, seen, x, y).exposed
if (exposed.size > 0) {
val vertices = ArrayList<Vector2d>()
var centroid = Vector2d.ZERO
for (pos in exposed) {
centroid += pos.pos
}
centroid /= exposed.size.toDouble()
for (pos in exposed) {
if (pos.left) {
vertices.addU(pos.pos + Vector2d(-0.5, -0.5))
vertices.addU(pos.pos + Vector2d(-0.5, 0.5))
}
if (pos.up) {
vertices.addU(pos.pos + Vector2d(-0.5, 0.5))
vertices.addU(pos.pos + Vector2d(0.5, 0.5))
}
if (pos.right) {
vertices.addU(pos.pos + Vector2d(0.5, 0.5))
vertices.addU(pos.pos + Vector2d(0.5, -0.5))
}
if (pos.down) {
vertices.addU(pos.pos + Vector2d(0.5, -0.5))
vertices.addU(pos.pos + Vector2d(-0.5, -0.5))
}
}
for (i in vertices.indices) {
vertices[i] -= centroid
}
vertices.sortWith { a, b ->
val scoreA = ccwSortScore(a.normalized, Vector2d.POSITIVE_Y)
val scoreB = ccwSortScore(b.normalized, Vector2d.POSITIVE_Y)
if (scoreA == scoreB) {
return@sortWith 0
} else if (scoreA > scoreB) {
return@sortWith 1
} else {
return@sortWith -1
}
}
for (i in vertices.indices) {
vertices[i] += centroid
}
val deflated = ArrayList<Vector2d>()
var edge = vertices[0]
deflated.add(edge)
for (i in 1 until vertices.size) {
if (vertices[i].x == edge.x) {
// expand along X axis
continue
} else if (vertices[i].y == edge.y) {
// expand along Y axis
continue
}
// completely different direction
if (deflated.indexOf(vertices[i - 1]) == -1)
deflated.add(vertices[i - 1])
if (deflated.indexOf(vertices[i]) == -1)
deflated.add(vertices[i])
edge = vertices[i]
}
collisionChains.add(body.createFixture(FixtureDef(
shape = ChainShape().also { it.createLoop(vertices) },
friction = 0.4,
)))
}
}
}
}*/
}
/**
@ -409,12 +193,20 @@ abstract class Chunk<WorldType : World<WorldType, This>, This : Chunk<WorldType,
/**
* Хранит тайлы как x + y * CHUNK_SIZE
*/
private val tiles: NotNullTwoDimensionalArray<TileState> = NotNullTwoDimensionalArray(CHUNK_SIZE, CHUNK_SIZE) { _, _ -> TileState() }
private val tiles: Object2DArray<TileState> = Object2DArray(CHUNK_SIZE, CHUNK_SIZE, TileState.EMPTY)
override operator fun get(x: Int, y: Int): TileState {
override fun getTile(x: Int, y: Int): TileState {
return tiles[x, y]
}
override fun setTile(x: Int, y: Int, value: TileState) {
tiles[x, y] = value
tileChangeset++
changeset++
collisionChangeset++
this@Chunk.changeset++
}
override fun randomLongFor(x: Int, y: Int): Long {
return super.randomLongFor(x, y) xor world.seed
}

View File

@ -1,8 +1,7 @@
package ru.dbotthepony.kstarbound.world
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kvector.api.IStruct2i
import ru.dbotthepony.kvector.vector.Vector2i
const val CHUNK_SHIFT = 5
const val CHUNK_SIZE = 1 shl CHUNK_SHIFT // 32
@ -11,48 +10,6 @@ const val CHUNK_SIZE_FF = CHUNK_SIZE - 1
const val CHUNK_SIZEf = CHUNK_SIZE.toFloat()
const val CHUNK_SIZEd = CHUNK_SIZE.toDouble()
interface ITileState {
val material: TileDefinition?
val modifier: MaterialModifier?
val color: Int
val hueShift: Float
val modifierHueShift: Float
}
interface IMutableTileState : ITileState {
override var material: TileDefinition?
override var modifier: MaterialModifier?
override var color: Int
override var hueShift: Float
override var modifierHueShift: Float
/**
* Выставляет hue shift как байтовое значение в диапазоне 0 .. 255
*/
fun setHueShift(value: Int) {
if (value < 0) {
hueShift = 0f
} else if (value > 255) {
hueShift = 360f
} else {
hueShift = (value / 255f) * 360f
}
}
/**
* Выставляет hue shift как байтовое значение в диапазоне 0 .. 255
*/
fun setModifierHueShift(value: Int) {
if (value < 0) {
modifierHueShift = 0f
} else if (value > 255) {
modifierHueShift = 360f
} else {
modifierHueShift = (value / 255f) * 360f
}
}
}
interface ITileMap {
/**
* Относительная проверка находится ли координата вне границ чанка
@ -63,52 +20,49 @@ interface ITileMap {
}
/**
* Предоставляет интерфейс для доступа к тайлам в чанке
* Предоставляет интерфейс для доступа к тайлам
*/
interface ITileGetter : ITileMap {
/**
* Возвращает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка
*/
operator fun get(x: Int, y: Int): ITileState
fun getTile(x: Int, y: Int): TileState
/**
* Возвращает тайл по ОТНОСИТЕЛЬНЫМ координатам внутри чанка
*/
operator fun get(pos: Vector2i) = get(pos.x, pos.y)
fun getTile(pos: IStruct2i) = getTile(pos.component1(), pos.component2())
}
/**
* Возвращает итератор пар <Vector2i, Тайл?>
*
* Вектор имеет ОТНОСИТЕЛЬНЫЕ значения внутри самого чанка
*/
val posToTile: Iterator<Pair<Vector2i, ITileState>> get() {
return object : Iterator<Pair<Vector2i, ITileState>> {
private var x = 0
private var y = 0
interface ITileSetter : ITileMap {
fun setTile(x: Int, y: Int, value: TileState)
fun setTile(pos: IStruct2i, value: TileState) = setTile(pos.component1(), pos.component2(), value)
}
private fun idx() = x + CHUNK_SIZE * y
fun ITileGetter.iterate(fromX: Int = 0, fromY: Int = 0, toX: Int = fromX + CHUNK_SIZE, toY: Int = fromY + CHUNK_SIZE): Iterator<Pair<Vector2i, TileState>> {
return object : Iterator<Pair<Vector2i, TileState>> {
private var x = fromX
private var y = fromY
override fun hasNext(): Boolean {
return idx() < CHUNK_SIZE * CHUNK_SIZE
override fun hasNext(): Boolean {
return x < toX && y < toY
}
override fun next(): Pair<Vector2i, TileState> {
if (!hasNext())
throw NoSuchElementException()
val tile = getTile(x, y)
val pos = Vector2i(x, y)
x++
if (x >= toX) {
y++
x = 0
}
override fun next(): Pair<Vector2i, ITileState> {
if (!hasNext()) {
throw IllegalStateException("Already iterated everything!")
}
val tile = this@ITileGetter[x, y]
val pos = Vector2i(x, y)
x++
if (x >= CHUNK_SIZE) {
y++
x = 0
}
return pos to tile
}
return pos to tile
}
}
}
@ -158,37 +112,4 @@ interface IChunkPositionable : ITileMap {
}
interface ITileChunk : ITileGetter, IChunkPositionable
interface IMutableTileChunk : ITileChunk {
override fun get(x: Int, y: Int): IMutableTileState
override fun get(pos: Vector2i): IMutableTileState {
return get(pos.x, pos.y)
}
}
object EmptyTileState : IMutableTileState {
override var material: TileDefinition?
get() = null
set(value) {}
override var modifier: MaterialModifier?
get() = null
set(value) {}
override var color: Int
get() = 0
set(value) {}
override var hueShift: Float
get() = 0f
set(value) {}
override var modifierHueShift: Float
get() = 0f
set(value) {}
}
object EmptyTileChunk : IMutableTileChunk {
override val pos: ChunkPos
get() = ChunkPos.ZERO
override fun get(x: Int, y: Int): IMutableTileState {
return EmptyTileState
}
}
interface IMutableTileChunk : ITileChunk, ITileSetter

View File

@ -3,7 +3,7 @@ package ru.dbotthepony.kstarbound.world
import ru.dbotthepony.kstarbound.math.roundByAbsoluteValue
import ru.dbotthepony.kvector.api.IStruct2d
import ru.dbotthepony.kvector.api.IStruct2i
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kvector.vector.Vector2i
import kotlin.math.absoluteValue
private fun circulate(value: Int, bounds: Int): Int {

View File

@ -1,7 +1,7 @@
package ru.dbotthepony.kstarbound.world
import ru.dbotthepony.kstarbound.util.NotNullTwoDimensionalArray
import ru.dbotthepony.kstarbound.util.TwoDimensionalArray
import ru.dbotthepony.kvector.arrays.Object2DArray
/**
* Предоставляет доступ к чанку и его соседям
@ -31,13 +31,13 @@ class RigidTileView(
override val pos: ChunkPos = view.pos
private val memory: NotNullTwoDimensionalArray<ITileState>
private val memory: Object2DArray<TileState>
init {
memory = NotNullTwoDimensionalArray(CHUNK_SIZE * 3, CHUNK_SIZE * 3) { a, b -> view[a - CHUNK_SIZE, b - CHUNK_SIZE] }
memory = Object2DArray(CHUNK_SIZE * 3, CHUNK_SIZE * 3) { a, b -> view.getTile(a - CHUNK_SIZE, b - CHUNK_SIZE) }
}
override fun get(x: Int, y: Int): ITileState {
override fun getTile(x: Int, y: Int): TileState {
return memory[x + CHUNK_SIZE, y + CHUNK_SIZE]
}
}

View File

@ -0,0 +1,86 @@
package ru.dbotthepony.kstarbound.world
import ru.dbotthepony.kstarbound.RegistryObject
import ru.dbotthepony.kstarbound.defs.tile.MaterialModifier
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
import java.io.DataInputStream
enum class TileColor {
DEFAULT,
RED,
BLUE,
GREEN,
YELLOW,
BROWN,
PURPLE,
BLACK,
WHITE;
companion object {
private val values = values()
fun of(index: Int): TileColor {
return values.getOrElse(index) { DEFAULT }
}
}
}
data class TileState(
val material: TileDefinition? = null,
val modifier: MaterialModifier? = null,
val color: TileColor = TileColor.DEFAULT,
val hueShift: Float = 0f,
val modifierHueShift: Float = 0f,
) {
private fun with(
material: TileDefinition? = this.material,
modifier: MaterialModifier? = this.modifier,
color: TileColor = this.color,
hueShift: Float = this.hueShift,
modifierHueShift: Float = this.modifierHueShift,
): TileState {
if (this.material === material && this.modifier === modifier && this.color == color && this.hueShift == hueShift && this.modifierHueShift == modifierHueShift) {
return this
} else {
return TileState(material, modifier, color, hueShift, modifierHueShift)
}
}
fun withHueShift(hueShift: Int): TileState {
if (hueShift < 0) {
return with(hueShift = 0f)
} else if (hueShift >= 255) {
return with(hueShift = 360f)
} else {
return with(hueShift = hueShift / 255f * 360f)
}
}
fun withModifierHueShift(hueShift: Int): TileState {
if (hueShift < 0) {
return with(modifierHueShift = 0f)
} else if (hueShift >= 255) {
return with(modifierHueShift = 360f)
} else {
return with(modifierHueShift = hueShift / 255f * 360f)
}
}
companion object {
val EMPTY = TileState()
fun read(
materialAccess: (Int) -> RegistryObject<TileDefinition>?,
modifierAccess: (Int) -> RegistryObject<MaterialModifier>?,
stream: DataInputStream
): TileState {
val mat = materialAccess(stream.readUnsignedShort())
val hue = stream.read()
val color = stream.read()
val mod = modifierAccess(stream.readUnsignedShort())
val modHue = stream.read()
return TileState(mat?.value, mod?.value, TileColor.of(color), hue / 255f * 360f, modHue / 255f * 360f)
}
}
}

View File

@ -1,7 +1,5 @@
package ru.dbotthepony.kstarbound.world
import ru.dbotthepony.kstarbound.defs.tile.TileDefinition
/**
* Предоставляет доступ к чанку и его соседям
*
@ -23,38 +21,38 @@ open class TileView(
open val bottomLeft: ITileChunk?,
open val bottomRight: ITileChunk?,
) : ITileChunk {
override fun get(x: Int, y: Int): ITileState {
override fun getTile(x: Int, y: Int): TileState {
if (x in 0 ..CHUNK_SIZE_FF) {
if (y in 0 ..CHUNK_SIZE_FF) {
return center?.get(x, y) ?: EmptyTileState
return center?.getTile(x, y) ?: TileState.EMPTY
}
if (y < 0) {
return bottom?.get(x, y + CHUNK_SIZE) ?: EmptyTileState
return bottom?.getTile(x, y + CHUNK_SIZE) ?: TileState.EMPTY
} else {
return top?.get(x, y - CHUNK_SIZE) ?: EmptyTileState
return top?.getTile(x, y - CHUNK_SIZE) ?: TileState.EMPTY
}
}
if (x < 0) {
if (y in 0 ..CHUNK_SIZE_FF) {
return left?.get(x + CHUNK_SIZE, y) ?: EmptyTileState
return left?.getTile(x + CHUNK_SIZE, y) ?: TileState.EMPTY
}
if (y < 0) {
return bottomLeft?.get(x + CHUNK_SIZE, y + CHUNK_SIZE) ?: EmptyTileState
return bottomLeft?.getTile(x + CHUNK_SIZE, y + CHUNK_SIZE) ?: TileState.EMPTY
} else {
return topLeft?.get(x + CHUNK_SIZE, y - CHUNK_SIZE) ?: EmptyTileState
return topLeft?.getTile(x + CHUNK_SIZE, y - CHUNK_SIZE) ?: TileState.EMPTY
}
} else {
if (y in 0 ..CHUNK_SIZE_FF) {
return right?.get(x - CHUNK_SIZE, y) ?: EmptyTileState
return right?.getTile(x - CHUNK_SIZE, y) ?: TileState.EMPTY
}
if (y < 0) {
return bottomRight?.get(x - CHUNK_SIZE, y + CHUNK_SIZE) ?: EmptyTileState
return bottomRight?.getTile(x - CHUNK_SIZE, y + CHUNK_SIZE) ?: TileState.EMPTY
} else {
return topRight?.get(x - CHUNK_SIZE, y - CHUNK_SIZE) ?: EmptyTileState
return topRight?.getTile(x - CHUNK_SIZE, y - CHUNK_SIZE) ?: TileState.EMPTY
}
}
}
@ -74,7 +72,7 @@ class MutableTileView(
override val bottomLeft: IMutableTileChunk?,
override val bottomRight: IMutableTileChunk?,
) : TileView(pos, center, right, top, topRight, topLeft, left, bottom, bottomLeft, bottomRight), IMutableTileChunk {
override fun get(x: Int, y: Int): IMutableTileState {
return super<TileView>.get(x, y) as IMutableTileState
override fun setTile(x: Int, y: Int, value: TileState) {
TODO()
}
}

View File

@ -1,8 +1,6 @@
package ru.dbotthepony.kstarbound.world
import com.google.common.collect.ImmutableList
import it.unimi.dsi.fastutil.objects.Object2DoubleAVLTreeMap
import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap
import ru.dbotthepony.kbox2d.api.ContactImpulse
@ -15,35 +13,24 @@ import ru.dbotthepony.kbox2d.dynamics.contact.AbstractContact
import ru.dbotthepony.kstarbound.METRES_IN_STARBOUND_UNIT
import ru.dbotthepony.kstarbound.math.*
import ru.dbotthepony.kstarbound.util.Timer
import ru.dbotthepony.kstarbound.world.entities.CollisionResolution
import ru.dbotthepony.kstarbound.world.entities.Entity
import ru.dbotthepony.kvector.narray.Double2Dimensional
import ru.dbotthepony.kvector.narray.Int2Dimensional
import ru.dbotthepony.kvector.arrays.Double2DArray
import ru.dbotthepony.kvector.arrays.Int2DArray
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.util2d.AABBi
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.Vector2i
import java.util.LinkedList
import kotlin.math.PI
import kotlin.math.absoluteValue
import kotlin.math.cos
import kotlin.math.roundToInt
import kotlin.math.sin
const val EARTH_FREEFALL_ACCELERATION = 9.8312 / METRES_IN_STARBOUND_UNIT
data class WorldSweepResult(
val hitPosition: Vector2d,
val collisionTime: Double,
val hitAnything: Boolean,
val hitNormal: Vector2d
)
private const val EPSILON = 0.00001
data class RayCastResult(
val traversedTiles: List<Pair<Vector2i, ITileState>>,
val hitTile: Pair<Vector2i, ITileState>?,
val traversedTiles: List<Pair<Vector2i, TileState>>,
val hitTile: Pair<Vector2i, TileState>?,
val fraction: Double
)
@ -101,7 +88,7 @@ enum class RayFilterResult {
}
fun interface TileRayFilter {
fun test(state: ITileState, fraction: Double, position: Vector2i): RayFilterResult
fun test(state: TileState, fraction: Double, position: Vector2i): RayFilterResult
}
/**
@ -373,12 +360,12 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
return lastChunk
}
fun getTile(pos: Vector2i): ITileState? {
return get(ChunkPos.fromTilePosition(pos))?.foreground?.get(ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y))
fun getTile(pos: Vector2i): TileState? {
return get(ChunkPos.fromTilePosition(pos))?.foreground?.getTile(ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y))
}
fun getBackgroundTile(pos: Vector2i): ITileState? {
return get(ChunkPos.fromTilePosition(pos))?.background?.get(ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y))
fun getBackgroundTile(pos: Vector2i): TileState? {
return get(ChunkPos.fromTilePosition(pos))?.background?.getTile(ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y))
}
/**
@ -397,16 +384,16 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
val dir = rayEnd - rayStart
val inc = 0.5 / dir.length
val tiles = LinkedList<Pair<Vector2i, ITileState>>()
val tiles = LinkedList<Pair<Vector2i, TileState>>()
var prev = Vector2i(Int.MIN_VALUE, Int.MAX_VALUE)
var hitTile: Pair<Vector2i, ITileState>? = null
var hitTile: Pair<Vector2i, TileState>? = null
while (t < 1.0) {
val (x, y) = rayStart + dir * t
val tilePos = Vector2i(x.roundToInt(), y.roundToInt())
if (tilePos != prev) {
val tile = getTile(tilePos) ?: EmptyTileState
val tile = getTile(tilePos) ?: TileState.EMPTY
when (filter.test(tile, t, tilePos)) {
RayFilterResult.HIT -> {
@ -442,7 +429,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
length: Double,
filter: TileRayFilter = AnythingRayFilter
): RayCastResult {
return castRayNaive(rayPosition, rayPosition + direction.normalized * length, filter)
return castRayNaive(rayPosition, rayPosition + direction.unitVector * length, filter)
}
/**
@ -490,8 +477,8 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
intensity: Double,
falloffByTile: Double = 2.0,
falloffByTravel: Double = 1.0,
): Double2Dimensional {
val combinedResult = Double2Dimensional(intensity.roundToInt() * 2, intensity.roundToInt() * 2)
): Double2DArray {
val combinedResult = Double2DArray.allocate(intensity.roundToInt() * 2, intensity.roundToInt() * 2)
val baselineX = position.x.roundToInt() - intensity.roundToInt()
val baselineY = position.y.roundToInt() - intensity.roundToInt()
@ -554,7 +541,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
intensity: Double,
falloffByTile: Double = 2.0,
falloffByTravel: Double = 2.0,
): Double2Dimensional {
): Double2DArray {
return CachedGetter().rayLightCircleNaive(position, intensity, falloffByTile, falloffByTravel)
}
@ -600,12 +587,12 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
return RigidTileView(getBackgroundView(pos))
}
fun getTile(pos: Vector2i): ITileState? {
return get(ChunkPos.fromTilePosition(pos))?.foreground?.get(ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y))
fun getTile(pos: Vector2i): TileState? {
return get(ChunkPos.fromTilePosition(pos))?.foreground?.getTile(ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y))
}
fun getBackgroundTile(pos: Vector2i): ITileState? {
return get(ChunkPos.fromTilePosition(pos))?.background?.get(ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y))
fun getBackgroundTile(pos: Vector2i): TileState? {
return get(ChunkPos.fromTilePosition(pos))?.background?.getTile(ChunkPos.normalizeCoordinate(pos.x), ChunkPos.normalizeCoordinate(pos.y))
}
/**
@ -642,168 +629,6 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
return output
}
/**
* Производит проверку на пересечение [worldaabb] с геометрией мира при попытке пройти в [_deltaMovement]
*/
fun sweep(
worldaabb: AABB,
_deltaMovement: Vector2d,
collisionResolution: CollisionResolution,
delta: Double
): WorldSweepResult {
var deltaMovement = _deltaMovement
val potentialAABB = worldaabb + deltaMovement
val combined = worldaabb.combine(potentialAABB)
val collected = collect((combined).encasingChunkPosAABB())
.map { it.foreground.collisionLayers() }
.flatten()
.sortedWith { o1, o2 ->
val a = o1.distance(worldaabb)
val b = o2.distance(worldaabb)
if (a == b)
return@sortedWith 0
if (a > b)
return@sortedWith 1
return@sortedWith -1
}
var hitAnything = false
var hitNormal = Vector2d.ZERO
if (collected.isNotEmpty()) {
for (iteration in 0 .. 100) {
var collided = false
for (aabb in collected) {
// залез в блоки?
/*if (potentialAABB.intersectWeak(aabb)) {
val push = worldaabb.pushOutFrom(aabb)
println("into tiles")
if (push.length > 0.0) {
if (iteration == 0) {
collided = true
continue
} else {
hitAnything = true
deltaMovement -= push * delta * 5.0
potentialAABB = worldaabb + deltaMovement
combined = worldaabb.combine(potentialAABB)
collided = true
continue
}
}
}*/
// ранний тест (отсечение заведомо не пересекаемой геометрии)
if (!aabb.intersect(combined)) {
continue
}
// обычный тест коллизии
val (normal, collisionTime) = worldaabb.sweep(aabb, deltaMovement)
if (collisionTime != 1.0) {
hitAnything = true
collided = true
hitNormal = normal
if (weakDoubleZeroing(collisionTime) == 0.0) {
// Мы ВПЛОТНУЮ стоим к другой геометрии (пересекаемся одной из осей)
deltaMovement = Vector2d.ZERO
} else {
val remainingTime = 1.0 - collisionTime
when (collisionResolution) {
CollisionResolution.STOP -> {
// val weak = weakDoubleZeroing(collisionTime, epsilon = EPSILON)
for (i in 100 downTo 1) {
val move = deltaMovement * collisionTime * (i / 100.0)
// сегодня, в программе
// погрешность плавающей запятой
if (!(worldaabb + move).intersect(aabb)) {
deltaMovement = move
break
} // ЭтО чО вАщЕ ТакОе?
}
}
CollisionResolution.PUSH -> {
var dot = deltaMovement.pseudoDot(normal)
val magnitude = deltaMovement.length * weakDoubleZeroing(remainingTime, epsilon = EPSILON)
if (dot > 0.0) {
dot = 1.0
} else {
dot = -1.0
}
deltaMovement = Vector2d(dot * normal.y * magnitude, dot * normal.x * magnitude)
}
CollisionResolution.SLIDE -> {
val dot = deltaMovement.pseudoDot(normal) * remainingTime
if (weakDoubleZeroing(dot) != 0.0) {
deltaMovement = Vector2d(dot * normal.y, dot * normal.x)
} else {
// Граничный случай: Направления идеально противоположны.
// Обрабатываем как CollisionResolution.STOP
// val weak = weakDoubleZeroing(collisionTime, epsilon = EPSILON)
for (i in 100 downTo 1) {
val move = deltaMovement * collisionTime * (i / 100.0)
// сегодня, в программе
// погрешность плавающей запятой
if (!(worldaabb + move).intersect(aabb)) {
deltaMovement = move
break
} // ЭтО чО вАщЕ ТакОе?
}
}
}
CollisionResolution.BOUNCE -> {
deltaMovement *= weakDoubleZeroing(remainingTime, epsilon = EPSILON)
if (normal.x.absoluteValue > 0.00001 && normal.y.absoluteValue > 0.00001) {
deltaMovement *= Vector2d.NEGATIVE_XY
} else if (normal.x.absoluteValue > 0.00001) {
deltaMovement *= Vector2d.NEGATIVE_X
} else if (normal.y.absoluteValue > 0.00001) {
deltaMovement *= Vector2d.NEGATIVE_Y
}
}
}
}
}
}
if (!collided) {
//println("resolved in $iteration")
break
}
}
}
return WorldSweepResult(
hitAnything = hitAnything,
hitNormal = hitNormal,
collisionTime = worldaabb.centre.distance(deltaMovement) / worldaabb.centre.distance(_deltaMovement),
hitPosition = deltaMovement,
)
}
/**
* Возвращает, застрянет ли сущность будет с коллизией [worldaabb]
*/
@ -840,7 +665,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
// Свет
private fun floodLightInto(
lightmap: Int2Dimensional,
lightmap: Int2DArray,
view: RigidTileView,
thisIntensity: Int,
lightBlockerStrength: Int,
@ -853,7 +678,7 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
return 1
}
val tile = view[worldPosX, worldPosY]
val tile = view.getTile(worldPosX, worldPosY)
val newIntensity: Int
@ -918,12 +743,12 @@ abstract class World<This : World<This, ChunkType>, ChunkType : Chunk<This, Chun
lightPosition: Vector2i,
lightIntensity: Int,
lightBlockerStrength: Int = 4,
): Int2Dimensional {
): Int2DArray {
require(lightIntensity >= 1) { "Invalid light intensity $lightIntensity" }
require(lightBlockerStrength >= 1) { "Invalid light blocker strength $lightBlockerStrength" }
require(lightIntensity <= CHUNK_SIZE) { "Too intensive light! $lightIntensity" }
val lightmap = Int2Dimensional(lightIntensity * 2 + 1, lightIntensity * 2 + 1)
val lightmap = Int2DArray.allocate(lightIntensity * 2 + 1, lightIntensity * 2 + 1)
val view = getRigidForegroundView(ChunkPos.fromTilePosition(lightPosition))

View File

@ -7,8 +7,8 @@ import ru.dbotthepony.kbox2d.collision.shapes.PolygonShape
import ru.dbotthepony.kbox2d.dynamics.B2Fixture
import ru.dbotthepony.kstarbound.world.World
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.ndouble.times
import ru.dbotthepony.kvector.vector.Vector2d
import ru.dbotthepony.kvector.vector.times
import kotlin.math.absoluteValue
enum class Move {

View File

@ -4,7 +4,7 @@ import ru.dbotthepony.kstarbound.defs.DamageType
import ru.dbotthepony.kstarbound.world.Chunk
import ru.dbotthepony.kstarbound.world.ChunkPos
import ru.dbotthepony.kstarbound.world.World
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
/**
* Интерфейс служит лишь для убирания жёсткой зависимости от класса Entity

View File

@ -3,7 +3,7 @@ package ru.dbotthepony.kstarbound.world.entities
import ru.dbotthepony.kbox2d.api.*
import ru.dbotthepony.kbox2d.dynamics.contact.AbstractContact
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
enum class CollisionResolution {
STOP,
@ -74,7 +74,7 @@ abstract class MovementController<T : IEntity>(val entity: T) : IContactListener
*/
open val onGround: Boolean get() {
for (contact in body.contactEdgeIterator) {
if (contact.contact.manifold.localNormal.dot(world.gravity.normalized) >= 0.97) {
if (contact.contact.manifold.localNormal.dot(world.gravity.unitVector) >= 0.97) {
return true
}
}

View File

@ -4,11 +4,9 @@ import ru.dbotthepony.kbox2d.api.ContactImpulse
import ru.dbotthepony.kbox2d.api.FixtureDef
import ru.dbotthepony.kbox2d.api.Manifold
import ru.dbotthepony.kbox2d.collision.shapes.PolygonShape
import ru.dbotthepony.kbox2d.dynamics.B2Fixture
import ru.dbotthepony.kbox2d.dynamics.contact.AbstractContact
import ru.dbotthepony.kstarbound.world.World
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.Vector2d
class PlayerMovementController(entity: PlayerEntity) : WalkableMovementController<PlayerEntity>(entity) {
public override var moveDirection = Move.STAND_STILL

View File

@ -1,14 +1,13 @@
package ru.dbotthepony.kstarbound.world.phys
import ru.dbotthepony.kstarbound.util.NotNullTwoDimensionalArray
import ru.dbotthepony.kstarbound.world.CHUNK_SHIFT
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE_FF
import ru.dbotthepony.kstarbound.world.Chunk
import ru.dbotthepony.kstarbound.world.ITileState
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kstarbound.world.TileState
import ru.dbotthepony.kvector.arrays.Object2DArray
import ru.dbotthepony.kvector.vector.Vector2i
class RectTileFlooderDepthFirst(
private val tiles: NotNullTwoDimensionalArray<out ITileState>,
private val tiles: Object2DArray<out TileState>,
private val seen: BooleanArray,
rootx: Int,
rooty: Int

View File

@ -1,13 +1,13 @@
package ru.dbotthepony.kstarbound.world.phys
import ru.dbotthepony.kstarbound.util.NotNullTwoDimensionalArray
import ru.dbotthepony.kstarbound.world.CHUNK_SHIFT
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE_FF
import ru.dbotthepony.kstarbound.world.ITileState
import ru.dbotthepony.kvector.vector.nint.Vector2i
import ru.dbotthepony.kstarbound.world.TileState
import ru.dbotthepony.kvector.arrays.Object2DArray
import ru.dbotthepony.kvector.vector.Vector2i
class RectTileFlooderSizeFirst(
private val tiles: NotNullTwoDimensionalArray<out ITileState>,
private val tiles: Object2DArray<out TileState>,
private val seen: BooleanArray,
private val rootx: Int,
private val rooty: Int

View File

@ -3,8 +3,8 @@ package ru.dbotthepony.kstarbound.world.phys
import ru.dbotthepony.kstarbound.util.NotNullTwoDimensionalArray
import ru.dbotthepony.kstarbound.world.CHUNK_SHIFT
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE_FF
import ru.dbotthepony.kstarbound.world.ITileState
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kstarbound.world.TileState
import ru.dbotthepony.kvector.vector.Vector2d
private data class TileExposure(
var pos: Vector2d,
@ -15,7 +15,7 @@ private data class TileExposure(
)
private class TileFlooder(
private val tiles: NotNullTwoDimensionalArray<out ITileState>,
private val tiles: NotNullTwoDimensionalArray<out TileState>,
private val seen: BooleanArray,
rootx: Int,
rooty: Int

View File

@ -5,14 +5,7 @@ import org.junit.jupiter.api.Test
import ru.dbotthepony.kstarbound.math.*
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE_FF
import ru.dbotthepony.kstarbound.world.CHUNK_SIZEd
import ru.dbotthepony.kstarbound.world.ChunkPos
import ru.dbotthepony.kvector.matrix.multiplyMatrix
import ru.dbotthepony.kvector.narray.Double2Dimensional
import ru.dbotthepony.kvector.util2d.AABB
import ru.dbotthepony.kvector.util2d.AABBi
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
import ru.dbotthepony.kvector.vector.nint.Vector2i
object MathTests {
@Test
@ -55,46 +48,6 @@ object MathTests {
check(roundTowardsPositiveInfinity(-1.6) == -1)
}
@Test
@DisplayName("AABB Basic Math")
fun basicAABB() {
val a = AABB.rectangle(Vector2d.ZERO, 1.0, 1.0)
check(a.intersect(AABB.rectangle(Vector2d(-1.0), 1.0, 1.0)))
check(!a.intersectWeak(AABB.rectangle(Vector2d(-1.0), 1.0, 1.0)))
check(!a.intersect(AABB.rectangle(Vector2d(-2.0), 1.0, 1.0)))
check(!a.intersectWeak(AABB.rectangle(Vector2d(-2.0), 1.0, 1.0)))
check(a.intersect(AABB.rectangle(Vector2d(-0.9), 1.0, 1.0)))
check(a.intersectWeak(AABB.rectangle(Vector2d(-0.9), 1.0, 1.0)))
val bigA = AABB.rectangle(Vector2d.ZERO, 200.0, 200.0)
val smallB = AABB.rectangle(Vector2d.ZERO, 1.0, 1.0)
check(bigA.intersect(smallB))
check(smallB.intersect(bigA))
check(bigA.intersectWeak(smallB))
check(smallB.intersectWeak(bigA))
check(AABB.rectangle(Vector2d.ZERO, 1.0, 1.0) == AABB(Vector2d(-0.5, -0.5), Vector2d(0.5, 0.5)))
val combineA = AABB(Vector2d(0.0, 0.0), Vector2d(2.0, 2.0))
val combineB = AABB(Vector2d(2.0, 5.0), Vector2d(4.0, 6.0))
check(combineA.combine(combineB) == AABB(Vector2d(0.0, 0.0), Vector2d(4.0, 6.0))) { combineA.combine(combineB).toString() }
}
@Test
@DisplayName("AABB transformation to AABBi")
fun transformAABB() {
check(AABB.rectangle(Vector2d.ZERO, 2.0, 2.0).encasingIntAABB() == AABBi(Vector2i(-1, -1), Vector2i(1, 1)))
check(AABB.rectangle(Vector2d.ZERO, 2.0, 2.0).encasingChunkPosAABB() == AABBi(Vector2i(-1, -1), Vector2i(0, 0))) { AABB.rectangle(Vector2d.ZERO, 2.0, 2.0).encasingChunkPosAABB()}
check(AABB.rectangle(Vector2d(x = CHUNK_SIZEd - 0.1), 2.0, 2.0).encasingChunkPosAABB() == AABBi(Vector2i(0, -1), Vector2i(1, 0))) { "${AABB.rectangle(Vector2d(x = CHUNK_SIZEd - 0.1), 2.0, 2.0)} ${AABB.rectangle(Vector2d(x = CHUNK_SIZEd - 0.1), 2.0, 2.0).encasingChunkPosAABB()}" }
check(AABB.rectangle(Vector2d(x = CHUNK_SIZEd + 0.1), 2.0, 2.0).encasingChunkPosAABB() == AABBi(Vector2i(0, -1), Vector2i(1, 0))) { "${AABB.rectangle(Vector2d(x = CHUNK_SIZEd + 0.1), 2.0, 2.0)} ${AABB.rectangle(Vector2d(x = CHUNK_SIZEd + 0.1), 2.0, 2.0).encasingChunkPosAABB()}" }
}
@Test
@DisplayName("ChunkPos class tests")
fun chunkPosTests() {
@ -115,46 +68,4 @@ object MathTests {
check(ChunkPos.fromTilePosition(0, -CHUNK_SIZE_FF) == ChunkPos(0, -1)) { ChunkPos.fromTilePosition(0, -CHUNK_SIZE_FF) }
check(ChunkPos.fromTilePosition(0, -CHUNK_SIZE) == ChunkPos(0, -2)) { ChunkPos.fromTilePosition(0, -CHUNK_SIZE) }
}
@Test
fun testMatrixMult() {
val matrix1 = Double2Dimensional(4, 2)
val matrix2 = Double2Dimensional(3, 4)
matrix1[0, 0] = 3.0
matrix1[1, 0] = 2.0
matrix1[2, 0] = 1.0
matrix1[3, 0] = 5.0
matrix1[0, 1] = 9.0
matrix1[1, 1] = 1.0
matrix1[2, 1] = 3.0
matrix1[3, 1] = 0.0
matrix2[0, 0] = 2.0
matrix2[1, 0] = 9.0
matrix2[2, 0] = 0.0
matrix2[0, 1] = 1.0
matrix2[1, 1] = 3.0
matrix2[2, 1] = 5.0
matrix2[0, 2] = 2.0
matrix2[1, 2] = 4.0
matrix2[2, 2] = 7.0
matrix2[0, 3] = 8.0
matrix2[1, 3] = 1.0
matrix2[2, 3] = 5.0
val product = multiplyMatrix(matrix1, matrix2)
check(product[0, 0] == 50.0)
check(product[1, 0] == 42.0)
check(product[2, 0] == 42.0)
check(product[0, 1] == 25.0)
check(product[1, 1] == 96.0)
check(product[2, 1] == 26.0)
}
}

View File

@ -1,31 +0,0 @@
package ru.dbotthepony.kstarbound.test
import jdk.jfr.Description
import org.junit.jupiter.api.Test
import ru.dbotthepony.kvector.matrix.nfloat.Matrix3f
object MatrixTest {
@Test
@Description("Matrix test")
fun test() {
val a = Matrix3f.rm(
4f, 2f, 0f,
0f, 8f, 1f,
0f, 1f, 0f
)
val b = Matrix3f.rm(
4f, 2f, 1f,
2f, 0f, 4f,
9f, 4f, 2f
)
val c = Matrix3f.rm(
20f, 8f, 12f,
25f, 4f, 34f,
2f, 0f, 4f
)
require(a * b == c) { "${a * b} != $c" }
}
}