Подгрузка ассетов во внешнем потоке
This commit is contained in:
parent
419980301b
commit
de15212824
@ -1,6 +1,5 @@
|
|||||||
package ru.dbotthepony.kstarbound
|
package ru.dbotthepony.kstarbound
|
||||||
|
|
||||||
import com.sun.jna.ptr.LongByReference
|
|
||||||
import org.apache.logging.log4j.LogManager
|
import org.apache.logging.log4j.LogManager
|
||||||
import org.lwjgl.Version
|
import org.lwjgl.Version
|
||||||
import org.lwjgl.glfw.Callbacks.glfwFreeCallbacks
|
import org.lwjgl.glfw.Callbacks.glfwFreeCallbacks
|
||||||
@ -9,25 +8,21 @@ import org.lwjgl.glfw.GLFWErrorCallback
|
|||||||
import org.lwjgl.opengl.GL46.*
|
import org.lwjgl.opengl.GL46.*
|
||||||
import org.lwjgl.system.MemoryStack.stackPush
|
import org.lwjgl.system.MemoryStack.stackPush
|
||||||
import org.lwjgl.system.MemoryUtil.NULL
|
import org.lwjgl.system.MemoryUtil.NULL
|
||||||
import ru.dbotthepony.kstarbound.defs.TileDefinition
|
|
||||||
import ru.dbotthepony.kstarbound.freetype.FREE_TYPE_JNA
|
|
||||||
import ru.dbotthepony.kstarbound.freetype.FreeType
|
|
||||||
import ru.dbotthepony.kstarbound.freetype.LoadFlag
|
|
||||||
import ru.dbotthepony.kstarbound.gl.*
|
import ru.dbotthepony.kstarbound.gl.*
|
||||||
import ru.dbotthepony.kstarbound.math.*
|
import ru.dbotthepony.kstarbound.math.*
|
||||||
import ru.dbotthepony.kstarbound.render.*
|
import ru.dbotthepony.kstarbound.render.*
|
||||||
|
import ru.dbotthepony.kstarbound.util.Color
|
||||||
import ru.dbotthepony.kstarbound.util.formatBytesShort
|
import ru.dbotthepony.kstarbound.util.formatBytesShort
|
||||||
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE
|
|
||||||
import ru.dbotthepony.kstarbound.world.CHUNK_SIZE_FF
|
|
||||||
import ru.dbotthepony.kstarbound.world.ChunkTile
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import kotlin.math.PI
|
|
||||||
|
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
private const val TEST = false
|
|
||||||
|
var terminateGame = false
|
||||||
|
private set
|
||||||
|
|
||||||
var viewportWidth = 800
|
var viewportWidth = 800
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var viewportHeight = 600
|
var viewportHeight = 600
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -51,25 +46,26 @@ var window = 0L
|
|||||||
fun main() {
|
fun main() {
|
||||||
LOGGER.info("Running LWJGL ${Version.getVersion()}")
|
LOGGER.info("Running LWJGL ${Version.getVersion()}")
|
||||||
|
|
||||||
if (!TEST) {
|
try {
|
||||||
try {
|
init()
|
||||||
init()
|
loop()
|
||||||
loop()
|
} finally {
|
||||||
} finally {
|
if (window != NULL) {
|
||||||
if (window != NULL) {
|
glfwFreeCallbacks(window)
|
||||||
glfwFreeCallbacks(window)
|
glfwDestroyWindow(window)
|
||||||
glfwDestroyWindow(window)
|
|
||||||
}
|
|
||||||
|
|
||||||
glfwTerminate()
|
|
||||||
glfwSetErrorCallback(null)?.free()
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Starbound.addFilePath(File("./unpacked_assets/"))
|
glfwTerminate()
|
||||||
Starbound.loadTileDefinition("alienrock")
|
glfwSetErrorCallback(null)?.free()
|
||||||
|
|
||||||
|
terminateGame = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var camera: Camera? = null
|
||||||
|
private val startupTextList = ArrayList<String>()
|
||||||
|
private var finishStartupRendering = Long.MAX_VALUE
|
||||||
|
|
||||||
private fun init() {
|
private fun init() {
|
||||||
GLFWErrorCallback.create { error, description ->
|
GLFWErrorCallback.create { error, description ->
|
||||||
LOGGER.error("LWJGL error {}: {}", error, description)
|
LOGGER.error("LWJGL error {}: {}", error, description)
|
||||||
@ -91,6 +87,8 @@ private fun init() {
|
|||||||
glfwSetKeyCallback(window) { window, key, scancode, action, mods ->
|
glfwSetKeyCallback(window) { window, key, scancode, action, mods ->
|
||||||
if (key == GLFW_KEY_ESCAPE || key == GLFW_RELEASE) {
|
if (key == GLFW_KEY_ESCAPE || key == GLFW_RELEASE) {
|
||||||
glfwSetWindowShouldClose(window, true)
|
glfwSetWindowShouldClose(window, true)
|
||||||
|
} else {
|
||||||
|
camera?.userInput(key, scancode, action, mods)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +127,21 @@ private fun init() {
|
|||||||
glfwShowWindow(window)
|
glfwShowWindow(window)
|
||||||
|
|
||||||
Starbound.addFilePath(File("./unpacked_assets/"))
|
Starbound.addFilePath(File("./unpacked_assets/"))
|
||||||
Starbound.loadTileMaterials()
|
Starbound.initializeGame { finished, replaceStatus, status ->
|
||||||
|
if (replaceStatus) {
|
||||||
|
if (startupTextList.isEmpty()) {
|
||||||
|
startupTextList.add(status)
|
||||||
|
} else {
|
||||||
|
startupTextList[startupTextList.size - 1] = status
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
startupTextList.add(status)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finished) {
|
||||||
|
finishStartupRendering = System.currentTimeMillis() + 2000L
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var frameRenderTime = 1.0
|
var frameRenderTime = 1.0
|
||||||
@ -139,7 +151,7 @@ val framesPerSecond get() = 1.0 / frameRenderTime
|
|||||||
|
|
||||||
private fun loop() {
|
private fun loop() {
|
||||||
val state = GLStateTracker()
|
val state = GLStateTracker()
|
||||||
val camera = Camera()
|
camera = Camera()
|
||||||
|
|
||||||
// Set the clear color
|
// Set the clear color
|
||||||
glClearColor(0.2f, 0.2f, 0.2f, 0.2f)
|
glClearColor(0.2f, 0.2f, 0.2f, 0.2f)
|
||||||
@ -147,7 +159,7 @@ private fun loop() {
|
|||||||
state.blend = true
|
state.blend = true
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
||||||
|
|
||||||
val chunk = Starbound.world.getOrMakeChunk(Vector2i(2, 2))
|
/*val chunk = Starbound.world.getOrMakeChunk(Vector2i(2, 2))
|
||||||
|
|
||||||
var x = 0
|
var x = 0
|
||||||
var y = 0
|
var y = 0
|
||||||
@ -183,7 +195,7 @@ private fun loop() {
|
|||||||
for (y in 4 .. 8) {
|
for (y in 4 .. 8) {
|
||||||
chunk.foreground[x, y] = null as TileDefinition?
|
chunk.foreground[x, y] = null as TileDefinition?
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
for (x in 0 .. 24) {
|
for (x in 0 .. 24) {
|
||||||
@ -193,9 +205,9 @@ private fun loop() {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
val chunkRenderer = ChunkRenderer(state, chunk, Starbound.world)
|
//val chunkRenderer = ChunkRenderer(state, chunk, Starbound.world)
|
||||||
chunkRenderer.tesselateStatic()
|
//chunkRenderer.tesselateStatic()
|
||||||
chunkRenderer.uploadStatic()
|
//chunkRenderer.uploadStatic()
|
||||||
|
|
||||||
val runtime = Runtime.getRuntime()
|
val runtime = Runtime.getRuntime()
|
||||||
|
|
||||||
@ -206,15 +218,41 @@ private fun loop() {
|
|||||||
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) // clear the framebuffer
|
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) // clear the framebuffer
|
||||||
|
|
||||||
state.matrixStack.clear(viewportMatrixGame.toMutableMatrix())
|
state.matrixStack.clear(viewportMatrixGame.toMutableMatrix())
|
||||||
|
camera?.translate(state.matrixStack.last)
|
||||||
|
|
||||||
state.matrixStack.push().scale(x = 20f, y = 20f).translateWithScale(0f, 0f)
|
state.matrixStack.push().scale(x = 20f, y = 20f).translateWithScale(0f, 0f)
|
||||||
chunkRenderer.render()
|
//chunkRenderer.render()
|
||||||
|
|
||||||
state.matrixStack.clear(viewportMatrixGUI.toMutableMatrix().translate(z = 2f))
|
state.matrixStack.clear(viewportMatrixGUI.toMutableMatrix().translate(z = 2f))
|
||||||
|
|
||||||
state.font.render("FPS: %.2f".format(framesPerSecond), scale = 0.4f)
|
state.font.render("FPS: %.2f".format(framesPerSecond), scale = 0.4f)
|
||||||
state.font.render("Mem: ${formatBytesShort(runtime.totalMemory() - runtime.freeMemory())}", x = viewportWidth.toFloat(), scale = 0.4f, alignX = TextAlignX.RIGHT)
|
state.font.render("Mem: ${formatBytesShort(runtime.totalMemory() - runtime.freeMemory())}", x = viewportWidth.toFloat(), scale = 0.4f, alignX = TextAlignX.RIGHT)
|
||||||
|
|
||||||
|
val thisTime = System.currentTimeMillis()
|
||||||
|
|
||||||
|
if (!startupTextList.isEmpty() && thisTime <= finishStartupRendering) {
|
||||||
|
var alpha = 1f
|
||||||
|
|
||||||
|
if (finishStartupRendering - thisTime < 1000L) {
|
||||||
|
alpha = (finishStartupRendering - thisTime) / 1000f
|
||||||
|
}
|
||||||
|
|
||||||
|
state.matrixStack.push()
|
||||||
|
state.matrixStack.translateWithScale(y = viewportHeight.toFloat())
|
||||||
|
var shade = 255
|
||||||
|
|
||||||
|
for (i in startupTextList.size - 1 downTo 0) {
|
||||||
|
val size = state.font.render(startupTextList[i], alignY = TextAlignY.BOTTOM, scale = 0.4f, color = Color.SHADES_OF_GRAY[shade].copy(alpha = alpha))
|
||||||
|
state.matrixStack.translateWithScale(y = -size.height * 1.2f)
|
||||||
|
|
||||||
|
if (shade > 120) {
|
||||||
|
shade -= 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state.matrixStack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
glfwSwapBuffers(window) // swap the color buffers
|
glfwSwapBuffers(window) // swap the color buffers
|
||||||
|
|
||||||
// Poll for window events. The key callback above will only be
|
// Poll for window events. The key callback above will only be
|
||||||
|
@ -5,20 +5,22 @@ import com.google.gson.JsonObject
|
|||||||
import com.google.gson.JsonParser
|
import com.google.gson.JsonParser
|
||||||
import ru.dbotthepony.kstarbound.defs.TileDefinition
|
import ru.dbotthepony.kstarbound.defs.TileDefinition
|
||||||
import ru.dbotthepony.kstarbound.defs.TileDefinitionBuilder
|
import ru.dbotthepony.kstarbound.defs.TileDefinitionBuilder
|
||||||
import ru.dbotthepony.kstarbound.defs.TileRenderTemplate
|
|
||||||
import ru.dbotthepony.kstarbound.world.World
|
import ru.dbotthepony.kstarbound.world.World
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.io.FilenameFilter
|
|
||||||
|
|
||||||
class TileDefLoadingException(message: String, cause: Throwable? = null) : IllegalStateException(message, cause)
|
class TileDefLoadingException(message: String, cause: Throwable? = null) : IllegalStateException(message, cause)
|
||||||
|
|
||||||
object Starbound {
|
object Starbound {
|
||||||
private val tiles = HashMap<String, TileDefinition>()
|
private val tiles = HashMap<String, TileDefinition>()
|
||||||
val tilesAccess = object : Map<String, TileDefinition> by tiles {}
|
val tilesAccess = object : Map<String, TileDefinition> by tiles {}
|
||||||
|
|
||||||
val world = World()
|
val world = World()
|
||||||
|
|
||||||
|
var initializing = false
|
||||||
|
private set
|
||||||
|
var initialized = false
|
||||||
|
private set
|
||||||
|
|
||||||
private val _filepath = ArrayList<File>()
|
private val _filepath = ArrayList<File>()
|
||||||
val filepath = object : List<File> by _filepath {}
|
val filepath = object : List<File> by _filepath {}
|
||||||
|
|
||||||
@ -51,18 +53,42 @@ object Starbound {
|
|||||||
return JsonParser.parseReader(findFile(path).bufferedReader())
|
return JsonParser.parseReader(findFile(path).bufferedReader())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadTileDefinition(name: String): TileDefinition {
|
|
||||||
return tiles.computeIfAbsent(name) {
|
|
||||||
val foundPath = findFile("tiles/materials/$name.material")
|
|
||||||
return@computeIfAbsent TileDefinitionBuilder.fromJson(JsonParser.parseReader(foundPath.bufferedReader()) as JsonObject).build(foundPath.parent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTileDefinition(name: String): TileDefinition? {
|
fun getTileDefinition(name: String): TileDefinition? {
|
||||||
return tiles[name]
|
return tiles[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadTileMaterials() {
|
fun initializeGame(callback: (finished: Boolean, replaceStatus: Boolean, status: String) -> Unit) {
|
||||||
|
if (initializing) {
|
||||||
|
throw IllegalStateException("Already initializing!")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialized) {
|
||||||
|
throw IllegalStateException("Already initialized!")
|
||||||
|
}
|
||||||
|
|
||||||
|
initializing = true
|
||||||
|
|
||||||
|
Thread {
|
||||||
|
val time = System.currentTimeMillis()
|
||||||
|
callback(false, false, "Loading materials...")
|
||||||
|
|
||||||
|
loadTileMaterials {
|
||||||
|
if (terminateGame) {
|
||||||
|
throw InterruptedException("Game is terminating")
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(false, true, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(false, false, "Loaded materials")
|
||||||
|
|
||||||
|
initializing = false
|
||||||
|
initialized = true
|
||||||
|
callback(true, false, "Finished loading in ${System.currentTimeMillis() - time}ms")
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadTileMaterials(callback: (String) -> Unit) {
|
||||||
for (sPath in _filepath) {
|
for (sPath in _filepath) {
|
||||||
val newPath = File(sPath.path, "tiles/materials")
|
val newPath = File(sPath.path, "tiles/materials")
|
||||||
|
|
||||||
@ -72,6 +98,7 @@ object Starbound {
|
|||||||
for (listedFile in findFiles) {
|
for (listedFile in findFiles) {
|
||||||
if (listedFile.path.endsWith(".material")) {
|
if (listedFile.path.endsWith(".material")) {
|
||||||
try {
|
try {
|
||||||
|
callback("Loading ${listedFile.name}")
|
||||||
val tileDef = TileDefinitionBuilder.fromJson(JsonParser.parseReader(listedFile.bufferedReader()) as JsonObject).build(listedFile.parent)
|
val tileDef = TileDefinitionBuilder.fromJson(JsonParser.parseReader(listedFile.bufferedReader()) as JsonObject).build(listedFile.parent)
|
||||||
|
|
||||||
check(tiles[tileDef.materialName] == null) { "Already has material with ID ${tileDef.materialName} loaded!" }
|
check(tiles[tileDef.materialName] == null) { "Already has material with ID ${tileDef.materialName} loaded!" }
|
||||||
|
@ -12,3 +12,29 @@ interface IStruct3f : IStruct2f {
|
|||||||
interface IStruct4f : IStruct3f {
|
interface IStruct4f : IStruct3f {
|
||||||
operator fun component4(): Float
|
operator fun component4(): Float
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IStruct2d {
|
||||||
|
operator fun component1(): Double
|
||||||
|
operator fun component2(): Double
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IStruct3d : IStruct2d {
|
||||||
|
operator fun component3(): Double
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IStruct4d : IStruct3d {
|
||||||
|
operator fun component4(): Double
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IStruct2i {
|
||||||
|
operator fun component1(): Int
|
||||||
|
operator fun component2(): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IStruct3i : IStruct2i {
|
||||||
|
operator fun component3(): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IStruct4i : IStruct3i {
|
||||||
|
operator fun component4(): Int
|
||||||
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package ru.dbotthepony.kstarbound.math
|
package ru.dbotthepony.kstarbound.math
|
||||||
|
|
||||||
|
import ru.dbotthepony.kstarbound.api.IStruct3f
|
||||||
|
import ru.dbotthepony.kstarbound.api.IStruct4f
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.nio.ByteOrder
|
import java.nio.ByteOrder
|
||||||
import java.nio.FloatBuffer
|
import java.nio.FloatBuffer
|
||||||
@ -11,7 +13,7 @@ interface IMatrixLike {
|
|||||||
val rows: Int
|
val rows: Int
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMatrixLikeGetterI {
|
interface IMatrixLikeInt {
|
||||||
operator fun get(row: Int, column: Int): Int
|
operator fun get(row: Int, column: Int): Int
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,14 +41,22 @@ interface FloatMatrix<T : FloatMatrix<T>> : IMatrix, IMatrixLikeFloat {
|
|||||||
* Если матрица больше или меньше, считать что всевозможные остальные координаты равны единице (не менять)
|
* Если матрица больше или меньше, считать что всевозможные остальные координаты равны единице (не менять)
|
||||||
*/
|
*/
|
||||||
fun scale(x: Float, y: Float = 1f, z: Float = 1f, w: Float = 1f): T
|
fun scale(x: Float, y: Float = 1f, z: Float = 1f, w: Float = 1f): T
|
||||||
|
fun scale(value: IStruct4f): T {
|
||||||
fun scale(value: Vector4f) = scale(value.x, value.y, value.z, value.w)
|
val (x, y, z, w) = value
|
||||||
|
return scale(x, y, z, w)
|
||||||
|
}
|
||||||
|
|
||||||
fun translate(x: Float = 0f, y: Float = 0f, z: Float = 0f): T
|
fun translate(x: Float = 0f, y: Float = 0f, z: Float = 0f): T
|
||||||
fun translate(vector3f: Vector3f) = translate(vector3f.x, vector3f.y, vector3f.z)
|
fun translate(value: IStruct3f): T {
|
||||||
|
val (x, y, z) = value
|
||||||
|
return translate(x, y, z)
|
||||||
|
}
|
||||||
|
|
||||||
fun translateWithScale(x: Float = 0f, y: Float = 0f, z: Float = 0f): T
|
fun translateWithScale(x: Float = 0f, y: Float = 0f, z: Float = 0f): T
|
||||||
fun translateWithScale(vector3f: Vector3f) = translateWithScale(vector3f.x, vector3f.y, vector3f.z)
|
fun translateWithScale(value: IStruct3f): T {
|
||||||
|
val (x, y, z) = value
|
||||||
|
return translateWithScale(x, y, z)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Выдает массив в готовом для OpenGL виде (строка -> столбец) по умолчанию
|
* Выдает массив в готовом для OpenGL виде (строка -> столбец) по умолчанию
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package ru.dbotthepony.kstarbound.math
|
package ru.dbotthepony.kstarbound.math
|
||||||
|
|
||||||
|
import ru.dbotthepony.kstarbound.api.IStruct3f
|
||||||
|
|
||||||
class Matrix4fStack {
|
class Matrix4fStack {
|
||||||
private val stack = ArrayDeque<MutableMatrix4f>()
|
private val stack = ArrayDeque<MutableMatrix4f>()
|
||||||
|
|
||||||
@ -70,12 +72,12 @@ class Matrix4fStack {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun translate(vec: Vector3f): Matrix4fStack {
|
fun translate(vec: IStruct3f): Matrix4fStack {
|
||||||
last.translate(vec)
|
last.translate(vec)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun translateWithScale(vec: Vector3f): Matrix4fStack {
|
fun translateWithScale(vec: IStruct3f): Matrix4fStack {
|
||||||
last.translateWithScale(vec)
|
last.translateWithScale(vec)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package ru.dbotthepony.kstarbound.math
|
package ru.dbotthepony.kstarbound.math
|
||||||
|
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
|
import ru.dbotthepony.kstarbound.api.IStruct2i
|
||||||
|
import ru.dbotthepony.kstarbound.api.IStruct3f
|
||||||
|
import ru.dbotthepony.kstarbound.api.IStruct4f
|
||||||
import kotlin.math.cos
|
import kotlin.math.cos
|
||||||
import kotlin.math.sin
|
import kotlin.math.sin
|
||||||
|
|
||||||
abstract class IVector2i<T : IVector2i<T>> : IMatrixLike, IMatrixLikeGetterI {
|
abstract class IVector2i<T : IVector2i<T>> : IMatrixLike, IMatrixLikeInt, IStruct2i {
|
||||||
override val columns = 1
|
override val columns = 1
|
||||||
override val rows = 2
|
override val rows = 2
|
||||||
|
|
||||||
@ -56,10 +59,24 @@ data class Vector2i(override val x: Int = 0, override val y: Int = 0) : IVector2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Vector3f(val x: Float = 0f, val y: Float = 0f, val z: Float = 0f) : IMatrixLikeFloat {
|
abstract class IVector3f<T : IVector3f<T>> : IMatrixLike, IMatrixLikeFloat, IStruct3f {
|
||||||
override val columns = 1
|
override val columns = 1
|
||||||
override val rows = 3
|
override val rows = 3
|
||||||
|
|
||||||
|
abstract val x: Float
|
||||||
|
abstract val y: Float
|
||||||
|
abstract val z: Float
|
||||||
|
|
||||||
|
operator fun plus(other: IVector3f<*>) = make(x + other.x, y + other.y, z + other.z)
|
||||||
|
operator fun minus(other: IVector3f<*>) = make(x - other.x, y - other.y, z - other.z)
|
||||||
|
operator fun times(other: IVector3f<*>) = make(x * other.x, y * other.y, z * other.z)
|
||||||
|
operator fun div(other: IVector3f<*>) = make(x / other.x, y / other.y, z / other.z)
|
||||||
|
|
||||||
|
operator fun plus(other: Float) = make(x + other, y + other, z + other)
|
||||||
|
operator fun minus(other: Float) = make(x - other, y - other, z - other)
|
||||||
|
operator fun times(other: Float) = make(x * other, y * other, z * other)
|
||||||
|
operator fun div(other: Float) = make(x / other, y / other, z / other)
|
||||||
|
|
||||||
override fun get(row: Int, column: Int): Float {
|
override fun get(row: Int, column: Int): Float {
|
||||||
if (column != 0) {
|
if (column != 0) {
|
||||||
throw IndexOutOfBoundsException("Column must be 0 ($column given)")
|
throw IndexOutOfBoundsException("Column must be 0 ($column given)")
|
||||||
@ -85,7 +102,7 @@ data class Vector3f(val x: Float = 0f, val y: Float = 0f, val z: Float = 0f) : I
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun times(other: IMatrixLikeFloat): Vector3f {
|
operator fun times(other: IMatrixLikeFloat): T {
|
||||||
if (other.rows >= 4 && other.columns >= 4) {
|
if (other.rows >= 4 && other.columns >= 4) {
|
||||||
val x = this.x * other[0, 0] +
|
val x = this.x * other[0, 0] +
|
||||||
this.y * other[0, 1] +
|
this.y * other[0, 1] +
|
||||||
@ -102,7 +119,7 @@ data class Vector3f(val x: Float = 0f, val y: Float = 0f, val z: Float = 0f) : I
|
|||||||
this.z * other[2, 2] +
|
this.z * other[2, 2] +
|
||||||
other[2, 3]
|
other[2, 3]
|
||||||
|
|
||||||
return Vector3f(x, y, z)
|
return make(x, y, z)
|
||||||
} else if (other.rows >= 3 && other.columns >= 3) {
|
} else if (other.rows >= 3 && other.columns >= 3) {
|
||||||
val x = this.x * other[0, 0] +
|
val x = this.x * other[0, 0] +
|
||||||
this.y * other[0, 1] +
|
this.y * other[0, 1] +
|
||||||
@ -116,12 +133,24 @@ data class Vector3f(val x: Float = 0f, val y: Float = 0f, val z: Float = 0f) : I
|
|||||||
this.y * other[2, 1] +
|
this.y * other[2, 1] +
|
||||||
this.z * other[2, 2]
|
this.z * other[2, 2]
|
||||||
|
|
||||||
return Vector3f(x, y, z)
|
return make(x, y, z)
|
||||||
}
|
}
|
||||||
|
|
||||||
throw IllegalArgumentException("Incompatible matrix provided: ${other.rows} x ${other.columns}")
|
throw IllegalArgumentException("Incompatible matrix provided: ${other.rows} x ${other.columns}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract fun make(x: Float, y: Float, z: Float): T
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Vector3f(override val x: Float = 0f, override val y: Float = 0f, override val z: Float = 0f) : IVector3f<Vector3f>() {
|
||||||
|
override fun make(x: Float, y: Float, z: Float): Vector3f {
|
||||||
|
return Vector3f(x, y, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toMutableVector(): MutableVector3f {
|
||||||
|
return MutableVector3f(x, y, z)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val UP = Vector3f(0f, 1f, 0f)
|
val UP = Vector3f(0f, 1f, 0f)
|
||||||
val DOWN = Vector3f(0f, -1f, 0f)
|
val DOWN = Vector3f(0f, -1f, 0f)
|
||||||
@ -132,7 +161,35 @@ data class Vector3f(val x: Float = 0f, val y: Float = 0f, val z: Float = 0f) : I
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Vector4f(val x: Float = 0f, val y: Float = 0f, val z: Float = 0f, val w: Float = 0f) : IMatrixLikeFloat {
|
data class MutableVector3f(override var x: Float = 0f, override var y: Float = 0f, override var z: Float = 0f) : IVector3f<MutableVector3f>() {
|
||||||
|
fun toVector(): Vector3f {
|
||||||
|
return Vector3f(x, y, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun make(x: Float, y: Float, z: Float): MutableVector3f {
|
||||||
|
this.x = x
|
||||||
|
this.y = y
|
||||||
|
this.z = z
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class IVector4f<T : IVector4f<T>> : IMatrixLike, IMatrixLikeFloat, IStruct4f {
|
||||||
|
abstract val x: Float
|
||||||
|
abstract val y: Float
|
||||||
|
abstract val z: Float
|
||||||
|
abstract val w: Float
|
||||||
|
|
||||||
|
operator fun plus(other: IVector4f<*>) = make(x + other.x, y + other.y, z + other.z, w + other.w)
|
||||||
|
operator fun minus(other: IVector4f<*>) = make(x - other.x, y - other.y, z - other.z, w + other.w)
|
||||||
|
operator fun times(other: IVector4f<*>) = make(x * other.x, y * other.y, z * other.z, w + other.w)
|
||||||
|
operator fun div(other: IVector4f<*>) = make(x / other.x, y / other.y, z / other.z, w + other.w)
|
||||||
|
|
||||||
|
operator fun plus(other: Float) = make(x + other, y + other, z + other, w + other)
|
||||||
|
operator fun minus(other: Float) = make(x - other, y - other, z - other, w - other)
|
||||||
|
operator fun times(other: Float) = make(x * other, y * other, z * other, w * other)
|
||||||
|
operator fun div(other: Float) = make(x / other, y / other, z / other, w / other)
|
||||||
|
|
||||||
override val columns = 1
|
override val columns = 1
|
||||||
override val rows = 4
|
override val rows = 4
|
||||||
|
|
||||||
@ -150,7 +207,7 @@ data class Vector4f(val x: Float = 0f, val y: Float = 0f, val z: Float = 0f, val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun times(other: IMatrixLikeFloat): Vector4f {
|
operator fun times(other: IMatrixLikeFloat): T {
|
||||||
if (other.rows >= 4 && other.columns >= 4) {
|
if (other.rows >= 4 && other.columns >= 4) {
|
||||||
val x = this.x * other[0, 0] +
|
val x = this.x * other[0, 0] +
|
||||||
this.y * other[0, 1] +
|
this.y * other[0, 1] +
|
||||||
@ -172,9 +229,27 @@ data class Vector4f(val x: Float = 0f, val y: Float = 0f, val z: Float = 0f, val
|
|||||||
this.z * other[3, 2] +
|
this.z * other[3, 2] +
|
||||||
this.w * other[3, 3]
|
this.w * other[3, 3]
|
||||||
|
|
||||||
return Vector4f(x, y, z, w)
|
return make(x, y, z, w)
|
||||||
}
|
}
|
||||||
|
|
||||||
throw IllegalArgumentException("Incompatible matrix provided: ${other.rows} x ${other.columns}")
|
throw IllegalArgumentException("Incompatible matrix provided: ${other.rows} x ${other.columns}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract fun make(x: Float, y: Float, z: Float, w: Float): T
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Vector4f(override val x: Float = 0f, override val y: Float = 0f, override val z: Float = 0f, override val w: Float = 0f) : IVector4f<Vector4f>() {
|
||||||
|
override fun make(x: Float, y: Float, z: Float, w: Float): Vector4f {
|
||||||
|
return Vector4f(x, y, z, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class MutableVector4f(override var x: Float = 0f, override var y: Float = 0f, override var z: Float = 0f, override var w: Float = 0f) : IVector4f<MutableVector4f>() {
|
||||||
|
override fun make(x: Float, y: Float, z: Float, w: Float): MutableVector4f {
|
||||||
|
this.x = x
|
||||||
|
this.y = y
|
||||||
|
this.z = z
|
||||||
|
this.w = w
|
||||||
|
return this
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
package ru.dbotthepony.kstarbound.render
|
package ru.dbotthepony.kstarbound.render
|
||||||
|
|
||||||
import ru.dbotthepony.kstarbound.math.Matrix4f
|
import ru.dbotthepony.kstarbound.math.*
|
||||||
import ru.dbotthepony.kstarbound.math.Vector3f
|
|
||||||
|
|
||||||
class Camera {
|
class Camera {
|
||||||
var pos = Vector3f(z = 400f)
|
val pos = MutableVector3f()
|
||||||
var zoom = 1f
|
var zoom = 1f
|
||||||
|
|
||||||
fun matrix(): Matrix4f {
|
fun translate(stack: FloatMatrix<*>) {
|
||||||
return Matrix4f.IDENTITY.scale(zoom, zoom, zoom).translate(pos)
|
stack.translateWithScale(pos)
|
||||||
|
stack.scale(x = zoom, y = zoom)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun userInput(key: Int, scancode: Int, action: Int, mods: Int) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -8,6 +8,7 @@ import ru.dbotthepony.kstarbound.freetype.LoadFlag
|
|||||||
import ru.dbotthepony.kstarbound.freetype.struct.FT_Pixel_Mode
|
import ru.dbotthepony.kstarbound.freetype.struct.FT_Pixel_Mode
|
||||||
import ru.dbotthepony.kstarbound.gl.*
|
import ru.dbotthepony.kstarbound.gl.*
|
||||||
import ru.dbotthepony.kstarbound.math.Matrix4fStack
|
import ru.dbotthepony.kstarbound.math.Matrix4fStack
|
||||||
|
import ru.dbotthepony.kstarbound.util.Color
|
||||||
|
|
||||||
private fun breakLines(text: String): List<String> {
|
private fun breakLines(text: String): List<String> {
|
||||||
var nextLineBreak = text.indexOf('\n', 0)
|
var nextLineBreak = text.indexOf('\n', 0)
|
||||||
@ -83,6 +84,8 @@ class Font(
|
|||||||
alignX: TextAlignX = TextAlignX.LEFT,
|
alignX: TextAlignX = TextAlignX.LEFT,
|
||||||
alignY: TextAlignY = TextAlignY.TOP,
|
alignY: TextAlignY = TextAlignY.TOP,
|
||||||
|
|
||||||
|
color: Color = Color.WHITE,
|
||||||
|
|
||||||
scale: Float = 1f,
|
scale: Float = 1f,
|
||||||
stack: Matrix4fStack = state.matrixStack,
|
stack: Matrix4fStack = state.matrixStack,
|
||||||
): TextSize {
|
): TextSize {
|
||||||
@ -107,6 +110,7 @@ class Font(
|
|||||||
stack.scale(x = scale, y = scale)
|
stack.scale(x = scale, y = scale)
|
||||||
|
|
||||||
state.fontProgram.use()
|
state.fontProgram.use()
|
||||||
|
state.fontProgram.color.set(color)
|
||||||
state.activeTexture = 0
|
state.activeTexture = 0
|
||||||
|
|
||||||
val space = getGlyph(' ')
|
val space = getGlyph(' ')
|
||||||
@ -165,7 +169,7 @@ class Font(
|
|||||||
state.VAO = null
|
state.VAO = null
|
||||||
stack.pop()
|
stack.pop()
|
||||||
|
|
||||||
return totalSize
|
return TextSize(totalX * scale, totalY * scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun render(
|
fun render(
|
||||||
@ -177,10 +181,21 @@ class Font(
|
|||||||
alignX: TextAlignX = TextAlignX.LEFT,
|
alignX: TextAlignX = TextAlignX.LEFT,
|
||||||
alignY: TextAlignY = TextAlignY.TOP,
|
alignY: TextAlignY = TextAlignY.TOP,
|
||||||
|
|
||||||
|
color: Color = Color.WHITE,
|
||||||
|
|
||||||
scale: Float = 1f,
|
scale: Float = 1f,
|
||||||
stack: Matrix4fStack = state.matrixStack,
|
stack: Matrix4fStack = state.matrixStack,
|
||||||
): TextSize {
|
): TextSize {
|
||||||
return render(breakLines(text), x, y, alignX, alignY, scale, stack)
|
return render(
|
||||||
|
breakLines(text),
|
||||||
|
x = x,
|
||||||
|
y = y,
|
||||||
|
alignX = alignX,
|
||||||
|
alignY = alignY,
|
||||||
|
scale = scale,
|
||||||
|
stack = stack,
|
||||||
|
color = color,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun lineWidth(line: String, space: Glyph): Float {
|
private fun lineWidth(line: String, space: Glyph): Float {
|
||||||
|
@ -59,7 +59,8 @@ class TileRenderers(val state: GLStateTracker) {
|
|||||||
|
|
||||||
operator fun get(tile: String): TileRenderer {
|
operator fun get(tile: String): TileRenderer {
|
||||||
return tileRenderers.computeIfAbsent(tile) {
|
return tileRenderers.computeIfAbsent(tile) {
|
||||||
return@computeIfAbsent TileRenderer(state, Starbound.loadTileDefinition(tile))
|
val def = Starbound.getTileDefinition(tile) // TODO: Пустой рендерер
|
||||||
|
return@computeIfAbsent TileRenderer(state, def!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package ru.dbotthepony.kstarbound.util
|
package ru.dbotthepony.kstarbound.util
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
import ru.dbotthepony.kstarbound.api.IStruct4f
|
import ru.dbotthepony.kstarbound.api.IStruct4f
|
||||||
|
|
||||||
@ -8,5 +9,13 @@ data class Color(val red: Float, val green: Float, val blue: Float, val alpha: F
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val WHITE = Color(1f, 1f, 1f)
|
val WHITE = Color(1f, 1f, 1f)
|
||||||
|
|
||||||
|
val SHADES_OF_GRAY = ArrayList<Color>().let {
|
||||||
|
for (i in 0 .. 256) {
|
||||||
|
it.add(Color(i / 256f, i / 256f, i / 256f))
|
||||||
|
}
|
||||||
|
|
||||||
|
return@let ImmutableList.copyOf(it) as List<Color>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user