mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-10 10:34:06 +09:00
Compare commits
137 Commits
v0.3.2-tes
...
v0.3.3-tes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97a7a36030 | ||
|
|
662069466a | ||
|
|
52cff00338 | ||
|
|
1a40334f8e | ||
|
|
763f512419 | ||
|
|
620a1c6956 | ||
|
|
5f4fcdba69 | ||
|
|
7a79f444b2 | ||
|
|
e4b947ce69 | ||
|
|
fdfec960ca | ||
|
|
75021ecfa2 | ||
|
|
c90ef21bfa | ||
|
|
3fce5d7e95 | ||
|
|
8db1228e70 | ||
|
|
5f7f724058 | ||
|
|
fab4179068 | ||
|
|
32803b6f18 | ||
|
|
f8f75fb7b6 | ||
|
|
9919a99032 | ||
|
|
6a43d1a5bd | ||
|
|
24c971e4b8 | ||
|
|
62f0fd7c68 | ||
|
|
3dec312989 | ||
|
|
77b51a45dd | ||
|
|
d1b4ce3404 | ||
|
|
fd7b88307c | ||
|
|
579b6b5b29 | ||
|
|
cef58f6a73 | ||
|
|
c0c98c3b80 | ||
|
|
88d844cc09 | ||
|
|
2411db17a7 | ||
|
|
53d372be38 | ||
|
|
88831051c8 | ||
|
|
87d92ecb74 | ||
|
|
6672dffdbc | ||
|
|
cd00ab4c7f | ||
|
|
014306c209 | ||
|
|
30fb57eca3 | ||
|
|
52ad8f0c46 | ||
|
|
1b08039018 | ||
|
|
c701519cb9 | ||
|
|
75e6669d49 | ||
|
|
18631064d4 | ||
|
|
9fe6618cc9 | ||
|
|
7b8d6d6913 | ||
|
|
385a882937 | ||
|
|
c73461a407 | ||
|
|
f7e4987785 | ||
|
|
78bd88858b | ||
|
|
d2b1346252 | ||
|
|
fb28fd8a76 | ||
|
|
36d25c6479 | ||
|
|
2ade76147c | ||
|
|
59d9adbbd1 | ||
|
|
821c7c77d8 | ||
|
|
3308f09e08 | ||
|
|
37d45e22ad | ||
|
|
1ac861fa82 | ||
|
|
451808cd1c | ||
|
|
0c00b3b7cc | ||
|
|
1669f7fdd0 | ||
|
|
f4bfe84009 | ||
|
|
91cf08e93a | ||
|
|
33a8112454 | ||
|
|
439cde09fc | ||
|
|
2a62435712 | ||
|
|
5495552db5 | ||
|
|
e04d0284bb | ||
|
|
ad601ffd7e | ||
|
|
987ec1fd98 | ||
|
|
4fb30821f1 | ||
|
|
a73c536941 | ||
|
|
4c1f16fe91 | ||
|
|
6df78b59a9 | ||
|
|
28c4d8f11b | ||
|
|
cdfc86398c | ||
|
|
91d94d2dab | ||
|
|
0af2e57368 | ||
|
|
fbce707cac | ||
|
|
9d7bd37394 | ||
|
|
df8bcf79af | ||
|
|
e328457259 | ||
|
|
9baec6c7a1 | ||
|
|
d05364f43f | ||
|
|
e7ed3d8eae | ||
|
|
da6da79186 | ||
|
|
0767521441 | ||
|
|
30aca57cbc | ||
|
|
e512c6c7ad | ||
|
|
6ebf79a8e3 | ||
|
|
e5d5feeb38 | ||
|
|
8e9d2371c8 | ||
|
|
1f5d032ad8 | ||
|
|
7993ccd2e5 | ||
|
|
c77f1ffd23 | ||
|
|
4eb7a8a77e | ||
|
|
10f92a11a9 | ||
|
|
c5659e2833 | ||
|
|
173f99f87d | ||
|
|
64e05a4f17 | ||
|
|
c033260ec5 | ||
|
|
22191bd377 | ||
|
|
79f19120f2 | ||
|
|
d96b7d1b84 | ||
|
|
2b62b4f413 | ||
|
|
f0fa5830bd | ||
|
|
ec24dc9870 | ||
|
|
6bc3d0e6ad | ||
|
|
64c610e77e | ||
|
|
b25ea9654c | ||
|
|
b6b98562a2 | ||
|
|
c93b70f537 | ||
|
|
fb67b0ef5a | ||
|
|
7c7b3de68d | ||
|
|
71df31b93d | ||
|
|
9b24014191 | ||
|
|
02308a7918 | ||
|
|
03c6061a12 | ||
|
|
325e67f999 | ||
|
|
211f936bd3 | ||
|
|
1f6fa49d19 | ||
|
|
13810fc09b | ||
|
|
f95bc36c98 | ||
|
|
d507d84950 | ||
|
|
b31da6ffec | ||
|
|
3593894c0f | ||
|
|
c28b286553 | ||
|
|
c0a3da1b66 | ||
|
|
02cf5fdce5 | ||
|
|
1e6f51e16c | ||
|
|
c61c169048 | ||
|
|
5c58c3006b | ||
|
|
742cabb81f | ||
|
|
07d5e571d6 | ||
|
|
305242045f | ||
|
|
67388999f0 | ||
|
|
b0cc1180bb |
@@ -1,26 +1,17 @@
|
|||||||
package net.torvald.terrarum.modulecomputers.gameactors
|
package net.torvald.terrarum.modulecomputers.gameactors
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx
|
|
||||||
import com.badlogic.gdx.Input
|
|
||||||
import com.badlogic.gdx.graphics.*
|
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
|
||||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
|
||||||
import com.badlogic.gdx.utils.Disposable
|
import com.badlogic.gdx.utils.Disposable
|
||||||
import kotlin.coroutines.*
|
|
||||||
import net.torvald.terrarum.*
|
import net.torvald.terrarum.*
|
||||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||||
import net.torvald.terrarum.gameactors.AVKey
|
import net.torvald.terrarum.gameactors.AVKey
|
||||||
import net.torvald.terrarum.langpack.Lang
|
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.BlockBox
|
import net.torvald.terrarum.modulebasegame.gameactors.BlockBox
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
|
import net.torvald.terrarum.modulebasegame.gameactors.FixtureBase
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
|
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
|
||||||
import net.torvald.terrarum.ui.Toolkit
|
import net.torvald.terrarum.modulecomputers.ui.UIHomeComputer
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
|
||||||
import net.torvald.tsvm.*
|
import net.torvald.tsvm.*
|
||||||
import net.torvald.tsvm.peripheral.AdapterConfig
|
import net.torvald.tsvm.peripheral.AdapterConfig
|
||||||
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
||||||
import net.torvald.tsvm.peripheral.VMProgramRom
|
import net.torvald.tsvm.peripheral.VMProgramRom
|
||||||
import net.torvald.unicode.*
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2021-12-04.
|
* Created by minjaesong on 2021-12-04.
|
||||||
@@ -131,77 +122,3 @@ class FixtureHomeComputer : FixtureBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class UIHomeComputer : UICanvas(
|
|
||||||
toggleKeyLiteral = Input.Keys.ESCAPE, // FIXME why do I have specify ESC for it to function? ESC should be work as the default key
|
|
||||||
toggleButtonLiteral = App.getConfigInt("control_gamepad_start"),
|
|
||||||
) {
|
|
||||||
override var width = 640
|
|
||||||
override var height = 480
|
|
||||||
override var openCloseTime = 0f
|
|
||||||
|
|
||||||
private val drawOffX = (width - 560).div(2).toFloat()
|
|
||||||
private val drawOffY = (height - 448).div(2).toFloat()
|
|
||||||
|
|
||||||
private var batch: FlippingSpriteBatch
|
|
||||||
private var camera: OrthographicCamera
|
|
||||||
|
|
||||||
internal lateinit var vm: VM
|
|
||||||
internal lateinit var fixture: FixtureHomeComputer
|
|
||||||
|
|
||||||
init {
|
|
||||||
batch = FlippingSpriteBatch()
|
|
||||||
camera = OrthographicCamera(width.toFloat(), height.toFloat())
|
|
||||||
//val m = Matrix4()
|
|
||||||
//m.setToOrtho2D(0f, 0f, width.toFloat(), height.toFloat())
|
|
||||||
batch.projectionMatrix = camera.combined
|
|
||||||
}
|
|
||||||
|
|
||||||
private val fbo = FrameBuffer(Pixmap.Format.RGBA8888, width, height, false)
|
|
||||||
|
|
||||||
private val controlHelp =
|
|
||||||
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}\u3000 " +
|
|
||||||
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_T$KEYCAP_R Terminate\u3000" +
|
|
||||||
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_R$KEYCAP_S Reset\u3000" +
|
|
||||||
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_R$KEYCAP_Q SysRq"
|
|
||||||
|
|
||||||
override fun updateUI(delta: Float) {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun renderUI(otherBatch: SpriteBatch, otherCamera: Camera) {
|
|
||||||
otherBatch.end()
|
|
||||||
|
|
||||||
fbo.inAction(camera, batch) {
|
|
||||||
Gdx.gl.glClearColor(0f,0f,0f,1f)
|
|
||||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) // to hide the crap might be there
|
|
||||||
|
|
||||||
(vm.peripheralTable[1].peripheral as? GraphicsAdapter)?.let { gpu ->
|
|
||||||
val clearCol = gpu.getBackgroundColour()
|
|
||||||
Gdx.gl.glClearColor(clearCol.r, clearCol.g, clearCol.b, clearCol.a)
|
|
||||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
|
||||||
|
|
||||||
gpu.render(Gdx.graphics.deltaTime, batch, drawOffX, drawOffY, true, fbo) // gpu.render will internally end() the fbo then begin() again before using the batch I've fed in
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
otherBatch.begin()
|
|
||||||
otherBatch.shader = null
|
|
||||||
blendNormalStraightAlpha(otherBatch)
|
|
||||||
otherBatch.color = Color.WHITE
|
|
||||||
otherBatch.draw(fbo.colorBufferTexture, posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat())
|
|
||||||
otherBatch.color = Toolkit.Theme.COL_INACTIVE
|
|
||||||
Toolkit.drawBoxBorder(otherBatch, posX - 1, posY - 1, width + 2, height + 2)
|
|
||||||
|
|
||||||
App.fontGame.draw(otherBatch, controlHelp, posX, posY + height + 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun doOpening(delta: Float) {
|
|
||||||
super.doOpening(delta)
|
|
||||||
fixture.startVM()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun dispose() {
|
|
||||||
fbo.dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package net.torvald.terrarum.modulecomputers.ui
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx
|
||||||
|
import com.badlogic.gdx.Input
|
||||||
|
import com.badlogic.gdx.graphics.*
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
||||||
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||||
|
import net.torvald.terrarum.App
|
||||||
|
import net.torvald.terrarum.FlippingSpriteBatch
|
||||||
|
import net.torvald.terrarum.blendNormalStraightAlpha
|
||||||
|
import net.torvald.terrarum.inAction
|
||||||
|
import net.torvald.terrarum.langpack.Lang
|
||||||
|
import net.torvald.terrarum.modulecomputers.gameactors.FixtureHomeComputer
|
||||||
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
|
import net.torvald.tsvm.VM
|
||||||
|
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
||||||
|
import net.torvald.unicode.*
|
||||||
|
|
||||||
|
internal class UIHomeComputer : UICanvas(
|
||||||
|
toggleKeyLiteral = Input.Keys.ESCAPE, // FIXME why do I have specify ESC for it to function? ESC should be work as the default key
|
||||||
|
toggleButtonLiteral = App.getConfigInt("control_gamepad_start"),
|
||||||
|
) {
|
||||||
|
override var width = 640
|
||||||
|
override var height = 480
|
||||||
|
override var openCloseTime = 0f
|
||||||
|
|
||||||
|
private val drawOffX = (width - 560).div(2).toFloat()
|
||||||
|
private val drawOffY = (height - 448).div(2).toFloat()
|
||||||
|
|
||||||
|
private var batch: FlippingSpriteBatch
|
||||||
|
private var camera: OrthographicCamera
|
||||||
|
|
||||||
|
internal lateinit var vm: VM
|
||||||
|
internal lateinit var fixture: FixtureHomeComputer
|
||||||
|
|
||||||
|
init {
|
||||||
|
batch = FlippingSpriteBatch()
|
||||||
|
camera = OrthographicCamera(width.toFloat(), height.toFloat())
|
||||||
|
//val m = Matrix4()
|
||||||
|
//m.setToOrtho2D(0f, 0f, width.toFloat(), height.toFloat())
|
||||||
|
batch.projectionMatrix = camera.combined
|
||||||
|
}
|
||||||
|
|
||||||
|
private val fbo = FrameBuffer(Pixmap.Format.RGBA8888, width, height, false)
|
||||||
|
|
||||||
|
private val controlHelp =
|
||||||
|
"${getKeycapPC(App.getConfigInt("control_key_inventory"))} ${Lang["GAME_ACTION_CLOSE"]}\u3000 " +
|
||||||
|
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_T$KEYCAP_R Terminate\u3000" +
|
||||||
|
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_R$KEYCAP_S Reset\u3000" +
|
||||||
|
"$KEYCAP_CTRL$KEYCAP_SHIFT$KEYCAP_R$KEYCAP_Q SysRq"
|
||||||
|
|
||||||
|
override fun updateUI(delta: Float) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun renderUI(otherBatch: SpriteBatch, otherCamera: Camera) {
|
||||||
|
otherBatch.end()
|
||||||
|
|
||||||
|
fbo.inAction(camera, batch) {
|
||||||
|
Gdx.gl.glClearColor(0f,0f,0f,1f)
|
||||||
|
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT) // to hide the crap might be there
|
||||||
|
|
||||||
|
(vm.peripheralTable[1].peripheral as? GraphicsAdapter)?.let { gpu ->
|
||||||
|
val clearCol = gpu.getBackgroundColour()
|
||||||
|
Gdx.gl.glClearColor(clearCol.r, clearCol.g, clearCol.b, clearCol.a)
|
||||||
|
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
|
||||||
|
|
||||||
|
gpu.render(Gdx.graphics.deltaTime, batch, drawOffX, drawOffY, true, fbo) // gpu.render will internally end() the fbo then begin() again before using the batch I've fed in
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
otherBatch.begin()
|
||||||
|
otherBatch.shader = null
|
||||||
|
blendNormalStraightAlpha(otherBatch)
|
||||||
|
otherBatch.color = Color.WHITE
|
||||||
|
otherBatch.draw(fbo.colorBufferTexture, posX.toFloat(), posY.toFloat(), width.toFloat(), height.toFloat())
|
||||||
|
otherBatch.color = Toolkit.Theme.COL_INACTIVE
|
||||||
|
Toolkit.drawBoxBorder(otherBatch, posX - 1, posY - 1, width + 2, height + 2)
|
||||||
|
|
||||||
|
App.fontGame.draw(otherBatch, controlHelp, posX, posY + height + 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doOpening(delta: Float) {
|
||||||
|
super.doOpening(delta)
|
||||||
|
fixture.startVM()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
fbo.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
BIN
assets/clut/skybox.png
LFS
Normal file
BIN
assets/clut/skybox.png
LFS
Normal file
Binary file not shown.
BIN
assets/graphics/astrum.png
LFS
Normal file
BIN
assets/graphics/astrum.png
LFS
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -379,11 +379,11 @@ let isDiacritics = (s) => s !== undefined && inRange(s.charCodeAt(0), 0x0300, 0x
|
|||||||
return Object.freeze({"n":"\uDBBF\uDFC1Бъл. Многоезична\uDBBF\uDFC0","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"\uDBBF\uDFC1Бъл. Многоезична\uDBBF\uDFC0","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"t":dislplayKeyLayouts,
|
"t":dislplayKeyLayouts,
|
||||||
"l":"bgBG",
|
"l":"bgBG",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin + 2*altgrin
|
let layer = 1*shiftin + 2*altgrin
|
||||||
|
|
||||||
let s = states.keylayouts[headkey][layer]
|
let s = (states.keylayouts[headkey][layer] || states.keylayouts[headkey][1*shiftin]) || states.keylayouts[headkey][0]
|
||||||
|
|
||||||
// typing seq for diacritics: diacritics THEN a character
|
// typing seq for diacritics: diacritics THEN a character
|
||||||
if (isDiacritics(s)) {
|
if (isDiacritics(s)) {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ let isDiacritics = (s) => s !== undefined && inRange(s.charCodeAt(0), 0x0300, 0x
|
|||||||
return Object.freeze({"n":"Ελ. Φωνητικό","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"Ελ. Φωνητικό","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"tf":states.layouttable,
|
"tf":states.layouttable,
|
||||||
"l":"elGR",
|
"l":"elGR",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin,lowlayerkey)=>{
|
"accept":(headkey,shiftin,altgrin,lowlayerkey)=>{
|
||||||
let layer = 1*shiftin + 2*altgrin
|
let layer = 1*shiftin + 2*altgrin
|
||||||
|
|
||||||
|
|||||||
283
assets/keylayout/hi_in_inscript.ime
Normal file
283
assets/keylayout/hi_in_inscript.ime
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
let states = {"keylayouts":[[""],[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
["0",")","\u0966",")"],
|
||||||
|
["1","\u090D","\u0967","!"],
|
||||||
|
["2","\u0945","\u0968","@"],
|
||||||
|
["3","\u094D\u0930","\u0969","#"],
|
||||||
|
["4","\u0930\u094D","\u096A","$"],
|
||||||
|
["5","\u091C\u094D\u091E","\u096B","%"],
|
||||||
|
["6","\u0924\u094D\u0930","\u096C","^"],
|
||||||
|
["7","\u0915\u094D\u0937","\u096D","&"],
|
||||||
|
["8","\u0936\u094D\u0930","\u096E","*"],
|
||||||
|
["9","(","\u096F","("],
|
||||||
|
["*"],
|
||||||
|
["#"],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
["\u094B","\u0913"],
|
||||||
|
["\u0935","\u0934"],
|
||||||
|
["\u092E","\u0923","\u0954","\u0923"],
|
||||||
|
["\u094D","\u0905"],
|
||||||
|
["\u093E","\u0906"],
|
||||||
|
["\u093F","\u0907","\u0962","\u090C"],
|
||||||
|
["\u0941","\u0909"],
|
||||||
|
["\u092A","\u092B","\u092A","\u095E"],
|
||||||
|
["\u0917","\u0918","\u095A","\u0918"],
|
||||||
|
["\u0930","\u0931"],
|
||||||
|
["\u0915","\u0916","\u0958","\u0959"],
|
||||||
|
["\u0924","\u0925"],
|
||||||
|
["\u0938","\u0936"],
|
||||||
|
["\u0932","\u0933"],
|
||||||
|
["\u0926","\u0927"],
|
||||||
|
["\u091C","\u091D","\u095B","\u091D"],
|
||||||
|
["\u094C","\u0914"],
|
||||||
|
["\u0940","\u0908","\u0963","\u0961"],
|
||||||
|
["\u0947","\u090F"],
|
||||||
|
["\u0942","\u090A"],
|
||||||
|
["\u0939","\u0919"],
|
||||||
|
["\u0928","\u0929"],
|
||||||
|
["\u0948","\u0910"],
|
||||||
|
["\u0902","\u0901","\u0902","\u0950"],
|
||||||
|
["\u092C","\u092D"],
|
||||||
|
["\u0946","\u090E","\u0953","\u090E"],
|
||||||
|
[",","\u0937","\u0970","\u0970"],
|
||||||
|
[".","\u0964","\u0965","\u093D"],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[" "],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
["\n"],
|
||||||
|
["\x08"],
|
||||||
|
["\u094A","\u0912"],
|
||||||
|
["-","\u0903"],
|
||||||
|
["\u0943","\u090B","\u0944","\u0960"],
|
||||||
|
["\u0921","\u0922","\u095C","\u095D"],
|
||||||
|
["\u093C","\u091E"],
|
||||||
|
["\u0949","\u0911"],
|
||||||
|
["\u091A","\u091B","\u0952","\u091B"],
|
||||||
|
["\u091F","\u0920","\u0951","\u0920"],
|
||||||
|
["\u092F","\u095F"],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
["0"],
|
||||||
|
["1"],
|
||||||
|
["2"],
|
||||||
|
["3"],
|
||||||
|
["4"],
|
||||||
|
["5"],
|
||||||
|
["6"],
|
||||||
|
["7"],
|
||||||
|
["8"],
|
||||||
|
["9"],
|
||||||
|
["/"],
|
||||||
|
["*"],
|
||||||
|
["-"],
|
||||||
|
["+"],
|
||||||
|
["."],
|
||||||
|
["."],
|
||||||
|
["\n"],
|
||||||
|
["="],
|
||||||
|
["("],
|
||||||
|
[")"],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined]
|
||||||
|
],
|
||||||
|
"code":""} // practically unused as long as there are no diacritics on the keyboard
|
||||||
|
let reset = () => {
|
||||||
|
states.code = 0
|
||||||
|
}
|
||||||
|
let inRange = (s,a,b) => (a <= s && s <= b)
|
||||||
|
return Object.freeze({"n":"इनस्क्रिप्ट","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
|
"t":states.keylayouts.slice(0,10).concat([["3","\uDBBF\uDE01\u094D\u0930","\u0969","#"], ["4","\u0930\u094D\uDBBF\uDE01","\u096A","$"]], states.keylayouts.slice(12)),
|
||||||
|
"l":"hiIN",
|
||||||
|
// return: [delete count, composed output]
|
||||||
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
|
let layer = 1*shiftin + 2*altgrin
|
||||||
|
|
||||||
|
let s = (states.keylayouts[headkey][layer] || states.keylayouts[headkey][1*shiftin]) || states.keylayouts[headkey][0]
|
||||||
|
|
||||||
|
return ['0', s]
|
||||||
|
},
|
||||||
|
"backspace":()=>{
|
||||||
|
reset()
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
"end":()=>{
|
||||||
|
reset()
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
"reset":()=>{ reset() },
|
||||||
|
"composing":()=>(states.code!='')
|
||||||
|
})
|
||||||
@@ -346,12 +346,12 @@ let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" :
|
|||||||
return Object.freeze({"n":"두벌식 표준","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"두벌식 표준","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
||||||
"l":"koKR",
|
"l":"koKR",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin// + 2*altgrin
|
let layer = 1*shiftin// + 2*altgrin
|
||||||
states.code = 1
|
states.code = 1
|
||||||
|
|
||||||
let s = states.keylayouts[headkey][layer]
|
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
|
||||||
|
|
||||||
if (isHangul(s)) {
|
if (isHangul(s)) {
|
||||||
let bufIndex = (isJongseongConsonant(s) && isConsonant(states.buf[0]) && undefined !== states.buf[1]) ? 2 :
|
let bufIndex = (isJongseongConsonant(s) && isConsonant(states.buf[0]) && undefined !== states.buf[1]) ? 2 :
|
||||||
|
|||||||
@@ -346,12 +346,12 @@ let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" :
|
|||||||
return Object.freeze({"n":"두벌식 수정 표준","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"두벌식 수정 표준","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
||||||
"l":"koKR",
|
"l":"koKR",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin// + 2*altgrin
|
let layer = 1*shiftin// + 2*altgrin
|
||||||
states.code = 1
|
states.code = 1
|
||||||
|
|
||||||
let s = states.keylayouts[headkey][layer]
|
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
|
||||||
|
|
||||||
if (isHangul(s)) {
|
if (isHangul(s)) {
|
||||||
let bufIndex = (isJongseongConsonant(s) && isConsonant(states.buf[0]) && undefined !== states.buf[1]) ? 2 :
|
let bufIndex = (isJongseongConsonant(s) && isConsonant(states.buf[0]) && undefined !== states.buf[1]) ? 2 :
|
||||||
|
|||||||
@@ -375,12 +375,12 @@ let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" :
|
|||||||
return Object.freeze({"n":"세벌식 3-90","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"세벌식 3-90","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
||||||
"l":"koKR",
|
"l":"koKR",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin// + 2*altgrin
|
let layer = 1*shiftin// + 2*altgrin
|
||||||
states.code = 1
|
states.code = 1
|
||||||
|
|
||||||
let s = states.keylayouts[headkey][layer]
|
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
|
||||||
let bufIndex = isJungseong(s) ? 1 : isJongseong(s) ? 2 : 0
|
let bufIndex = isJungseong(s) ? 1 : isJongseong(s) ? 2 : 0
|
||||||
|
|
||||||
if (isHangul(s)) {
|
if (isHangul(s)) {
|
||||||
|
|||||||
@@ -375,12 +375,12 @@ let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" :
|
|||||||
return Object.freeze({"n":"세벌식 공자판","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"세벌식 공자판","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
||||||
"l":"koKR",
|
"l":"koKR",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin// + 2*altgrin
|
let layer = 1*shiftin// + 2*altgrin
|
||||||
states.code = 1
|
states.code = 1
|
||||||
|
|
||||||
let s = states.keylayouts[headkey][layer]
|
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
|
||||||
let bufIndex = isJungseong(s) ? 1 : isJongseong(s) ? 2 : 0
|
let bufIndex = isJungseong(s) ? 1 : isJongseong(s) ? 2 : 0
|
||||||
|
|
||||||
if (isHangul(s)) {
|
if (isHangul(s)) {
|
||||||
|
|||||||
@@ -385,12 +385,12 @@ let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" :
|
|||||||
return Object.freeze({"n":"신세벌식 ’03","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"신세벌식 ’03","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
||||||
"l":"koKR",
|
"l":"koKR",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin// + 2*altgrin
|
let layer = 1*shiftin// + 2*altgrin
|
||||||
states.code = 1
|
states.code = 1
|
||||||
|
|
||||||
let s = states.keylayouts[headkey][layer]
|
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
|
||||||
let s2 = states.keylayouts[headkey][2]
|
let s2 = states.keylayouts[headkey][2]
|
||||||
let bufIndex = isJungseong(s) ? 1 : isJongseong(s) ? 2 : 0
|
let bufIndex = isJungseong(s) ? 1 : isJongseong(s) ? 2 : 0
|
||||||
|
|
||||||
|
|||||||
@@ -385,12 +385,12 @@ let bufDebugStringify = (buf) => [0,1,2].map(i => (buf[i] == undefined) ? "·" :
|
|||||||
return Object.freeze({"n":"신세벌식 P2","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"신세벌식 P2","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
||||||
"l":"koKR",
|
"l":"koKR",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin// + 2*altgrin
|
let layer = 1*shiftin// + 2*altgrin
|
||||||
states.code = 1
|
states.code = 1
|
||||||
|
|
||||||
let s = states.keylayouts[headkey][layer]
|
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
|
||||||
let s2 = states.keylayouts[headkey][2]
|
let s2 = states.keylayouts[headkey][2]
|
||||||
let bufIndex = isJungseong(s) ? 1 : isJongseong(s) ? 2 : 0
|
let bufIndex = isJungseong(s) ? 1 : isJongseong(s) ? 2 : 0
|
||||||
|
|
||||||
|
|||||||
@@ -375,11 +375,11 @@ let isDiacritics = (s) => s !== undefined && inRange(s.charCodeAt(0), 0x0300, 0x
|
|||||||
return Object.freeze({"n":"ЙЦУКЕН Многоязычна","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"ЙЦУКЕН Многоязычна","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"t":states.keylayouts,
|
"t":states.keylayouts,
|
||||||
"l":"ruRU",
|
"l":"ruRU",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin + 2*altgrin
|
let layer = 1*shiftin + 2*altgrin
|
||||||
|
|
||||||
let s = states.keylayouts[headkey][layer]
|
let s = (states.keylayouts[headkey][layer] || states.keylayouts[headkey][1*shiftin]) || states.keylayouts[headkey][0]
|
||||||
|
|
||||||
// typing seq for diacritics: diacritics THEN a character
|
// typing seq for diacritics: diacritics THEN a character
|
||||||
if (isDiacritics(s)) {
|
if (isDiacritics(s)) {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ let states = {"keylayouts":[[""],[undefined],
|
|||||||
[undefined],
|
[undefined],
|
||||||
[undefined],
|
[undefined],
|
||||||
["ф","Ф","ƒ","ƒ"],
|
["ф","Ф","ƒ","ƒ"],
|
||||||
["и","И"],
|
["и","И","и","И"],
|
||||||
["с","С","≠","≠"],
|
["с","С","≠","≠"],
|
||||||
["в","В","ћ","Ћ"],
|
["в","В","ћ","Ћ"],
|
||||||
["у","У","ќ","Ќ"],
|
["у","У","ќ","Ќ"],
|
||||||
@@ -69,10 +69,10 @@ let states = {"keylayouts":[[""],[undefined],
|
|||||||
["-","_","—","–"],
|
["-","_","—","–"],
|
||||||
["=","+","»","«"],
|
["=","+","»","«"],
|
||||||
["х","Х","“","“"],
|
["х","Х","“","“"],
|
||||||
["ъ","Ъ"],
|
["ъ","Ъ","ъ","Ъ"],
|
||||||
["ё","Ё"],
|
["ё","Ё","ё","Ё"],
|
||||||
["ж","Ж","…","…"],
|
["ж","Ж","…","…"],
|
||||||
["э",'Э'],
|
["э",'Э',"э",'Э'],
|
||||||
["/","?","„","„"],
|
["/","?","„","„"],
|
||||||
[undefined],
|
[undefined],
|
||||||
[undefined],
|
[undefined],
|
||||||
@@ -263,12 +263,12 @@ let isDiacritics = (s) => s !== undefined && inRange(s.charCodeAt(0), 0x0300, 0x
|
|||||||
return Object.freeze({"n":"ЙЦУКЕН (Рус. Apple)","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"ЙЦУКЕН (Рус. Apple)","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"t":states.keylayouts,
|
"t":states.keylayouts,
|
||||||
"l":"ruRU",
|
"l":"ruRU",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin + 2*altgrin
|
let layer = 1*shiftin + 2*altgrin
|
||||||
states.code = 1
|
states.code = 1
|
||||||
|
|
||||||
let s = states.keylayouts[headkey][layer]
|
let s = (states.keylayouts[headkey][layer] || states.keylayouts[headkey][1*shiftin]) || states.keylayouts[headkey][0]
|
||||||
|
|
||||||
if (isDiacritics(s)) {
|
if (isDiacritics(s)) {
|
||||||
return ['1', '']
|
return ['1', '']
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ let isDiacritics = (s) => s !== undefined && inRange(s.charCodeAt(0), 0x0300, 0x
|
|||||||
return Object.freeze({"n":"Рус. Фонетическая","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"Рус. Фонетическая","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"tf":states.layouttable,
|
"tf":states.layouttable,
|
||||||
"l":"ruRU",
|
"l":"ruRU",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin,lowlayerkey)=>{
|
"accept":(headkey,shiftin,altgrin,lowlayerkey)=>{
|
||||||
let layer = 1*shiftin// + 2*altgrin
|
let layer = 1*shiftin// + 2*altgrin
|
||||||
states.code = 1
|
states.code = 1
|
||||||
|
|||||||
290
assets/keylayout/ta_in_tamil99.ime
Normal file
290
assets/keylayout/ta_in_tamil99.ime
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
let states = {"keylayouts":[[""],[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
["0",")"],
|
||||||
|
["1","!"],
|
||||||
|
["2","@"],
|
||||||
|
["3","#"],
|
||||||
|
["4","$"],
|
||||||
|
["5","%"],
|
||||||
|
["6","^"],
|
||||||
|
["7","&"],
|
||||||
|
["8","*"],
|
||||||
|
["9","("],
|
||||||
|
["*"],
|
||||||
|
["#"],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
["\u0B85","\u0BF9"],
|
||||||
|
["\u0B99","\u0BF7"],
|
||||||
|
["\u0B92","\u0BF5","\u0BCA"],
|
||||||
|
["\u0B89","\u0BF8","\u0BC1"],
|
||||||
|
["\u0B8A","\u0B9C","\u0BC2"],
|
||||||
|
["\u0BCD","\u0B83"],
|
||||||
|
["\u0B8E","\u0B8E","\u0BC6"],
|
||||||
|
["\u0B95","\u0B95"],
|
||||||
|
["\u0BA9","\u0BA9"],
|
||||||
|
["\u0BAA","\u0BAA"],
|
||||||
|
["\u0BAE",'"'],
|
||||||
|
["\u0BA4",":"],
|
||||||
|
["\u0BB0","/"],
|
||||||
|
["\u0BB2","\u0BB2"],
|
||||||
|
["\u0B9F","["],
|
||||||
|
["\u0BA3","]"],
|
||||||
|
["\u0B86","\u0BB8","\u0BBE"],
|
||||||
|
["\u0B90","\u0BB9","\u0BC8"],
|
||||||
|
["\u0B87","\u0BFA","\u0BBF"],
|
||||||
|
["\u0B8F","\u0B95\u0BCD\u0BB7","\u0BC7"],
|
||||||
|
["\u0BB1","\u0BB1"],
|
||||||
|
["\u0BB5","\u0BF6"],
|
||||||
|
["\u0B88","\u0BB7","\u0BC0"],
|
||||||
|
["\u0B93","\u0BF4","\u0BCB"],
|
||||||
|
["\u0BB3","\u0BB8\u0BCD\u0BB0\u0BC0"],
|
||||||
|
["\u0B94","\u0BF3","\u0BCC"],
|
||||||
|
[",","<"],
|
||||||
|
[".",">"],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[" "],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
["\n"],
|
||||||
|
["\x08"],
|
||||||
|
["`","~"],
|
||||||
|
["-","_"],
|
||||||
|
["=","+"],
|
||||||
|
["\u0B9A","{"],
|
||||||
|
["\u0B9E","}"],
|
||||||
|
["\\","|"],
|
||||||
|
["\u0BA8",";"],
|
||||||
|
["\u0BAF","'"],
|
||||||
|
["\u0BB4","?"],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
["0"],
|
||||||
|
["1"],
|
||||||
|
["2"],
|
||||||
|
["3"],
|
||||||
|
["4"],
|
||||||
|
["5"],
|
||||||
|
["6"],
|
||||||
|
["7"],
|
||||||
|
["8"],
|
||||||
|
["9"],
|
||||||
|
["/"],
|
||||||
|
["*"],
|
||||||
|
["-"],
|
||||||
|
["+"],
|
||||||
|
["."],
|
||||||
|
["."],
|
||||||
|
["\n"],
|
||||||
|
["="],
|
||||||
|
["("],
|
||||||
|
[")"],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined],
|
||||||
|
[undefined]
|
||||||
|
],
|
||||||
|
"code":""} // the last character typed
|
||||||
|
let reset = () => {
|
||||||
|
states.code = ""
|
||||||
|
}
|
||||||
|
let inRange = (s,a,b) => (a <= s && s <= b)
|
||||||
|
let isConsonant = (s) => s !== undefined && (inRange(s, 0x0B95, 0x0BB9) || s == 0x0BD0 || inRange(s, 0x0BE6, 0x0BFA)) // determines the behaviour of the vowel key
|
||||||
|
return Object.freeze({"n":"தமிழ் 99","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
|
"t":states.keylayouts,
|
||||||
|
"l":"taIN",
|
||||||
|
// return: [delete count, composed output]
|
||||||
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
|
let layer = 1*shiftin
|
||||||
|
|
||||||
|
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
|
||||||
|
|
||||||
|
if (layer == 0 && states.code != "" && isConsonant(states.code.charCodeAt(states.code.length - 1))) {
|
||||||
|
s = states.keylayouts[headkey][2] || states.keylayouts[headkey][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
states.code = s
|
||||||
|
|
||||||
|
return ['0', s]
|
||||||
|
},
|
||||||
|
"backspace":()=>{
|
||||||
|
reset()
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
"end":()=>{
|
||||||
|
reset()
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
"reset":()=>{ reset() },
|
||||||
|
"composing":()=>(states.code!='')
|
||||||
|
})
|
||||||
@@ -269,12 +269,12 @@ let isDiacritics = (s) => s !== undefined && inRange(s.charCodeAt(0), 0x0300, 0x
|
|||||||
return Object.freeze({"n":"แป้นพิมพ์เกษมณี","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"แป้นพิมพ์เกษมณี","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"t":states.keylayouts,
|
"t":states.keylayouts,
|
||||||
"l":"thTH",
|
"l":"thTH",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin + 2*altgrin // use AltGr to type conventional numbers
|
let layer = 1*shiftin + 2*altgrin // use AltGr to type conventional numbers
|
||||||
states.code = 0
|
states.code = 0
|
||||||
|
|
||||||
let s = states.keylayouts[headkey][layer]
|
let s = (states.keylayouts[headkey][layer] || states.keylayouts[headkey][1*shiftin]) || states.keylayouts[headkey][0]
|
||||||
return ['0', s]
|
return ['0', s]
|
||||||
},
|
},
|
||||||
"backspace":()=>{
|
"backspace":()=>{
|
||||||
|
|||||||
@@ -269,12 +269,12 @@ let isDiacritics = (s) => s !== undefined && (inRange(s.charCodeAt(0), 0x0E31, 0
|
|||||||
return Object.freeze({"n":"แป้นพิมพ์ปัตตะโชติ","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
return Object.freeze({"n":"แป้นพิมพ์ปัตตะโชติ","v":"none","c":"CuriousTo\uA75Bvald","m":"rewrite",
|
||||||
"t":states.keylayouts,
|
"t":states.keylayouts,
|
||||||
"l":"thTH",
|
"l":"thTH",
|
||||||
// return: [displayed output, composed output]
|
// return: [delete count, composed output]
|
||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin + 2*altgrin // use AltGr to type conventional numbers
|
let layer = 1*shiftin + 2*altgrin // use AltGr to type conventional numbers
|
||||||
states.code = 0
|
states.code = 0
|
||||||
|
|
||||||
let s = states.keylayouts[headkey][layer]
|
let s = (states.keylayouts[headkey][layer] || states.keylayouts[headkey][1*shiftin]) || states.keylayouts[headkey][0]
|
||||||
return ['0', s]
|
return ['0', s]
|
||||||
},
|
},
|
||||||
"backspace":()=>{
|
"backspace":()=>{
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ return Object.freeze({"n":"五仓简体 Qwerty","v":"many","c":"CuriousTo\uA75Bv
|
|||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin// + 2*altgrin
|
let layer = 1*shiftin// + 2*altgrin
|
||||||
|
|
||||||
let cjkey = states.keylayouts[headkey][layer]
|
let cjkey = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
|
||||||
let cjkeyAsc = cjkey.codePointAt(0)
|
let cjkeyAsc = cjkey.codePointAt(0)
|
||||||
|
|
||||||
if (states.code == 1 && 48 <= cjkeyAsc && cjkeyAsc <= 57) {
|
if (states.code == 1 && 48 <= cjkeyAsc && cjkeyAsc <= 57) {
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ return Object.freeze({"n":"五倉正體 Qwerty","v":"many","c":"CuriousTo\uA75Bv
|
|||||||
"accept":(headkey,shiftin,altgrin)=>{
|
"accept":(headkey,shiftin,altgrin)=>{
|
||||||
let layer = 1*shiftin// + 2*altgrin
|
let layer = 1*shiftin// + 2*altgrin
|
||||||
|
|
||||||
let cjkey = states.keylayouts[headkey][layer]
|
let cjkey = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
|
||||||
let cjkeyAsc = cjkey.codePointAt(0)
|
let cjkeyAsc = cjkey.codePointAt(0)
|
||||||
|
|
||||||
if (states.code == 1 && 48 <= cjkeyAsc && cjkeyAsc <= 57) {
|
if (states.code == 1 && 48 <= cjkeyAsc && cjkeyAsc <= 57) {
|
||||||
|
|||||||
4
assets/locales/de/input.json
Normal file
4
assets/locales/de/input.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"INPUT_KEYBOARD_DEFAULT_LAYOUT": "en_intl_qwertz",
|
||||||
|
"INPUT_KEYBOARD_DEFAULT_IME": "none"
|
||||||
|
}
|
||||||
@@ -1,37 +1,41 @@
|
|||||||
{
|
{
|
||||||
"CONTEXT_CHARACTER": "Character",
|
|
||||||
"MENU_LABEL_COPYRIGHT": "Copyright",
|
|
||||||
"COPYRIGHT_ALL_RIGHTS_RESERVED": "All rights reserved",
|
|
||||||
"COPYRIGHT_GNU_GPL_3": "Distributed under GNU GPL 3",
|
|
||||||
"APP_WARNING_HEALTH_AND_SAFETY": "WARNING-HEALTH AND SAFETY",
|
"APP_WARNING_HEALTH_AND_SAFETY": "WARNING-HEALTH AND SAFETY",
|
||||||
"MENU_LABEL_PRESS_START_SYMBOL": "Press >",
|
"CONTEXT_CHARACTER": "Character",
|
||||||
"MENU_MODULES" : "Modules",
|
|
||||||
"MENU_CREDIT_GPL_DNT" : "GPL",
|
|
||||||
"MENU_LABEL_JVM_DNT" : "JVM",
|
|
||||||
"GAME_ACTION_MOVE_VERB" : "Move",
|
|
||||||
"GAME_ACTION_ZOOM" : "Zoom",
|
|
||||||
"MENU_LABEL_RESET" : "Reset",
|
|
||||||
"MENU_OPTION_STREAMERS_LAYOUT": "Chat Overlay",
|
|
||||||
"MENU_LABEL_RESTART_REQUIRED": "Restart Required",
|
|
||||||
"MENU_LABEL_KEYBOARD_LAYOUT": "Keyboard Layout",
|
|
||||||
"MENU_LABEL_IME": "IME",
|
|
||||||
"MENU_OPTIONS_DITHER": "Dithering",
|
|
||||||
"MENU_OPTIONS_BLUR": "Blur",
|
|
||||||
"MENU_OPTIONS_PARTICLES": "Particles",
|
|
||||||
"MENU_IO_IMPORT": "Import",
|
|
||||||
"MENU_LABEL_IME_TOGGLE": "Toggle IME",
|
|
||||||
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "Paste from Clipboard",
|
|
||||||
"MENU_OPTIONS_PERFORMANCE": "Performance",
|
|
||||||
"MENU_LABEL_DELETE": "Delete",
|
|
||||||
"MENU_OPTIONS_JVM_HEAP_MAX": "Max Heap Memory",
|
|
||||||
"MENU_OPTIONS_AUTOSAVE": "Autosave",
|
|
||||||
"CONTEXT_TIME_MINUTE_PLURAL": "Minutes",
|
"CONTEXT_TIME_MINUTE_PLURAL": "Minutes",
|
||||||
"CONTEXT_TIME_SECOND_PLURAL": "Seconds",
|
"CONTEXT_TIME_SECOND_PLURAL": "Seconds",
|
||||||
"MENU_LABEL_SYSTEM_INFO": "System Info",
|
"COPYRIGHT_ALL_RIGHTS_RESERVED": "All rights reserved",
|
||||||
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "Show notification for",
|
"COPYRIGHT_GNU_GPL_3": "Distributed under GNU GPL 3",
|
||||||
"MENU_LABEL_STREAMING": "Livestreaming",
|
"GAME_ACTION_MOVE_VERB" : "Move",
|
||||||
"MENU_LABEL_EXTRA_JVM_ARGUMENTS": "Extra Arguments",
|
"GAME_ACTION_ZOOM" : "Zoom",
|
||||||
"MENU_IO_MANUAL_SAVE": "Manual Save",
|
|
||||||
"MENU_IO_AUTOSAVE": "Autosave",
|
"MENU_IO_AUTOSAVE": "Autosave",
|
||||||
"MENU_OPTIONS_DEBUG_CONSOLE": "Debug Console"
|
"MENU_IO_IMPORT": "Import",
|
||||||
|
"MENU_IO_MANUAL_SAVE": "Manual Save",
|
||||||
|
"MENU_LABEL_COPYRIGHT": "Copyright",
|
||||||
|
"MENU_LABEL_DELETE": "Delete",
|
||||||
|
"MENU_LABEL_EXTRA_JVM_ARGUMENTS": "Extra Arguments",
|
||||||
|
"MENU_LABEL_IME": "IME",
|
||||||
|
"MENU_LABEL_IME_TOGGLE": "Toggle IME",
|
||||||
|
"MENU_LABEL_KEYBOARD_LAYOUT": "Keyboard Layout",
|
||||||
|
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "Paste from Clipboard",
|
||||||
|
"MENU_LABEL_PRESS_START_SYMBOL": "Press >",
|
||||||
|
"MENU_LABEL_RESET" : "Reset",
|
||||||
|
"MENU_LABEL_RESTART_REQUIRED": "Restart Required",
|
||||||
|
"MENU_LABEL_STREAMING": "Livestreaming",
|
||||||
|
"MENU_LABEL_SYSTEM_INFO": "System Info",
|
||||||
|
"MENU_MODULES" : "Modules",
|
||||||
|
"MENU_OPTIONS_ATLAS_TEXTURE_SIZE": "Atlas Texture Size",
|
||||||
|
"MENU_OPTIONS_AUTOSAVE": "Autosave",
|
||||||
|
"MENU_OPTIONS_BLUR": "Blur",
|
||||||
|
"MENU_OPTIONS_DEBUG_CONSOLE": "Debug Console",
|
||||||
|
"MENU_OPTIONS_DITHER": "Dithering",
|
||||||
|
"MENU_OPTIONS_JVM_HEAP_MAX": "Max Heap Memory",
|
||||||
|
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "Show notification for",
|
||||||
|
"MENU_OPTIONS_PARTICLES": "Particles",
|
||||||
|
"MENU_OPTIONS_PERFORMANCE": "Performance",
|
||||||
|
"MENU_OPTIONS_STREAMERS_LAYOUT": "Chat Overlay",
|
||||||
|
"MENU_OPTIONS_NONE" : "None",
|
||||||
|
|
||||||
|
"MENU_CREDIT_GPL_DNT" : "GPL",
|
||||||
|
"MENU_LABEL_JVM_DNT" : "JVM",
|
||||||
|
"MENU_OPTIONS_FILTERING_HQ2X_DNT" : "Hq2x"
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
{
|
{
|
||||||
"GAME_32BIT_WARNING1": "32비트 버전의 Java를 사용중인 것 같습니다.",
|
"GAME_32BIT_WARNING1": "It looks like you’re running a 32-Bit version of Java.",
|
||||||
"GAME_32BIT_WARNING2": "아래 링크에서 최신 64비트 Java를 내려받아 설치해주세요.",
|
"GAME_32BIT_WARNING2": "Please download and install the latest 64-Bit Java at:",
|
||||||
"GAME_32BIT_WARNING3": "https://www.java.com/ko/download/",
|
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
|
||||||
"GAME_APPLE_ROSETTA_WARNING1": "Apple Silicon이 탑재된 Mac을 사용 중이지만 x86 빌드의 게임을 실행 중입니다.",
|
"GAME_APPLE_ROSETTA_WARNING1": "It seems you are using a Mac with Apple Silicon but running the x86 build of the game.",
|
||||||
"GAME_APPLE_ROSETTA_WARNING2": "최적의 성능과 게임 경험을 위해 Apple Silicon용 빌드의 게임을 이용해 주십시오.",
|
"GAME_APPLE_ROSETTA_WARNING2": "Please use the native build for improved performance and gameplay experiences.",
|
||||||
"APP_NOMODULE_1": "현재 불러와진 모듈이 없습니다.",
|
"APP_NOMODULE_1": "No Module is currently loaded.",
|
||||||
"APP_NOMODULE_2": "다음의 파일에서 불러오기 순서를 설정하고 게임을 재시작하십시오.",
|
"APP_NOMODULE_2": "Please configure your Load Order and restart:",
|
||||||
"MENU_LABEL_KEYCONFIG_HELP1": "키캡을 클릭해 컨트롤을 배정하십시오",
|
"MENU_LABEL_KEYCONFIG_HELP1": "Click On the Keycap to Assign Actions",
|
||||||
"GAME_PREV_SAVE_WAS_LOADED1": "가장 최근에 저장된 게임이 손상되었습니다.",
|
"GAME_PREV_SAVE_WAS_LOADED1": "The most recently saved game was corrupted.",
|
||||||
"GAME_PREV_SAVE_WAS_LOADED2": "이전에 저장된 게임을 불러왔습니다.",
|
"GAME_PREV_SAVE_WAS_LOADED2": "The previously saved game was loaded.",
|
||||||
"GAME_MORE_RECENT_AUTOSAVE1": "자동 저장된 게임이 수동으로 저장한 게임보다 더 최신입니다.",
|
"GAME_MORE_RECENT_AUTOSAVE1": "The Autosave is more recent than the manual save.",
|
||||||
"GAME_MORE_RECENT_AUTOSAVE2": "불러올 게임을 선택해 주십시오.",
|
"GAME_MORE_RECENT_AUTOSAVE2": "Please select the saved game you wish to play:",
|
||||||
"MENU_LABEL_SAVE_WILL_BE_DELETED": "선택된 세이브가 삭제됩니다.",
|
"MENU_LABEL_SAVE_WILL_BE_DELETED": "The selected save file will be deleted.",
|
||||||
"MENU_LABEL_UNSAVED_PROGRESSES_WILL_BE_LOST": "저장하지 않은 변동사항을 잃게 됩니다."
|
"MENU_LABEL_UNSAVED_PROGRESS_WILL_BE_LOST": "Unsaved progress will be lost."
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
"GAME_ACTION_MOVE_VERB" : "हिलना",
|
"GAME_ACTION_MOVE_VERB" : "हिलना",
|
||||||
"GAME_ACTION_ZOOM" : "ज़ूम",
|
"GAME_ACTION_ZOOM" : "ज़ूम",
|
||||||
"MENU_LABEL_RESET" : "रीसेट",
|
"MENU_LABEL_RESET" : "रीसेट",
|
||||||
"MENU_OPTION_STREAMERS_LAYOUT": "Chat Overlay",
|
"MENU_OPTIONS_STREAMERS_LAYOUT": "Chat Overlay",
|
||||||
"MENU_LABEL_RESTART_REQUIRED": "पुनः शुरआत जरुरी है",
|
"MENU_LABEL_RESTART_REQUIRED": "पुनः शुरआत जरुरी है",
|
||||||
"MENU_LABEL_KEYBOARD_LAYOUT": "कीबोर्ड विन्यास",
|
"MENU_LABEL_KEYBOARD_LAYOUT": "कीबोर्ड विन्यास",
|
||||||
"MENU_LABEL_IME": "इनपुट विधि",
|
"MENU_LABEL_IME": "इनपुट विधि",
|
||||||
|
|||||||
@@ -1,37 +1,37 @@
|
|||||||
{
|
{
|
||||||
"CONTEXT_CHARACTER": "캐릭터",
|
|
||||||
"MENU_LABEL_COPYRIGHT": "저작권",
|
|
||||||
"COPYRIGHT_ALL_RIGHTS_RESERVED": "모든 권리 보유",
|
|
||||||
"COPYRIGHT_GNU_GPL_3": "GNU GPL 3에 따라 배포됨",
|
|
||||||
"APP_WARNING_HEALTH_AND_SAFETY": "경고—건강과 안전을 위하여",
|
"APP_WARNING_HEALTH_AND_SAFETY": "경고—건강과 안전을 위하여",
|
||||||
"MENU_LABEL_PRESS_START_SYMBOL": ">을 누르세요",
|
"CONTEXT_CHARACTER": "캐릭터",
|
||||||
"MENU_MODULES" : "모듈",
|
|
||||||
|
|
||||||
|
|
||||||
"GAME_ACTION_MOVE_VERB" : "이동하기",
|
|
||||||
"GAME_ACTION_ZOOM" : "확대·축소",
|
|
||||||
"MENU_LABEL_RESET" : "재설정",
|
|
||||||
"MENU_OPTION_STREAMERS_LAYOUT": "채팅창 오버레이",
|
|
||||||
"MENU_LABEL_RESTART_REQUIRED": "재시작 필요",
|
|
||||||
"MENU_LABEL_KEYBOARD_LAYOUT": "자판 배열",
|
|
||||||
"MENU_LABEL_IME": "입력기",
|
|
||||||
"MENU_OPTIONS_DITHER": "디더링",
|
|
||||||
"MENU_OPTIONS_BLUR": "흐림",
|
|
||||||
"MENU_OPTIONS_PARTICLES": "입자 수",
|
|
||||||
"MENU_IO_IMPORT": "가져오기",
|
|
||||||
"MENU_LABEL_IME_TOGGLE": "입력기 켜고 끄기",
|
|
||||||
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "복사한 텍스트 붙여넣기",
|
|
||||||
"MENU_OPTIONS_PERFORMANCE": "성능",
|
|
||||||
"MENU_LABEL_DELETE": "삭제",
|
|
||||||
"MENU_OPTIONS_JVM_HEAP_MAX": "최대 힙 메모리",
|
|
||||||
"MENU_OPTIONS_AUTOSAVE": "자동 저장",
|
|
||||||
"CONTEXT_TIME_MINUTE_PLURAL": "분",
|
"CONTEXT_TIME_MINUTE_PLURAL": "분",
|
||||||
"CONTEXT_TIME_SECOND_PLURAL": "초",
|
"CONTEXT_TIME_SECOND_PLURAL": "초",
|
||||||
"MENU_LABEL_SYSTEM_INFO": "시스템 정보",
|
"COPYRIGHT_ALL_RIGHTS_RESERVED": "모든 권리 보유",
|
||||||
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "알림 표시 시간",
|
"COPYRIGHT_GNU_GPL_3": "GNU GPL 3에 따라 배포됨",
|
||||||
"MENU_LABEL_STREAMING": "실시간 방송",
|
"GAME_ACTION_MOVE_VERB" : "이동하기",
|
||||||
"MENU_LABEL_EXTRA_JVM_ARGUMENTS": "추가 명령 인수",
|
"GAME_ACTION_ZOOM" : "확대·축소",
|
||||||
"MENU_IO_MANUAL_SAVE": "수동 저장",
|
|
||||||
"MENU_IO_AUTOSAVE": "자동 저장",
|
"MENU_IO_AUTOSAVE": "자동 저장",
|
||||||
"MENU_OPTIONS_DEBUG_CONSOLE": "디버그 콘솔"
|
"MENU_IO_IMPORT": "가져오기",
|
||||||
|
"MENU_IO_MANUAL_SAVE": "수동 저장",
|
||||||
|
"MENU_LABEL_COPYRIGHT": "저작권",
|
||||||
|
"MENU_LABEL_DELETE": "삭제",
|
||||||
|
"MENU_LABEL_EXTRA_JVM_ARGUMENTS": "추가 명령 인수",
|
||||||
|
"MENU_LABEL_IME": "입력기",
|
||||||
|
"MENU_LABEL_IME_TOGGLE": "입력기 켜고 끄기",
|
||||||
|
"MENU_LABEL_KEYBOARD_LAYOUT": "자판 배열",
|
||||||
|
"MENU_LABEL_PASTE_FROM_CLIPBOARD": "복사한 텍스트 붙여넣기",
|
||||||
|
"MENU_LABEL_PRESS_START_SYMBOL": ">을 누르세요",
|
||||||
|
"MENU_LABEL_RESET" : "재설정",
|
||||||
|
"MENU_LABEL_RESTART_REQUIRED": "재시작 필요",
|
||||||
|
"MENU_LABEL_STREAMING": "실시간 방송",
|
||||||
|
"MENU_LABEL_SYSTEM_INFO": "시스템 정보",
|
||||||
|
"MENU_MODULES" : "모듈",
|
||||||
|
"MENU_OPTIONS_ATLAS_TEXTURE_SIZE": "아틀라스 텍스처 크기",
|
||||||
|
"MENU_OPTIONS_AUTOSAVE": "자동 저장",
|
||||||
|
"MENU_OPTIONS_BLUR": "흐림",
|
||||||
|
"MENU_OPTIONS_DEBUG_CONSOLE": "디버그 콘솔",
|
||||||
|
"MENU_OPTIONS_DITHER": "디더링",
|
||||||
|
"MENU_OPTIONS_JVM_HEAP_MAX": "최대 힙 메모리",
|
||||||
|
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "알림 표시 시간",
|
||||||
|
"MENU_OPTIONS_PARTICLES": "입자 수",
|
||||||
|
"MENU_OPTIONS_PERFORMANCE": "성능",
|
||||||
|
"MENU_OPTIONS_STREAMERS_LAYOUT": "채팅창 오버레이",
|
||||||
|
"MENU_OPTIONS_NONE" : "없음"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,5 +11,6 @@
|
|||||||
"GAME_PREV_SAVE_WAS_LOADED2": "이전에 저장된 게임을 불러왔습니다.",
|
"GAME_PREV_SAVE_WAS_LOADED2": "이전에 저장된 게임을 불러왔습니다.",
|
||||||
"GAME_MORE_RECENT_AUTOSAVE1": "자동 저장된 게임이 수동으로 저장한 게임보다 더 최신입니다.",
|
"GAME_MORE_RECENT_AUTOSAVE1": "자동 저장된 게임이 수동으로 저장한 게임보다 더 최신입니다.",
|
||||||
"GAME_MORE_RECENT_AUTOSAVE2": "불러올 게임을 선택해 주십시오.",
|
"GAME_MORE_RECENT_AUTOSAVE2": "불러올 게임을 선택해 주십시오.",
|
||||||
"MENU_LABEL_SAVE_WILL_BE_DELETED": "선택된 세이브가 삭제됩니다."
|
"MENU_LABEL_SAVE_WILL_BE_DELETED": "선택된 세이브가 삭제됩니다.",
|
||||||
|
"MENU_LABEL_UNSAVED_PROGRESS_WILL_BE_LOST": "저장하지 않은 진행 상황을 잃게 됩니다."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
"GAME_32BIT_WARNING1": "看起来您正在运行32位版本的Java。",
|
"GAME_32BIT_WARNING1": "看起来您正在运行32位版本的Java。",
|
||||||
"GAME_32BIT_WARNING2": "请下载并安装最新的64位Java :",
|
"GAME_32BIT_WARNING2": "请下载并安装最新的64位Java :",
|
||||||
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
|
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
|
||||||
"MENU_OPTION_STREAMERS_LAYOUT": "聊天叠加",
|
"MENU_OPTIONS_STREAMERS_LAYOUT": "聊天叠加",
|
||||||
"MENU_LABEL_RESTART_REQUIRED": "需要重新启动",
|
"MENU_LABEL_RESTART_REQUIRED": "需要重新启动",
|
||||||
"MENU_LABEL_KEYBOARD_LAYOUT": "键盘布局",
|
"MENU_LABEL_KEYBOARD_LAYOUT": "键盘布局",
|
||||||
"MENU_LABEL_IME": "输入法",
|
"MENU_LABEL_IME": "输入法",
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"GAME_32BIT_WARNING1": "看起來您正在運行32位版本的Java。",
|
"GAME_32BIT_WARNING1": "看起來您正在運行32位版本的Java。",
|
||||||
"GAME_32BIT_WARNING2": "請下載並安裝最新的64位Java :",
|
"GAME_32BIT_WARNING2": "請下載並安裝最新的64位Java :",
|
||||||
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
|
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
|
||||||
"MENU_OPTION_STREAMERS_LAYOUT": "聊天疊加",
|
"MENU_OPTIONS_STREAMERS_LAYOUT": "聊天疊加",
|
||||||
"MENU_LABEL_RESTART_REQUIRED": "需要重新啟動",
|
"MENU_LABEL_RESTART_REQUIRED": "需要重新啟動",
|
||||||
"MENU_LABEL_KEYBOARD_LAYOUT": "鍵盤配置",
|
"MENU_LABEL_KEYBOARD_LAYOUT": "鍵盤配置",
|
||||||
"MENU_LABEL_IME": "輸入法",
|
"MENU_LABEL_IME": "輸入法",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"id";"drop";"spawn";"name";"shdr";"shdg";"shdb";"shduv";"str";"dsty";"mate";"solid";"wall";"grav";"dlfn";"fv";"fr";"lumr";"lumg";"lumb";"lumuv";"colour";"vscs";"refl";"tags"
|
"id";"drop";"spawn";"name";"shdr";"shdg";"shdb";"shduv";"str";"dsty";"mate";"solid";"wall";"grav";"dlfn";"fv";"fr";"lumr";"lumg";"lumb";"lumuv";"colour";"vscs";"refl";"tags"
|
||||||
"0";"0";"0";"BLOCK_AIR";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";""
|
"0";"0";"0";"BLOCK_AIR";"0.0312";"0.0312";"0.0312";"0.0312";"1";"1";"NULL";"0";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"INCONSEQUENTIAL"
|
||||||
"16";"17";"17";"BLOCK_STONE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK,NATURAL"
|
"16";"17";"17";"BLOCK_STONE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK,NATURAL"
|
||||||
"17";"17";"17";"BLOCK_STONE_QUARRIED";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK"
|
"17";"17";"17";"BLOCK_STONE_QUARRIED";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ROCK"
|
||||||
"18";"18";"18";"BLOCK_STONE_TILE_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.18";"STONE"
|
"18";"18";"18";"BLOCK_STONE_TILE_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"ROCK";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.18";"STONE"
|
||||||
@@ -23,12 +23,12 @@
|
|||||||
"65";"65";"65";"BLOCK_TRUNK_EBONY";"0.0312";"0.0312";"0.0312";"0.0312";"19";"1200";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,NATURAL"
|
"65";"65";"65";"BLOCK_TRUNK_EBONY";"0.0312";"0.0312";"0.0312";"0.0312";"19";"1200";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,NATURAL"
|
||||||
"66";"66";"66";"BLOCK_TRUNK_BIRCH";"0.0312";"0.0312";"0.0312";"0.0312";"15";"670";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,NATURAL"
|
"66";"66";"66";"BLOCK_TRUNK_BIRCH";"0.0312";"0.0312";"0.0312";"0.0312";"15";"670";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,NATURAL"
|
||||||
"67";"67";"67";"BLOCK_TRUNK_BLOODROSE";"0.0312";"0.0312";"0.0312";"0.0312";"17";"900";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,NATURAL"
|
"67";"67";"67";"BLOCK_TRUNK_BLOODROSE";"0.0312";"0.0312";"0.0312";"0.0312";"17";"900";"WOOD";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"TREE,NATURAL"
|
||||||
"80";"80";"80";"BLOCK_SAND";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL"
|
"80";"80";"80";"BLOCK_SAND";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
|
||||||
"81";"81";"81";"BLOCK_SAND_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL"
|
"81";"81";"81";"BLOCK_SAND_WHITE";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
|
||||||
"82";"82";"82";"BLOCK_SAND_RED";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL"
|
"82";"82";"82";"BLOCK_SAND_RED";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
|
||||||
"83";"83";"83";"BLOCK_SAND_DESERT";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL"
|
"83";"83";"83";"BLOCK_SAND_DESERT";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
|
||||||
"84";"84";"84";"BLOCK_SAND_BLACK";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL"
|
"84";"84";"84";"BLOCK_SAND_BLACK";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
|
||||||
"85";"85";"85";"BLOCK_SAND_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL"
|
"85";"85";"85";"BLOCK_SAND_GREEN";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"SAND";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.06";"SAND,NATURAL,WARM"
|
||||||
"96";"96";"96";"BLOCK_GRAVEL";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"GRVL";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRAVEL,NATURAL"
|
"96";"96";"96";"BLOCK_GRAVEL";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"GRVL";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRAVEL,NATURAL"
|
||||||
"97";"97";"97";"BLOCK_GRAVEL_GREY";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"GRVL";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRAVEL,NATURAL"
|
"97";"97";"97";"BLOCK_GRAVEL_GREY";"0.1252";"0.1252";"0.1252";"0.1252";"24";"2400";"GRVL";"1";"0";"0";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GRAVEL,NATURAL"
|
||||||
"112";"112";"112";"BLOCK_ORE_MALACHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
"112";"112";"112";"BLOCK_ORE_MALACHITE";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OORE";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ORE,NATURAL"
|
||||||
@@ -44,10 +44,10 @@
|
|||||||
"132";"132";"132";"BLOCK_GEM_DIAMOND";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
"132";"132";"132";"BLOCK_GEM_DIAMOND";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||||
"133";"133";"133";"BLOCK_GEM_AMETHYST";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
"133";"133";"133";"BLOCK_GEM_AMETHYST";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||||
"134";"134";"134";"BLOCK_GEM_QUARTZ";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
"134";"134";"134";"BLOCK_GEM_QUARTZ";"0.1252";"0.1252";"0.1252";"0.1252";"48";"2400";"OGEM";"1";"0";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GEM,NATURAL"
|
||||||
"144";"144";"144";"BLOCK_SNOW";"0.1252";"0.1252";"0.1252";"0.1252";"24";"500";"SNOW";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SNOW,NATURAL"
|
"144";"144";"144";"BLOCK_SNOW";"0.1252";"0.1252";"0.1252";"0.1252";"24";"500";"SNOW";"1";"1";"N/A";"0";"4";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"SNOW,NATURAL,COLD"
|
||||||
"145";"N/A";"N/A";"BLOCK_ICE_FRAGILE";"0.0508";"0.0508";"0.0508";"0.0508";"5";"930";"ICEI";"1";"0";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ICE,NATURAL,FRAGIEL"
|
"145";"N/A";"N/A";"BLOCK_ICE_FRAGILE";"0.0508";"0.0508";"0.0508";"0.0508";"5";"930";"ICEI";"1";"0";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ICE,NATURAL,FRAGILE,COLD"
|
||||||
"146";"146";"146";"BLOCK_ICE_NATURAL";"0.1016";"0.1016";"0.1016";"0.1016";"35";"930";"ICEI";"1";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ICE,NATURAL"
|
"146";"146";"146";"BLOCK_ICE_NATURAL";"0.1016";"0.1016";"0.1016";"0.1016";"35";"930";"ICEI";"1";"1";"N/A";"0";"0";"4";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"ICE,NATURAL,COLD"
|
||||||
"147";"147";"147";"BLOCK_ICE_CLEAR_MAGICAL";"0.1252";"0.1252";"0.1252";"0.1252";"48";"3720";"ICEX";"1";"1";"N/A";"0";"0";"4";"0.0744";"0.1252";"0.2268";"0.0000";"N/A";"N/A";"0.0";"ICE"
|
"147";"147";"147";"BLOCK_ICE_CLEAR_MAGICAL";"0.1252";"0.1252";"0.1252";"0.1252";"48";"3720";"ICEX";"1";"1";"N/A";"0";"0";"4";"0.0744";"0.1252";"0.2268";"0.0000";"N/A";"N/A";"0.0";"ICE,COLD"
|
||||||
"148";"148";"148";"BLOCK_GLASS_CRUDE";"0.0876";"0.0424";"0.0876";"0.1252";"5";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GLASS"
|
"148";"148";"148";"BLOCK_GLASS_CRUDE";"0.0876";"0.0424";"0.0876";"0.1252";"5";"2500";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GLASS"
|
||||||
"149";"149";"149";"BLOCK_GLASS_CLEAN";"0.0424";"0.0424";"0.0424";"0.0636";"5";"2203";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GLASS"
|
"149";"149";"149";"BLOCK_GLASS_CLEAN";"0.0424";"0.0424";"0.0424";"0.0636";"5";"2203";"GLAS";"1";"1";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"GLASS"
|
||||||
"160";"160";"160";"BLOCK_PLATFORM_STONE";"0.0312";"0.0312";"0.0312";"0.0312";"5";"2400";"ROCK";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"PLATFORM"
|
"160";"160";"160";"BLOCK_PLATFORM_STONE";"0.0312";"0.0312";"0.0312";"0.0312";"5";"2400";"ROCK";"0";"0";"N/A";"0";"0";"16";"0.0000";"0.0000";"0.0000";"0.0000";"N/A";"N/A";"0.0";"PLATFORM"
|
||||||
@@ -188,6 +188,7 @@
|
|||||||
## Some tags are reserved for internal use, which are:
|
## Some tags are reserved for internal use, which are:
|
||||||
## - INTERNAL: denotes that the tile is internal-use. Will not be rendered unless debug window is on.
|
## - INTERNAL: denotes that the tile is internal-use. Will not be rendered unless debug window is on.
|
||||||
## - DORENDER: this internal tile must go through the standard-issue tile drawing routine.
|
## - DORENDER: this internal tile must go through the standard-issue tile drawing routine.
|
||||||
|
## - INCONSEQUENTIAL: denotes that this tile can be overwritten without dropping it. Usually used with flower tiles.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
## References ##
|
## References ##
|
||||||
|
|||||||
|
Can't render this file because it contains an unexpected character in line 179 and column 37.
|
@@ -22,6 +22,8 @@ Seed
|
|||||||
SetAV
|
SetAV
|
||||||
SetBulletin
|
SetBulletin
|
||||||
SetScale
|
SetScale
|
||||||
|
SetSol
|
||||||
|
SetTurb
|
||||||
SetTime
|
SetTime
|
||||||
SetTimeDelta
|
SetTimeDelta
|
||||||
SpawnPhysTestBall
|
SpawnPhysTestBall
|
||||||
|
|||||||
|
@@ -8,6 +8,7 @@ id;classname
|
|||||||
8;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalEmitter
|
8;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalEmitter
|
||||||
9;net.torvald.terrarum.modulebasegame.gameitems.WireCutterAll
|
9;net.torvald.terrarum.modulebasegame.gameitems.WireCutterAll
|
||||||
10;net.torvald.terrarum.modulebasegame.gameitems.ItemTypewriter
|
10;net.torvald.terrarum.modulebasegame.gameitems.ItemTypewriter
|
||||||
|
11;net.torvald.terrarum.modulebasegame.gameitems.ItemWallCalendar
|
||||||
|
|
||||||
256;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak
|
256;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak
|
||||||
257;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorEbony
|
257;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorEbony
|
||||||
|
|||||||
|
34
assets/mods/basegame/locales/en/calendar.json
Normal file
34
assets/mods/basegame/locales/en/calendar.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"MENU_CALENDAR_CALENDAR": "Calendar",
|
||||||
|
"MENU_CALENDAR_EVENTS": "Events",
|
||||||
|
"MENU_CALENDAR_ADD_NEW_EVENT": "Add New Event",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_SPRING": "Spring",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_SUMMER": "Summer",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_AUTUMN": "Autumn",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_WINTER": "Winter",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_SPRI": "Spri",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_SUMM": "Summ",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_AUTM": "Autm",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_WINT": "Wint",
|
||||||
|
"CONTEXT_CALENDAR_DATE_FORMAT_Y": "Year {0}",
|
||||||
|
"CONTEXT_CALENDAR_DATE_FORMAT_YMD": "Year {0} {1} {2}",
|
||||||
|
"CONTEXT_CALENDAR_DATE_FORMAT_YMD_DDD": "Year {0} {1} {2} {3}",
|
||||||
|
|
||||||
|
"CONTEXT_CALENDAR_DAY_MONDAG_DNT": "Mondag",
|
||||||
|
"CONTEXT_CALENDAR_DAY_TYSDAG_DNT": "Tysdag",
|
||||||
|
"CONTEXT_CALENDAR_DAY_MIDTVEKE_DNT": "Midtveke",
|
||||||
|
"CONTEXT_CALENDAR_DAY_TORSDAG_DNT": "Torsdag",
|
||||||
|
"CONTEXT_CALENDAR_DAY_FREDAG_DNT": "Fredag",
|
||||||
|
"CONTEXT_CALENDAR_DAY_LAURDAG_DNT": "Laurdag",
|
||||||
|
"CONTEXT_CALENDAR_DAY_SUNDAG_DNT": "Sundag",
|
||||||
|
"CONTEXT_CALENDAR_DAY_VERDDAG_DNT": "Verddag",
|
||||||
|
"CONTEXT_CALENDAR_DAY_MON_DNT": "Mon",
|
||||||
|
"CONTEXT_CALENDAR_DAY_TYS_DNT": "Tys",
|
||||||
|
"CONTEXT_CALENDAR_DAY_MID_DNT": "Mid",
|
||||||
|
"CONTEXT_CALENDAR_DAY_TOR_DNT": "Tor",
|
||||||
|
"CONTEXT_CALENDAR_DAY_FRE_DNT": "Fre",
|
||||||
|
"CONTEXT_CALENDAR_DAY_LAU_DNT": "Lau",
|
||||||
|
"CONTEXT_CALENDAR_DAY_SUN_DNT": "Sun",
|
||||||
|
"CONTEXT_CALENDAR_DAY_VER_DNT": "Ver",
|
||||||
|
"CONTEXT_CALENDAR_DATE_FORMAT_YMD_SHORT_DNT": "ɣ{0}-{1}-{2}"
|
||||||
|
}
|
||||||
@@ -1,23 +1,24 @@
|
|||||||
{
|
{
|
||||||
|
"CONTEXT_GENERATOR_SEED": "Seed",
|
||||||
|
"CONTEXT_ITEM_MAP": "Map",
|
||||||
|
"CONTEXT_ITEM_TOOL_PLURAL": "Tools",
|
||||||
|
"CONTEXT_PLACE_COORDINATE": "Coordinate",
|
||||||
|
"CONTEXT_WORLD_COUNT": "Worlds: ",
|
||||||
"CONTEXT_WORLD_NEW": "New World",
|
"CONTEXT_WORLD_NEW": "New World",
|
||||||
"MENU_LABEL_DELETE_WORLD": "Delete World",
|
"MENU_LABEL_DELETE_WORLD": "Delete World",
|
||||||
"CONTEXT_WORLD_COUNT": "Worlds: ",
|
|
||||||
"GAME_INVENTORY_INGREDIENTS": "Ingredients",
|
|
||||||
"GAME_INVENTORY_POTIONS": "Potions",
|
|
||||||
"GAME_INVENTORY_BLOCKS": "Blocks",
|
|
||||||
"GAME_INVENTORY_WALLS": "Walls",
|
|
||||||
"CONTEXT_ITEM_TOOL_PLURAL": "Tools",
|
|
||||||
"GAME_INVENTORY_FAVORITES": "Favorites",
|
|
||||||
"GAME_INVENTORY_REGISTER": "Register",
|
|
||||||
"CONTEXT_ITEM_MAP": "Map",
|
|
||||||
"MENU_LABEL_MENU": "Menu",
|
"MENU_LABEL_MENU": "Menu",
|
||||||
"CONTEXT_GENERATOR_SEED": "Seed",
|
"MENU_LABEL_PREV_SAVES": "Previous Saves",
|
||||||
|
"MENU_LABEL_RENAME": "Rename",
|
||||||
|
"GAME_ACTION_CRAFT": "Craft",
|
||||||
"GAME_ACTION_GRAPPLE": "Grapple",
|
"GAME_ACTION_GRAPPLE": "Grapple",
|
||||||
"GAME_ACTION_QUICKSEL": "Quick Select",
|
"GAME_ACTION_QUICKSEL": "Quick Select",
|
||||||
"GAME_ACTION_CRAFT": "Craft",
|
|
||||||
"GAME_CRAFTING": "Crafting",
|
|
||||||
"GAME_CRAFTABLE_ITEMS": "Craftable Items",
|
|
||||||
"MENU_LABEL_RENAME": "Rename",
|
|
||||||
"GAME_ACTION_TELEPORT": "Teleport",
|
"GAME_ACTION_TELEPORT": "Teleport",
|
||||||
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "This is a world currently playing."
|
"GAME_CRAFTABLE_ITEMS": "Craftable Items",
|
||||||
|
"GAME_CRAFTING": "Crafting",
|
||||||
|
"GAME_INVENTORY_BLOCKS": "Blocks",
|
||||||
|
"GAME_INVENTORY_FAVORITES": "Favorites",
|
||||||
|
"GAME_INVENTORY_INGREDIENTS": "Ingredients",
|
||||||
|
"GAME_INVENTORY_POTIONS": "Potions",
|
||||||
|
"GAME_INVENTORY_REGISTER": "Register",
|
||||||
|
"GAME_INVENTORY_WALLS": "Walls"
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,20 @@
|
|||||||
{
|
{
|
||||||
|
"BLOCK_STONE_DEEP": "Deepstone",
|
||||||
|
"BLOCK_SCAFFOLDING_NORMAL": "Scaffolding",
|
||||||
|
"BLOCK_STONE_MARBLE": "Marble",
|
||||||
|
|
||||||
|
"ITEM_CALENDAR": "Calendar",
|
||||||
|
"ITEM_LOGIC_SIGNAL_EMITTER": "Logic Signal Emitter",
|
||||||
|
"ITEM_STORAGE_CHEST": "Storage Chest",
|
||||||
|
"ITEM_TIKI_TORCH": "Tiki Torch",
|
||||||
|
"ITEM_TYPEWRITER": "Typewriter",
|
||||||
|
"ITEM_WIRE": "Wire",
|
||||||
|
"ITEM_WIRE_CUTTER": "Wire Cutter",
|
||||||
|
|
||||||
"ACTORBLOCK_ALLOW_MOVE_DOWN": "Urist Arôlcustith",
|
"ACTORBLOCK_ALLOW_MOVE_DOWN": "Urist Arôlcustith",
|
||||||
"ACTORBLOCK_FULL_COLLISION": "Urist Berdanrifot",
|
"ACTORBLOCK_FULL_COLLISION": "Urist Berdanrifot",
|
||||||
"ACTORBLOCK_NO_COLLISION": "Urist Zafal",
|
"ACTORBLOCK_NO_COLLISION": "Urist Zafal",
|
||||||
"ACTORBLOCK_NO_PASS_RIGHT": "Urist McPassLeft",
|
"ACTORBLOCK_NO_PASS_RIGHT": "Urist McPassLeft",
|
||||||
"ACTORBLOCK_NO_PASS_LEFT": "Urist McPassRight",
|
"ACTORBLOCK_NO_PASS_LEFT": "Urist McPassRight",
|
||||||
"ACTORBLOCK_TILING_PLACEHOLDER": "Urist Berdanurdim",
|
"ACTORBLOCK_TILING_PLACEHOLDER": "Urist Berdanurdim"
|
||||||
|
|
||||||
"BLOCK_STONE_DEEP": "Deepstone",
|
|
||||||
"BLOCK_SCAFFOLDING_NORMAL": "Scaffolding",
|
|
||||||
"BLOCK_STONE_MARBLE": "Marble",
|
|
||||||
|
|
||||||
"ITEM_STORAGE_CHEST": "Storage Chest",
|
|
||||||
"ITEM_WIRE": "Wire",
|
|
||||||
"ITEM_WIRE_CUTTER": "Wire Cutter",
|
|
||||||
"ITEM_LOGIC_SIGNAL_EMITTER": "Logic Signal Emitter",
|
|
||||||
"ITEM_TIKI_TORCH": "Tiki Torch"
|
|
||||||
}
|
}
|
||||||
3
assets/mods/basegame/locales/en/sentences.json
Normal file
3
assets/mods/basegame/locales/en/sentences.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "This is a world currently playing."
|
||||||
|
}
|
||||||
16
assets/mods/basegame/locales/koKR/calendar.json
Normal file
16
assets/mods/basegame/locales/koKR/calendar.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"MENU_CALENDAR_CALENDAR": "달력",
|
||||||
|
"MENU_CALENDAR_EVENTS": "일정",
|
||||||
|
"MENU_CALENDAR_ADD_NEW_EVENT": "새 일정 추가",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_SPRING": "봄",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_SUMMER": "여름",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_AUTUMN": "가을",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_WINTER": "겨울",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_SPRI": "봄",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_SUMM": "여름",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_AUTM": "가을",
|
||||||
|
"CONTEXT_CALENDAR_SEASON_WINT": "겨울",
|
||||||
|
"CONTEXT_CALENDAR_DATE_FORMAT_Y": "{0}년",
|
||||||
|
"CONTEXT_CALENDAR_DATE_FORMAT_YMD": "{0}년 {1} {2}일",
|
||||||
|
"CONTEXT_CALENDAR_DATE_FORMAT_YMD_DDD": "{0}년 {1} {2}일 {3}"
|
||||||
|
}
|
||||||
@@ -1,24 +1,25 @@
|
|||||||
{
|
{
|
||||||
|
"CONTEXT_GENERATOR_SEED": "시드",
|
||||||
|
"CONTEXT_ITEM_MAP": "지도",
|
||||||
|
"CONTEXT_ITEM_TOOL_PLURAL": "도구",
|
||||||
|
"CONTEXT_PLACE_COORDINATE": "좌표",
|
||||||
|
"CONTEXT_WORLD_COUNT": "새계: ",
|
||||||
"CONTEXT_WORLD_NEW": "새 세계",
|
"CONTEXT_WORLD_NEW": "새 세계",
|
||||||
"MENU_LABEL_DELETE_WORLD": "새계 삭제",
|
"MENU_LABEL_DELETE_WORLD": "새계 삭제",
|
||||||
"CONTEXT_WORLD_COUNT": "새계: ",
|
|
||||||
"MENU_MONITOR_CALI_TITLE": "모니터 확인",
|
|
||||||
"GAME_INVENTORY_INGREDIENTS": "재료",
|
|
||||||
"GAME_INVENTORY_POTIONS": "물약",
|
|
||||||
"GAME_INVENTORY_BLOCKS": "블록",
|
|
||||||
"GAME_INVENTORY_WALLS": "벽지",
|
|
||||||
"CONTEXT_ITEM_TOOL_PLURAL": "도구",
|
|
||||||
"GAME_INVENTORY_FAVORITES": "즐겨찾기",
|
|
||||||
"GAME_INVENTORY_REGISTER": "등록하기",
|
|
||||||
"MENU_LABEL_MENU": "메뉴",
|
"MENU_LABEL_MENU": "메뉴",
|
||||||
"CONTEXT_ITEM_MAP": "지도",
|
"MENU_LABEL_PREV_SAVES": "이전 세이브",
|
||||||
"CONTEXT_GENERATOR_SEED": "시드",
|
"MENU_LABEL_RENAME": "이름 바꾸기",
|
||||||
|
"MENU_MONITOR_CALI_TITLE": "모니터 확인",
|
||||||
|
"GAME_ACTION_CRAFT": "제작하기",
|
||||||
"GAME_ACTION_GRAPPLE": "매달리기",
|
"GAME_ACTION_GRAPPLE": "매달리기",
|
||||||
"GAME_ACTION_QUICKSEL": "빠른 선택",
|
"GAME_ACTION_QUICKSEL": "빠른 선택",
|
||||||
"GAME_ACTION_CRAFT": "제작하기",
|
|
||||||
"GAME_CRAFTING": "제작",
|
|
||||||
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템",
|
|
||||||
"MENU_LABEL_RENAME": "이름 바꾸기",
|
|
||||||
"GAME_ACTION_TELEPORT": "텔레포트하기",
|
"GAME_ACTION_TELEPORT": "텔레포트하기",
|
||||||
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "현재 플레이 중인 월드입니다."
|
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템",
|
||||||
|
"GAME_CRAFTING": "제작",
|
||||||
|
"GAME_INVENTORY_BLOCKS": "블록",
|
||||||
|
"GAME_INVENTORY_FAVORITES": "즐겨찾기",
|
||||||
|
"GAME_INVENTORY_INGREDIENTS": "재료",
|
||||||
|
"GAME_INVENTORY_POTIONS": "물약",
|
||||||
|
"GAME_INVENTORY_REGISTER": "등록하기",
|
||||||
|
"GAME_INVENTORY_WALLS": "벽지"
|
||||||
}
|
}
|
||||||
@@ -3,9 +3,11 @@
|
|||||||
"BLOCK_SCAFFOLDING_NORMAL": "발판",
|
"BLOCK_SCAFFOLDING_NORMAL": "발판",
|
||||||
"BLOCK_STONE_MARBLE": "대리석",
|
"BLOCK_STONE_MARBLE": "대리석",
|
||||||
|
|
||||||
"ITEM_STORAGE_CHEST": "보관상자",
|
"ITEM_CALENDAR": "달력",
|
||||||
"ITEM_WIRE": "전선",
|
|
||||||
"ITEM_WIRE_CUTTER": "전선 절단기",
|
|
||||||
"ITEM_LOGIC_SIGNAL_EMITTER": "신호발생기",
|
"ITEM_LOGIC_SIGNAL_EMITTER": "신호발생기",
|
||||||
"ITEM_TIKI_TORCH": "티키 토치"
|
"ITEM_STORAGE_CHEST": "보관상자",
|
||||||
|
"ITEM_TIKI_TORCH": "티키 토치",
|
||||||
|
"ITEM_TYPEWRITER": "타자기",
|
||||||
|
"ITEM_WIRE": "전선",
|
||||||
|
"ITEM_WIRE_CUTTER": "전선 절단기"
|
||||||
}
|
}
|
||||||
3
assets/mods/basegame/locales/koKR/sentences.json
Normal file
3
assets/mods/basegame/locales/koKR/sentences.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "현재 플레이 중인 월드입니다."
|
||||||
|
}
|
||||||
BIN
assets/mods/basegame/sprites/fixtures/calendar.tga
LFS
Normal file
BIN
assets/mods/basegame/sprites/fixtures/calendar.tga
LFS
Normal file
Binary file not shown.
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"skyboxGradColourMap": "generic_skybox.tga",
|
"skyboxGradColourMap": "generic_skybox.tga",
|
||||||
|
"daylightClut": "clut_daylight.tga",
|
||||||
"classification": "generic",
|
"classification": "generic",
|
||||||
"extraImages": [
|
"extraImages": [
|
||||||
|
|
||||||
|
|||||||
BIN
assets/mods/basegame/weathers/clut_daylight.tga
LFS
Normal file
BIN
assets/mods/basegame/weathers/clut_daylight.tga
LFS
Normal file
Binary file not shown.
@@ -25,6 +25,7 @@ chmod +x $DESTDIR/AppRun
|
|||||||
# Copy over a Java runtime
|
# Copy over a Java runtime
|
||||||
mkdir $DESTDIR/out
|
mkdir $DESTDIR/out
|
||||||
cp -r "../out/$RUNTIME" $DESTDIR/out/
|
cp -r "../out/$RUNTIME" $DESTDIR/out/
|
||||||
|
mv $DESTDIR/out/$RUNTIME/bin/java $DESTDIR/out/$RUNTIME/bin/Terrarum
|
||||||
|
|
||||||
# Copy over all the assets and a jarfile
|
# Copy over all the assets and a jarfile
|
||||||
cp -r "../assets_release" $DESTDIR/
|
cp -r "../assets_release" $DESTDIR/
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ chmod +x $DESTDIR/AppRun
|
|||||||
# Copy over a Java runtime
|
# Copy over a Java runtime
|
||||||
mkdir $DESTDIR/out
|
mkdir $DESTDIR/out
|
||||||
cp -r "../out/$RUNTIME" $DESTDIR/out/
|
cp -r "../out/$RUNTIME" $DESTDIR/out/
|
||||||
|
mv $DESTDIR/out/$RUNTIME/bin/java $DESTDIR/out/$RUNTIME/bin/Terrarum
|
||||||
|
|
||||||
# Copy over all the assets and a jarfile
|
# Copy over all the assets and a jarfile
|
||||||
cp -r "../assets_release" $DESTDIR/
|
cp -r "../assets_release" $DESTDIR/
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ if (( $EUID == 0 )); then echo "The build process is not meant to be run with ro
|
|||||||
|
|
||||||
cd "${0%/*}"
|
cd "${0%/*}"
|
||||||
SRCFILES="terrarummac_arm"
|
SRCFILES="terrarummac_arm"
|
||||||
DESTDIR="out/TerrarumMac.arm.app"
|
APPDIR="./TerrarumMac.arm.app"
|
||||||
|
DESTDIR="out/$APPDIR"
|
||||||
RUNTIME="runtime-osx-arm"
|
RUNTIME="runtime-osx-arm"
|
||||||
|
|
||||||
if [ ! -d "../assets_release" ]; then
|
if [ ! -d "../assets_release" ]; then
|
||||||
@@ -27,10 +28,15 @@ chmod +x $DESTDIR/Contents/MacOS/Terrarum.sh
|
|||||||
# Copy over a Java runtime
|
# Copy over a Java runtime
|
||||||
mkdir $DESTDIR/Contents/MacOS/out
|
mkdir $DESTDIR/Contents/MacOS/out
|
||||||
cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/out/
|
cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/out/
|
||||||
|
mv $DESTDIR/Contents/MacOS/out/$RUNTIME/bin/java $DESTDIR/Contents/MacOS/out/$RUNTIME/bin/Terrarum
|
||||||
|
|
||||||
# Copy over all the assets and a jarfile
|
# Copy over all the assets and a jarfile
|
||||||
cp -r "../assets_release" $DESTDIR/Contents/MacOS/
|
cp -r "../assets_release" $DESTDIR/Contents/MacOS/
|
||||||
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
|
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
|
||||||
cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/
|
cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/
|
||||||
|
|
||||||
|
cd "out"
|
||||||
|
rm $APPDIR.zip
|
||||||
|
7z a -tzip $APPDIR.zip $APPDIR
|
||||||
|
|
||||||
echo "Build successful: $DESTDIR"
|
echo "Build successful: $DESTDIR"
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ if (( $EUID == 0 )); then echo "The build process is not meant to be run with ro
|
|||||||
|
|
||||||
cd "${0%/*}"
|
cd "${0%/*}"
|
||||||
SRCFILES="terrarummac_x86"
|
SRCFILES="terrarummac_x86"
|
||||||
DESTDIR="out/TerrarumMac.x86.app"
|
APPDIR="./TerrarumMac.x86.app"
|
||||||
|
DESTDIR="out/$APPDIR"
|
||||||
RUNTIME="runtime-osx-x86"
|
RUNTIME="runtime-osx-x86"
|
||||||
|
|
||||||
if [ ! -d "../assets_release" ]; then
|
if [ ! -d "../assets_release" ]; then
|
||||||
@@ -27,10 +28,15 @@ chmod +x $DESTDIR/Contents/MacOS/Terrarum.sh
|
|||||||
# Copy over a Java runtime
|
# Copy over a Java runtime
|
||||||
mkdir $DESTDIR/Contents/MacOS/out
|
mkdir $DESTDIR/Contents/MacOS/out
|
||||||
cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/out/
|
cp -r "../out/$RUNTIME" $DESTDIR/Contents/MacOS/out/
|
||||||
|
mv $DESTDIR/Contents/MacOS/out/$RUNTIME/bin/java $DESTDIR/Contents/MacOS/out/$RUNTIME/bin/Terrarum
|
||||||
|
|
||||||
# Copy over all the assets and a jarfile
|
# Copy over all the assets and a jarfile
|
||||||
cp -r "../assets_release" $DESTDIR/Contents/MacOS/
|
cp -r "../assets_release" $DESTDIR/Contents/MacOS/
|
||||||
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
|
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
|
||||||
cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/
|
cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/
|
||||||
|
|
||||||
|
cd "out"
|
||||||
|
rm $APPDIR.zip
|
||||||
|
7z a -tzip $APPDIR.zip $APPDIR
|
||||||
|
|
||||||
echo "Build successful: $DESTDIR"
|
echo "Build successful: $DESTDIR"
|
||||||
|
|||||||
@@ -21,11 +21,13 @@ then
|
|||||||
echo 'Mingw32 not found; please install mingw64-cross-gcc (or similar) to your system' >&2; exit 1;
|
echo 'Mingw32 not found; please install mingw64-cross-gcc (or similar) to your system' >&2; exit 1;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
x86_64-w64-mingw32-gcc -o $DESTDIR/Terrarum.exe $SRCFILES/Terrarum.c || { echo 'Building EXE failed' >&2; exit 1; }
|
x86_64-w64-mingw32-gcc -Os -s -o $DESTDIR/Terrarum.exe $SRCFILES/Terrarum.c || { echo 'Building EXE failed' >&2; exit 1; }
|
||||||
|
# TODO add icon to the exe (use x86_64-w64-mingw32-windres?)
|
||||||
|
|
||||||
# Copy over a Java runtime
|
# Copy over a Java runtime
|
||||||
mkdir $DESTDIR/out
|
mkdir $DESTDIR/out
|
||||||
cp -r "../out/$RUNTIME" $DESTDIR/out/
|
cp -r "../out/$RUNTIME" $DESTDIR/out/
|
||||||
|
mv $DESTDIR/out/$RUNTIME/bin/java.exe $DESTDIR/out/$RUNTIME/bin/Terrarum.exe
|
||||||
|
|
||||||
# Copy over all the assets and a jarfile
|
# Copy over all the assets and a jarfile
|
||||||
cp -r "../assets_release" $DESTDIR/
|
cp -r "../assets_release" $DESTDIR/
|
||||||
|
|||||||
25
buildapp/make_assets_release.sh
Executable file
25
buildapp/make_assets_release.sh
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
if (( $EUID == 0 )); then echo "The build process is not meant to be run with root privilege, exiting now." >&2; exit 1; fi
|
||||||
|
|
||||||
|
cd "${0%/*}"
|
||||||
|
DESTDIR="../assets_release"
|
||||||
|
|
||||||
|
rm -r $DESTDIR
|
||||||
|
cp -r "../assets" $DESTDIR
|
||||||
|
|
||||||
|
rm $DESTDIR/loopey.wav
|
||||||
|
rm $DESTDIR/ktGrepExample.kts
|
||||||
|
rm $DESTDIR/batchtest.txt
|
||||||
|
rm $DESTDIR/test_texture.tga
|
||||||
|
rm $DESTDIR/worldbacktest.tga
|
||||||
|
rm -r $DESTDIR/books
|
||||||
|
rm $DESTDIR/clut/skybox.tga
|
||||||
|
rm $DESTDIR/graphics/*.bat
|
||||||
|
rm $DESTDIR/keylayout/*.not_ime
|
||||||
|
rm $DESTDIR/mods/basegame/blocks/*.gz
|
||||||
|
rm $DESTDIR/mods/basegame/blocks/*.txt
|
||||||
|
rm -r $DESTDIR/mods/basegame/sounds
|
||||||
|
rm -r $DESTDIR/mods/dwarventech
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cd "${0%/*}"
|
cd "${0%/*}"
|
||||||
./out/runtime-linux-arm/bin/java -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./out/TerrarumBuild.jar
|
./out/runtime-linux-arm/bin/Terrarum -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./out/TerrarumBuild.jar
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cd "${0%/*}"
|
cd "${0%/*}"
|
||||||
./out/runtime-linux-x86/bin/java -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./out/TerrarumBuild.jar
|
./out/runtime-linux-x86/bin/Terrarum -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd -jar ./out/TerrarumBuild.jar
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cd "${0%/*}"
|
cd "${0%/*}"
|
||||||
./out/runtime-osx-arm/bin/java -jar ./out/TerrarumBuild.jar
|
./out/runtime-osx-arm/bin/Terrarum -jar ./out/TerrarumBuild.jar
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
cd "${0%/*}"
|
cd "${0%/*}"
|
||||||
./out/runtime-osx-x86/bin/java -jar ./out/TerrarumBuild.jar
|
./out/runtime-osx-x86/bin/Terrarum -jar ./out/TerrarumBuild.jar
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
return system(".\\out\\runtime-windows-x86\\bin\\java -jar .\\out\\TerrarumBuild.jar");
|
return system(".\\out\\runtime-windows-x86\\bin\\Terrarum.exe -jar .\\out\\TerrarumBuild.jar");
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package com.badlogic.gdx.graphics.glutils;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Application;
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
|
import com.badlogic.gdx.graphics.GL30;
|
||||||
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
|
import com.badlogic.gdx.utils.GdxRuntimeException;
|
||||||
|
import net.torvald.terrarum.App;
|
||||||
|
|
||||||
|
// typealias Float16FrameBuffer = FloatFrameBuffer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2023-08-16.
|
||||||
|
*/
|
||||||
|
public class Float16FrameBuffer extends FrameBuffer {
|
||||||
|
|
||||||
|
Float16FrameBuffer () {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a GLFrameBuffer from the specifications provided by bufferBuilder
|
||||||
|
*
|
||||||
|
* @param bufferBuilder **/
|
||||||
|
protected Float16FrameBuffer (GLFrameBufferBuilder<? extends GLFrameBuffer<Texture>> bufferBuilder) {
|
||||||
|
super(bufferBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a new FrameBuffer with a float backing texture, having the given dimensions and potentially a depth buffer
|
||||||
|
* attached.
|
||||||
|
*
|
||||||
|
* @param width the width of the framebuffer in pixels
|
||||||
|
* @param height the height of the framebuffer in pixels
|
||||||
|
* @param hasDepth whether to attach a depth buffer
|
||||||
|
* @throws GdxRuntimeException in case the FrameBuffer could not be created */
|
||||||
|
public Float16FrameBuffer (int width, int height, boolean hasDepth) {
|
||||||
|
if (App.isAppleM) { // disable float framebuffer for Apple M chips
|
||||||
|
FrameBufferBuilder bufferBuilder = new FrameBufferBuilder(width, height);
|
||||||
|
bufferBuilder.addColorTextureAttachment(GL20.GL_RGBA, GL20.GL_RGBA, GL20.GL_UNSIGNED_SHORT); // but 16bpp int works perfectly?!
|
||||||
|
if (hasDepth) bufferBuilder.addBasicDepthRenderBuffer();
|
||||||
|
this.bufferBuilder = bufferBuilder;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FloatFrameBufferBuilder bufferBuilder = new FloatFrameBufferBuilder(width, height);
|
||||||
|
bufferBuilder.addFloatAttachment(GL30.GL_RGBA16F, GL30.GL_RGBA, GL30.GL_FLOAT, false); // FIXME sporadic black screen on GL_RGBA16F? or maybe it was Plasma bugging out?
|
||||||
|
if (hasDepth) bufferBuilder.addBasicDepthRenderBuffer();
|
||||||
|
this.bufferBuilder = bufferBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Texture createTexture (FrameBufferTextureAttachmentSpec attachmentSpec) {
|
||||||
|
if (App.isAppleM) {
|
||||||
|
GLOnlyTextureData data = new GLOnlyTextureData(bufferBuilder.width, bufferBuilder.height, 0, attachmentSpec.internalFormat,
|
||||||
|
attachmentSpec.format, attachmentSpec.type);
|
||||||
|
Texture result = new Texture(data);
|
||||||
|
result.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
|
||||||
|
result.setWrap(Texture.TextureWrap.ClampToEdge, Texture.TextureWrap.ClampToEdge);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FloatTextureData data = new FloatTextureData(bufferBuilder.width, bufferBuilder.height, attachmentSpec.internalFormat,
|
||||||
|
attachmentSpec.format, attachmentSpec.type, attachmentSpec.isGpuOnly);
|
||||||
|
Texture result = new Texture(data);
|
||||||
|
result.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
|
||||||
|
result.setWrap(Texture.TextureWrap.ClampToEdge, Texture.TextureWrap.ClampToEdge);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -166,6 +166,19 @@ final public class FastMath {
|
|||||||
return ((1f - scale) * startValue) + (scale * endValue);
|
return ((1f - scale) * startValue) + (scale * endValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static double interpolateLinear(double scale, double startValue, double endValue) {
|
||||||
|
if (startValue == endValue) {
|
||||||
|
return startValue;
|
||||||
|
}
|
||||||
|
if (scale <= 0.0) {
|
||||||
|
return startValue;
|
||||||
|
}
|
||||||
|
if (scale >= 1.0) {
|
||||||
|
return endValue;
|
||||||
|
}
|
||||||
|
return ((1.0 - scale) * startValue) + (scale * endValue);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Linear interpolation from startValue to endValue by the given percent.
|
* Linear interpolation from startValue to endValue by the given percent.
|
||||||
* Basically: ((1 - percent) * startValue) + (percent * endValue)
|
* Basically: ((1 - percent) * startValue) + (percent * endValue)
|
||||||
@@ -800,28 +813,6 @@ final public class FastMath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Take a float input and clamp it between min and max.
|
|
||||||
*
|
|
||||||
* @param input
|
|
||||||
* @param min
|
|
||||||
* @param max
|
|
||||||
* @return clamped input
|
|
||||||
*/
|
|
||||||
public static float clamp(float input, float min, float max) {
|
|
||||||
return (input < min) ? min : (input > max) ? max : input;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clamps the given float to be between 0 and 1.
|
|
||||||
*
|
|
||||||
* @param input
|
|
||||||
* @return input clamped between 0 and 1.
|
|
||||||
*/
|
|
||||||
public static float saturate(float input) {
|
|
||||||
return clamp(input, 0f, 1f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a single precision (32 bit) floating point value
|
* Converts a single precision (32 bit) floating point value
|
||||||
* into half precision (16 bit).
|
* into half precision (16 bit).
|
||||||
@@ -876,31 +867,6 @@ final public class FastMath {
|
|||||||
| ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00)
|
| ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00)
|
||||||
| ((f >> 13) & 0x03ff));
|
| ((f >> 13) & 0x03ff));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static float min(float... f) {
|
|
||||||
float min = f[0];
|
|
||||||
for (int i = 1; i < f.length; i++) min = (f[i] < min) ? f[i] : min;
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float max(float... f) {
|
|
||||||
float max = f[0];
|
|
||||||
for (int i = 1; i < f.length; i++) max = (f[i] > max) ? f[i] : max;
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int min(int... f) {
|
|
||||||
int min = f[0];
|
|
||||||
for (int i = 1; i < f.length; i++) min = (f[i] < min) ? f[i] : min;
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int max(int... f) {
|
|
||||||
int max = f[0];
|
|
||||||
for (int i = 1; i < f.length; i++) max = (f[i] > max) ? f[i] : max;
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getGCD(int a, int b) {
|
public static int getGCD(int a, int b) {
|
||||||
while (a != b) {
|
while (a != b) {
|
||||||
if (a > b) a = a-b;
|
if (a > b) a = a-b;
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ fun Color.toXYZ(): CIEXYZ = RGB(this).toXYZ()
|
|||||||
}
|
}
|
||||||
val step = value.clampOne() * 255f // 0.0 .. 255.0
|
val step = value.clampOne() * 255f // 0.0 .. 255.0
|
||||||
val intStep = step.toInt() // 0 .. 255
|
val intStep = step.toInt() // 0 .. 255
|
||||||
val NeXTSTEP = minOf(intStep + 1, 255) // 1 .. 255
|
val NeXTSTEP = min(intStep + 1, 255) // 1 .. 255
|
||||||
|
|
||||||
out[i] = interpolateLinear(step - intStep, rgbLinLUT[intStep], rgbLinLUT[NeXTSTEP])
|
out[i] = interpolateLinear(step - intStep, rgbLinLUT[intStep], rgbLinLUT[NeXTSTEP])
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ fun RGB.linearise(): RGB {
|
|||||||
}
|
}
|
||||||
val step = value.clampOne() * 255f // 0.0 .. 255.0
|
val step = value.clampOne() * 255f // 0.0 .. 255.0
|
||||||
val intStep = step.toInt() // 0 .. 255
|
val intStep = step.toInt() // 0 .. 255
|
||||||
val NeXTSTEP = minOf(intStep + 1, 255) // 1 .. 255
|
val NeXTSTEP = min(intStep + 1, 255) // 1 .. 255
|
||||||
|
|
||||||
out[i] = interpolateLinear(step - intStep, rgbUnLinLUT[intStep], rgbUnLinLUT[NeXTSTEP])
|
out[i] = interpolateLinear(step - intStep, rgbUnLinLUT[intStep], rgbUnLinLUT[NeXTSTEP])
|
||||||
}
|
}
|
||||||
@@ -192,6 +192,16 @@ fun CIEXYZ.toColorRaw(): Color {
|
|||||||
return Color(rgb.r, rgb.g, rgb.b, rgb.alpha)
|
return Color(rgb.r, rgb.g, rgb.b, rgb.alpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun CIEXYZ.toYXY(): CIEYXY {
|
||||||
|
val dot = this.X + this.Y + this.Z
|
||||||
|
return CIEYXY(
|
||||||
|
this.Y,
|
||||||
|
this.X / dot,
|
||||||
|
this.Y / dot,
|
||||||
|
this.alpha
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun CIEYXY.toXYZ(): CIEXYZ {
|
fun CIEYXY.toXYZ(): CIEXYZ {
|
||||||
return CIEXYZ(x * yy / y, yy, (1f - x - y) * yy / y)
|
return CIEXYZ(x * yy / y, yy, (1f - x - y) * yy / y)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package net.torvald.colourutil
|
|||||||
|
|
||||||
import com.jme3.math.FastMath
|
import com.jme3.math.FastMath
|
||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
|
import kotlin.math.max
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OBSOLETE; use CIELchUtil for natural-looking colour
|
* OBSOLETE; use CIELchUtil for natural-looking colour
|
||||||
@@ -75,8 +77,8 @@ object HSVUtil {
|
|||||||
val g = color.g
|
val g = color.g
|
||||||
val b = color.b
|
val b = color.b
|
||||||
|
|
||||||
val rgbMin = FastMath.min(r, g, b)
|
val rgbMin = min(min(r, g), b)
|
||||||
val rgbMax = FastMath.max(r, g, b)
|
val rgbMax = max(max(r, g), b)
|
||||||
|
|
||||||
var h: Float
|
var h: Float
|
||||||
val s: Float
|
val s: Float
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ public class HUSLColorConverter {
|
|||||||
float x = intersectLineLine(line, new float[]{-1 / m1, 0});
|
float x = intersectLineLine(line, new float[]{-1 / m1, 0});
|
||||||
float length = distanceFromPole(new float[]{x, b1 + x * m1});
|
float length = distanceFromPole(new float[]{x, b1 + x * m1});
|
||||||
|
|
||||||
min = FastMath.min(min, length);
|
min = Math.min(min, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return min;
|
return min;
|
||||||
@@ -125,7 +125,7 @@ public class HUSLColorConverter {
|
|||||||
for (float[] bound : bounds) {
|
for (float[] bound : bounds) {
|
||||||
Length length = lengthOfRayUntilIntersect(hrad, bound);
|
Length length = lengthOfRayUntilIntersect(hrad, bound);
|
||||||
if (length.greaterEqualZero) {
|
if (length.greaterEqualZero) {
|
||||||
min = FastMath.min(min, length.length);
|
min = Math.min(min, length.length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,13 @@ class Cvec {
|
|||||||
this.a = color.a
|
this.a = color.a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constructor(rgb: Color, alpha: Float) {
|
||||||
|
this.r = rgb.r
|
||||||
|
this.g = rgb.g
|
||||||
|
this.b = rgb.b
|
||||||
|
this.a = alpha
|
||||||
|
}
|
||||||
|
|
||||||
/** Constructor, sets the components of the color
|
/** Constructor, sets the components of the color
|
||||||
*
|
*
|
||||||
* @param r the red component
|
* @param r the red component
|
||||||
|
|||||||
@@ -104,10 +104,10 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) {
|
|||||||
// operators
|
// operators
|
||||||
fun max(x: Int, y: Int, other: Cvec) {
|
fun max(x: Int, y: Int, other: Cvec) {
|
||||||
val a = toAddr(x, y)
|
val a = toAddr(x, y)
|
||||||
array.setFloat(a + 0, maxOf(array.getFloat(a + 0), other.r))
|
array.setFloat(a + 0, kotlin.math.max(array.getFloat(a + 0), other.r))
|
||||||
array.setFloat(a + 1, maxOf(array.getFloat(a + 1), other.g))
|
array.setFloat(a + 1, kotlin.math.max(array.getFloat(a + 1), other.g))
|
||||||
array.setFloat(a + 2, maxOf(array.getFloat(a + 2), other.b))
|
array.setFloat(a + 2, kotlin.math.max(array.getFloat(a + 2), other.b))
|
||||||
array.setFloat(a + 3, maxOf(array.getFloat(a + 3), other.a))
|
array.setFloat(a + 3, kotlin.math.max(array.getFloat(a + 3), other.a))
|
||||||
}
|
}
|
||||||
fun mul(x: Int, y: Int, scalar: Float) {
|
fun mul(x: Int, y: Int, scalar: Float) {
|
||||||
val a = toAddr(x, y)
|
val a = toAddr(x, y)
|
||||||
@@ -202,10 +202,10 @@ internal class TestCvecArr(val width: Int, val height: Int) {
|
|||||||
|
|
||||||
// operators
|
// operators
|
||||||
inline fun max(x: Int, y: Int, other: Cvec) {
|
inline fun max(x: Int, y: Int, other: Cvec) {
|
||||||
setR(x, y, maxOf(getR(x, y), other.r))
|
setR(x, y, kotlin.math.max(getR(x, y), other.r))
|
||||||
setG(x, y, maxOf(getG(x, y), other.g))
|
setG(x, y, kotlin.math.max(getG(x, y), other.g))
|
||||||
setB(x, y, maxOf(getB(x, y), other.b))
|
setB(x, y, kotlin.math.max(getB(x, y), other.b))
|
||||||
setA(x, y, maxOf(getA(x, y), other.a))
|
setA(x, y, kotlin.math.max(getA(x, y), other.a))
|
||||||
}
|
}
|
||||||
inline fun mul(x: Int, y: Int, scalar: Float) {
|
inline fun mul(x: Int, y: Int, scalar: Float) {
|
||||||
setR(x, y, getR(x, y) * scalar)
|
setR(x, y, getR(x, y) * scalar)
|
||||||
|
|||||||
@@ -12,24 +12,36 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
|||||||
import net.torvald.unicode.EMDASH
|
import net.torvald.unicode.EMDASH
|
||||||
import net.torvald.colourutil.*
|
import net.torvald.colourutil.*
|
||||||
import net.torvald.parametricsky.datasets.DatasetCIEXYZ
|
import net.torvald.parametricsky.datasets.DatasetCIEXYZ
|
||||||
import net.torvald.parametricsky.datasets.DatasetRGB
|
import net.torvald.terrarum.abs
|
||||||
import net.torvald.parametricsky.datasets.DatasetSpectral
|
import net.torvald.terrarum.clut.Skybox
|
||||||
|
import net.torvald.terrarum.clut.Skybox.coerceInSmoothly
|
||||||
|
import net.torvald.terrarum.clut.Skybox.mapCircle
|
||||||
import net.torvald.terrarum.inUse
|
import net.torvald.terrarum.inUse
|
||||||
import net.torvald.terrarum.modulebasegame.worldgenerator.HALF_PI
|
import net.torvald.terrarum.modulebasegame.worldgenerator.HALF_PI
|
||||||
import net.torvald.terrarum.modulebasegame.worldgenerator.TWO_PI
|
import java.awt.BorderLayout
|
||||||
import java.awt.Dimension
|
import java.awt.Dimension
|
||||||
|
import java.lang.Math.pow
|
||||||
import javax.swing.*
|
import javax.swing.*
|
||||||
import kotlin.math.PI
|
import kotlin.math.*
|
||||||
import kotlin.math.pow
|
|
||||||
|
|
||||||
|
|
||||||
const val WIDTH = 1200
|
val INITIAL_TURBIDITY = 4.0
|
||||||
const val HEIGHT = 600
|
val INITIAL_ALBEDO = 0.1
|
||||||
|
val INITIAL_ELEV = 0.0
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2018-08-01.
|
* Created by minjaesong on 2018-08-01.
|
||||||
*/
|
*/
|
||||||
class Application : Game() {
|
class Application(val WIDTH: Int, val HEIGHT: Int) : Game() {
|
||||||
|
|
||||||
|
private val HW = WIDTH / 2
|
||||||
|
private val HH = HEIGHT / 2
|
||||||
|
|
||||||
|
private val wf = WIDTH.toFloat()
|
||||||
|
private val hf = HEIGHT.toFloat()
|
||||||
|
private val hwf = HW.toFloat()
|
||||||
|
// private val hhf = HH.toFloat()
|
||||||
|
|
||||||
/* Variables:
|
/* Variables:
|
||||||
* 1. Canvas Y (theta)
|
* 1. Canvas Y (theta)
|
||||||
@@ -53,12 +65,12 @@ class Application : Game() {
|
|||||||
private lateinit var oneScreen: Pixmap
|
private lateinit var oneScreen: Pixmap
|
||||||
private lateinit var batch: SpriteBatch
|
private lateinit var batch: SpriteBatch
|
||||||
|
|
||||||
private lateinit var testTex: Texture
|
var turbidity = INITIAL_TURBIDITY
|
||||||
|
var albedo = INITIAL_ALBEDO
|
||||||
|
var elevation = Math.toRadians(INITIAL_ELEV)
|
||||||
|
|
||||||
var turbidity = 5.0
|
var solarBearing = Math.toRadians(90.0)
|
||||||
var albedo = 0.1
|
var cameraHeading = Math.toRadians(90.0)
|
||||||
var elevation = 0.0
|
|
||||||
var scalefactor = 1f
|
|
||||||
|
|
||||||
override fun getScreen(): Screen {
|
override fun getScreen(): Screen {
|
||||||
return super.getScreen()
|
return super.getScreen()
|
||||||
@@ -68,20 +80,38 @@ class Application : Game() {
|
|||||||
super.setScreen(screen)
|
super.setScreen(screen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var model = ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevation.abs())
|
||||||
|
|
||||||
|
fun regenerateModel() {
|
||||||
|
model = ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevation.abs())
|
||||||
|
}
|
||||||
|
|
||||||
override fun render() {
|
override fun render() {
|
||||||
Gdx.graphics.setTitle("Daylight Model $EMDASH F: ${Gdx.graphics.framesPerSecond}")
|
Gdx.graphics.setTitle("Daylight Model $EMDASH F: ${Gdx.graphics.framesPerSecond}")
|
||||||
|
|
||||||
if (turbidity <= 0) throw IllegalStateException()
|
if (turbidity <= 0) throw IllegalStateException()
|
||||||
|
|
||||||
// we need to use different modelstate to accomodate different albedo for each spectral band but oh well...
|
// we need to use different model-state to accommodate different albedo for each spectral band but oh well...
|
||||||
genTexLoop(ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevation))
|
genTexLoop(model, elevation)
|
||||||
|
// println("$elevation\t${ymaxDisp.text}\t${ymaxDisp2.text}")
|
||||||
|
|
||||||
|
|
||||||
|
/*for (elev in -75..75) {
|
||||||
|
val elevation = Math.toRadians(elev.toDouble())
|
||||||
|
val model = ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevation.abs())
|
||||||
|
genTexLoop(model, elevation)
|
||||||
|
println("$elev\t${ymaxDisp.text}\t${ymaxDisp2.text}")
|
||||||
|
}*/
|
||||||
|
|
||||||
|
|
||||||
val tex = Texture(oneScreen)
|
val tex = Texture(oneScreen)
|
||||||
tex.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
|
tex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
|
||||||
|
|
||||||
batch.inUse {
|
batch.inUse {
|
||||||
batch.draw(tex, 0f, 0f, WIDTH.toFloat(), HEIGHT.toFloat())
|
// batch.draw(tex, hwf, 0f, hwf, hf)
|
||||||
|
// batch.draw(tex, hwf, 0f, -hwf, hf)
|
||||||
|
|
||||||
|
batch.draw(tex, 0f, 0f, wf, hf)
|
||||||
}
|
}
|
||||||
|
|
||||||
tex.dispose()
|
tex.dispose()
|
||||||
@@ -103,14 +133,48 @@ class Application : Game() {
|
|||||||
oneScreen.dispose()
|
oneScreen.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
val outTexWidth = 256
|
val outTexWidth = 1
|
||||||
val outTexHeight = 256
|
val outTexHeight = 128
|
||||||
|
|
||||||
|
private fun Float.scaleFun() =
|
||||||
|
(1f - 1f / 2f.pow(this/6f)) * 0.97f
|
||||||
|
|
||||||
|
private fun CIEXYZ.scaleToFit(elevation: Double): CIEXYZ {
|
||||||
|
return if (elevation >= 0) {
|
||||||
|
CIEXYZ(
|
||||||
|
this.X.scaleFun(),
|
||||||
|
this.Y.scaleFun(),
|
||||||
|
this.Z.scaleFun(),
|
||||||
|
this.alpha
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// maths model: https://www.desmos.com/calculator/cwi7iyzygg
|
||||||
|
|
||||||
|
val x = -Math.toDegrees(elevation).toFloat()
|
||||||
|
// val elevation2 = -Math.toDegrees(elevation) / 28.5
|
||||||
|
val p = 3.5f
|
||||||
|
val q = 7.5f
|
||||||
|
val s = -0.2f
|
||||||
|
val f = (1f - (1f - 1f / 1.8f.pow(x)) * 0.97f).toFloat()
|
||||||
|
// val g = (1.0 - (elevation2.pow(E) / E.pow(elevation2))*0.8).toFloat()
|
||||||
|
val h = ((x / q).pow(p) + 1f).pow(s)
|
||||||
|
CIEXYZ(
|
||||||
|
this.X.scaleFun() * f * h,
|
||||||
|
this.Y.scaleFun() * f * h,
|
||||||
|
this.Z.scaleFun() * f * h,
|
||||||
|
this.alpha
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Double.mapCircle() = sin(HALF_PI * this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generated texture is as if you took the panorama picture of sky: up 70deg to horizon, east-south-west;
|
* Generated texture is as if you took the panorama picture of sky: up 70deg to horizon, east-south-west;
|
||||||
* with sun not moving (sun is at exact south, sun's height is adjustable)
|
* with sun not moving (sun is at exact south, sun's height is adjustable)
|
||||||
*/
|
*/
|
||||||
private fun genTexLoop(state: ArHosekSkyModelState) {
|
private fun genTexLoop(state: ArHosekSkyModelState, elevation: Double) {
|
||||||
|
|
||||||
fun normaliseY(y: Double): Float {
|
fun normaliseY(y: Double): Float {
|
||||||
var v = y.coerceAtLeast(0.0)
|
var v = y.coerceAtLeast(0.0)
|
||||||
@@ -120,20 +184,49 @@ class Application : Game() {
|
|||||||
return v.toFloat()
|
return v.toFloat()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val ys = ArrayList<Float>()
|
||||||
|
val ys2 = ArrayList<Float>()
|
||||||
|
|
||||||
|
val halfHeight = oneScreen.height * 0.5
|
||||||
|
val elevationDeg = Math.toDegrees(elevation)
|
||||||
|
|
||||||
for (y in 0 until oneScreen.height) {
|
|
||||||
for (x in 0 until oneScreen.width) {
|
for (x in 0 until oneScreen.width) {
|
||||||
val gamma = (x / oneScreen.width.toDouble()) * TWO_PI // 0deg..360deg
|
for (y in 0 until oneScreen.height) {
|
||||||
val theta = (1.0 - (y / oneScreen.height.toDouble())) * HALF_PI // 90deg..0deg
|
|
||||||
|
// sky-sphere mapping
|
||||||
|
/*val xf = ((x + 0.5) / oneScreen.width) * 2.0 - 1.0
|
||||||
|
val yf = ((y + 0.5) / oneScreen.height) * 2.0 - 1.0
|
||||||
|
val gamma = atan2(yf, xf) + PI
|
||||||
|
val theta = sqrt(xf*xf + yf*yf) * HALF_PI*/
|
||||||
|
|
||||||
|
// AM-PM mapping (use with WIDTH=1)
|
||||||
|
val yp = y % (oneScreen.height / 2)
|
||||||
|
val yi = yp - 3
|
||||||
|
val xf = -elevationDeg / 90.0
|
||||||
|
var yf = (yi / 58.0).coerceIn(0.0, 1.0).mapCircle().coerceInSmoothly(0.0, 0.95)
|
||||||
|
if (elevationDeg < 0) yf *= Skybox.superellipsoidDecay(1.0 / 3.0, xf)
|
||||||
|
val theta = yf * HALF_PI
|
||||||
|
val gamma = if (y < halfHeight) HALF_PI else 3 * HALF_PI
|
||||||
|
|
||||||
|
|
||||||
val xyz = CIEXYZ(
|
val xyz = CIEXYZ(
|
||||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 0).toFloat().times(scalefactor / 10f),
|
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 0).toFloat(),
|
||||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 1).toFloat().times(scalefactor / 10f),
|
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 1).toFloat(),
|
||||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 2).toFloat().times(scalefactor / 10f)
|
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 2).toFloat(),
|
||||||
)
|
)
|
||||||
val rgb = xyz.toRGB().toColor()
|
val xyz2 = xyz.scaleToFit(elevation)
|
||||||
|
ys.add(xyz.Y)
|
||||||
|
ys2.add(xyz2.Y)
|
||||||
|
val rgb = xyz2.toRGB().toColor()
|
||||||
rgb.a = 1f
|
rgb.a = 1f
|
||||||
|
|
||||||
|
/*val rgb2 = Color(
|
||||||
|
((rgb.r * 255f).roundToInt() xor 0xAA) / 255f,
|
||||||
|
((rgb.g * 255f).roundToInt() xor 0xAA) / 255f,
|
||||||
|
((rgb.b * 255f).roundToInt() xor 0xAA) / 255f,
|
||||||
|
rgb.a
|
||||||
|
)*/
|
||||||
|
|
||||||
oneScreen.setColor(rgb)
|
oneScreen.setColor(rgb)
|
||||||
oneScreen.drawPixel(x, y)
|
oneScreen.drawPixel(x, y)
|
||||||
|
|
||||||
@@ -142,140 +235,148 @@ class Application : Game() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ymaxDisp.text = "${ys.max()}"
|
||||||
|
ymaxDisp2.text = "${ys2.max()}"
|
||||||
|
|
||||||
//System.exit(0)
|
//System.exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generated texture is as if you took the panorama picture of sky: up 70deg to horizon, east-south-west;
|
|
||||||
* with sun not moving (sun is at exact south, sun's height is adjustable)
|
|
||||||
*/
|
|
||||||
/*private fun genTexLoop2(T: Double, theta_s: Double) {
|
|
||||||
|
|
||||||
fun hazeFun(T: Double): Double {
|
|
||||||
val T = T - 1
|
|
||||||
if (T >= 10) return 1.0
|
|
||||||
else return 2.0.pow(T).div(1024.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop thru gamma and theta
|
|
||||||
for (y in 0..outTexDim) { // theta
|
|
||||||
for (x in 0..outTexDim) { // gamma
|
|
||||||
val theta = Math.toRadians(y * (90.0 / outTexDim.toDouble())) // of observer
|
|
||||||
val gamma = Math.toRadians(x * (90.0 / outTexDim.toDouble())) // of observer
|
|
||||||
|
|
||||||
val Y_z = Model.getAbsoluteZenithLuminance(T, theta_s)
|
|
||||||
val x_z = Model.getZenithChromaX(T, theta_s)
|
|
||||||
val y_z = Model.getZenithChromaY(T, theta_s)
|
|
||||||
|
|
||||||
val Y_p = Y_z * Model.getFforLuma(theta, gamma, T) / Model.getFforLuma(0.0, theta_s, T)
|
|
||||||
val Y_oc = Y_z * (1.0 + 2.0 * Math.cos(theta)) / 3.0
|
|
||||||
val x_p = (x_z * Model.getFforChromaX(theta, gamma, T) / Model.getFforChromaX(0.0, theta_s, T)).coerceIn(0.0, 1.0)
|
|
||||||
val y_p = (y_z * Model.getFforChromaY(theta, gamma, T) / Model.getFforChromaY(0.0, theta_s, T)).coerceIn(0.0, 1.0)
|
|
||||||
|
|
||||||
val normalisedY = Y_p.toFloat().pow(0.5f).div(10f)
|
|
||||||
val normalisedY_oc = Y_oc.toFloat().pow(0.5f).div(10f)
|
|
||||||
|
|
||||||
//println("$Y_p -> $normalisedY, $x_p, $y_p")
|
|
||||||
|
|
||||||
if (T < 11) {
|
|
||||||
val rgbColour = CIEYXY(normalisedY, x_p.toFloat(), y_p.toFloat()).toXYZ().toColorRaw()
|
|
||||||
val hazeColour = CIEYXY(normalisedY_oc, 0.3128f, 0.3290f).toXYZ().toColorRaw()
|
|
||||||
|
|
||||||
val hazeAmount = hazeFun(T).toFloat()
|
|
||||||
val newColour = Color(
|
|
||||||
FastMath.interpolateLinear(hazeAmount, rgbColour.r, hazeColour.r),
|
|
||||||
FastMath.interpolateLinear(hazeAmount, rgbColour.g, hazeColour.g),
|
|
||||||
FastMath.interpolateLinear(hazeAmount, rgbColour.b, hazeColour.b),
|
|
||||||
1f
|
|
||||||
)
|
|
||||||
|
|
||||||
oneScreen.setColor(newColour)
|
|
||||||
oneScreen.drawPixel(x, y)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val hazeColour = CIEYXY(normalisedY_oc, 0.3128f, 0.3290f).toXYZ().toColorRaw()
|
|
||||||
oneScreen.setColor(hazeColour)
|
|
||||||
oneScreen.drawPixel(x, y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// end loop
|
|
||||||
}*/
|
|
||||||
|
|
||||||
override fun create() {
|
override fun create() {
|
||||||
batch = SpriteBatch()
|
batch = SpriteBatch()
|
||||||
testTex = Texture(Gdx.files.internal("assets/test_texture.tga"))
|
|
||||||
|
|
||||||
oneScreen = Pixmap(outTexWidth * 2, outTexHeight, Pixmap.Format.RGBA8888)
|
oneScreen = Pixmap(outTexWidth, outTexHeight, Pixmap.Format.RGBA8888)
|
||||||
|
|
||||||
DatasetSpectral
|
// DatasetSpectral
|
||||||
DatasetCIEXYZ
|
DatasetCIEXYZ
|
||||||
DatasetRGB
|
// DatasetRGB
|
||||||
|
|
||||||
ApplicationController(this)
|
ApplicationController(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val ymaxDisp = JTextField().also {
|
||||||
|
it.preferredSize = Dimension(64, 20)
|
||||||
|
}
|
||||||
|
val ymaxDisp2 = JTextField().also {
|
||||||
|
it.preferredSize = Dimension(64, 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
class ApplicationController(val app: Application) : JFrame() {
|
||||||
|
|
||||||
class ApplicationController(app: Application) : JFrame() {
|
val dialSize = Dimension(45, 20)
|
||||||
|
|
||||||
|
val turbidityControl = JSpinner(SpinnerNumberModel(INITIAL_TURBIDITY, 1.0, 10.0, 0.1)).also {
|
||||||
|
it.preferredSize = dialSize
|
||||||
|
it.addChangeListener { _ ->
|
||||||
|
app.turbidity = it.value as Double
|
||||||
|
app.regenerateModel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val albedoControl = JSpinner(SpinnerNumberModel(INITIAL_ALBEDO, 0.0, 1.0, 0.05)).also {
|
||||||
|
it.preferredSize = dialSize
|
||||||
|
it.addChangeListener { _ ->
|
||||||
|
app.albedo = it.value as Double
|
||||||
|
app.regenerateModel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val elevationControl = JSpinner(SpinnerNumberModel(INITIAL_ELEV, -75.0, 75.0, 0.5)).also {
|
||||||
|
it.preferredSize = dialSize
|
||||||
|
it.addChangeListener { _ ->
|
||||||
|
app.elevation = Math.toRadians(it.value as Double)
|
||||||
|
app.regenerateModel()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val solarBearing = JSpinner(SpinnerNumberModel(90.0, 0.0, 180.0, 1.0)).also {
|
||||||
|
it.preferredSize = dialSize
|
||||||
|
it.addChangeListener { _ ->
|
||||||
|
app.solarBearing = (it.value as Double)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val cameraHeading = JSpinner(SpinnerNumberModel(90.0, 0.0, 180.0, 1.0)).also {
|
||||||
|
it.preferredSize = dialSize
|
||||||
|
it.addChangeListener { _ ->
|
||||||
|
app.cameraHeading = (it.value as Double)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val atmosPanel = JPanel()
|
||||||
|
val turbidityPanel = JPanel().also {
|
||||||
|
it.add(JLabel("Turbidity (log_2)"))
|
||||||
|
it.add(turbidityControl)
|
||||||
|
atmosPanel.add(it)
|
||||||
|
}
|
||||||
|
val albedoPanel = JPanel().also {
|
||||||
|
it.add(JLabel("Albedo"))
|
||||||
|
it.add(albedoControl)
|
||||||
|
atmosPanel.add(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val sunPanel = JPanel()
|
||||||
|
val elevationPanel = JPanel().also {
|
||||||
|
it.add(JLabel("Elevation"))
|
||||||
|
it.add(elevationControl)
|
||||||
|
sunPanel.add(it)
|
||||||
|
}
|
||||||
|
val scalefactorPanel = JPanel().also {
|
||||||
|
it.add(JLabel("Bearing"))
|
||||||
|
it.add(solarBearing)
|
||||||
|
sunPanel.add(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val cameraPanel = JPanel()
|
||||||
|
val headingPanel = JPanel().also {
|
||||||
|
it.add(JLabel("Heading"))
|
||||||
|
it.add(cameraHeading)
|
||||||
|
cameraPanel.add(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val statsPanel = JPanel()
|
||||||
|
val ymaxPanel = JPanel().also {
|
||||||
|
it.add(JLabel("Ymax (CIEXYZ)"))
|
||||||
|
it.add(app.ymaxDisp)
|
||||||
|
statsPanel.add(it)
|
||||||
|
}
|
||||||
|
val ymaxPanel2 = JPanel().also {
|
||||||
|
it.add(JLabel("Ymax (scaled)"))
|
||||||
|
it.add(app.ymaxDisp2)
|
||||||
|
statsPanel.add(it)
|
||||||
|
}
|
||||||
|
|
||||||
val mainPanel = JPanel()
|
val mainPanel = JPanel()
|
||||||
|
|
||||||
val turbidityControl = JSpinner(SpinnerNumberModel(5.0, 1.0, 10.0, 0.1))
|
mainPanel.layout = BoxLayout(mainPanel, BoxLayout.Y_AXIS)
|
||||||
val albedoControl = JSpinner(SpinnerNumberModel(0.1, 0.0, 1.0, 0.05))
|
JPanel().also {
|
||||||
val elevationControl = JSpinner(SpinnerNumberModel(0.0, 0.0, 90.0, 0.5))
|
it.layout = BorderLayout()
|
||||||
val scalefactorControl = JSpinner(SpinnerNumberModel(1.0, 0.0, 2.0, 0.01))
|
it.add(JPanel().also { it.add(JLabel("Atmosphere")) }, BorderLayout.NORTH)
|
||||||
|
it.add(atmosPanel, BorderLayout.CENTER)
|
||||||
init {
|
it.add(JSeparator(), BorderLayout.SOUTH)
|
||||||
val turbidityPanel = JPanel()
|
mainPanel.add(it)
|
||||||
val albedoPanel = JPanel()
|
}
|
||||||
val elevationPanel = JPanel()
|
JPanel().also {
|
||||||
val scalefactorPanel = JPanel()
|
it.layout = BorderLayout()
|
||||||
|
it.add(JPanel().also { it.add(JLabel("Sun")) }, BorderLayout.NORTH)
|
||||||
turbidityControl.preferredSize = Dimension(45, 18)
|
it.add(sunPanel, BorderLayout.CENTER)
|
||||||
albedoControl.preferredSize = Dimension(45, 18)
|
it.add(JSeparator(), BorderLayout.SOUTH)
|
||||||
elevationControl.preferredSize = Dimension(45, 18)
|
mainPanel.add(it)
|
||||||
scalefactorControl.preferredSize = Dimension(45, 18)
|
}
|
||||||
|
JPanel().also {
|
||||||
turbidityPanel.add(JLabel("Turbidity"))
|
it.layout = BorderLayout()
|
||||||
turbidityPanel.add(turbidityControl)
|
it.add(JPanel().also { it.add(JLabel("Camera")) }, BorderLayout.NORTH)
|
||||||
|
it.add(cameraPanel, BorderLayout.CENTER)
|
||||||
albedoPanel.add(JLabel("Albedo"))
|
it.add(JSeparator(), BorderLayout.SOUTH)
|
||||||
albedoPanel.add(albedoControl)
|
mainPanel.add(it)
|
||||||
|
}
|
||||||
elevationPanel.add(JLabel("Elevation"))
|
JPanel().also {
|
||||||
elevationPanel.add(elevationControl)
|
it.layout = BorderLayout()
|
||||||
|
it.add(JPanel().also { it.add(JLabel("Statistics")) }, BorderLayout.NORTH)
|
||||||
scalefactorPanel.add(JLabel("Scaling Factor"))
|
it.add(statsPanel, BorderLayout.CENTER)
|
||||||
scalefactorPanel.add(scalefactorControl)
|
mainPanel.add(it)
|
||||||
|
}
|
||||||
mainPanel.add(turbidityPanel)
|
|
||||||
mainPanel.add(albedoPanel)
|
|
||||||
mainPanel.add(elevationPanel)
|
|
||||||
mainPanel.add(scalefactorPanel)
|
|
||||||
|
|
||||||
this.isVisible = true
|
this.isVisible = true
|
||||||
this.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
|
this.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
|
||||||
this.size = Dimension(300, 400)
|
this.size = Dimension(300, 600)
|
||||||
|
this.add(mainPanel, BorderLayout.CENTER)
|
||||||
this.add(mainPanel)
|
|
||||||
|
|
||||||
|
|
||||||
turbidityControl.addChangeListener {
|
|
||||||
app.turbidity = turbidityControl.value as Double
|
|
||||||
}
|
|
||||||
|
|
||||||
albedoControl.addChangeListener {
|
|
||||||
app.albedo = albedoControl.value as Double
|
|
||||||
}
|
|
||||||
|
|
||||||
elevationControl.addChangeListener {
|
|
||||||
app.elevation = Math.toRadians(elevationControl.value as Double)
|
|
||||||
}
|
|
||||||
|
|
||||||
scalefactorControl.addChangeListener {
|
|
||||||
app.scalefactor = (scalefactorControl.value as Double).toFloat()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +386,10 @@ class Application : Game() {
|
|||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val config = Lwjgl3ApplicationConfiguration()
|
val config = Lwjgl3ApplicationConfiguration()
|
||||||
config.setWindowedMode(WIDTH, HEIGHT)
|
|
||||||
|
|
||||||
Lwjgl3Application(Application(), config)
|
val WIDTH = 2048
|
||||||
|
val HEIGHT = 2048
|
||||||
|
|
||||||
|
config.setWindowedMode(WIDTH, HEIGHT)
|
||||||
|
Lwjgl3Application(Application(WIDTH, HEIGHT), config)
|
||||||
}
|
}
|
||||||
@@ -11,8 +11,8 @@ object DatasetOp {
|
|||||||
val entrysize = file.length().toInt() / 8
|
val entrysize = file.length().toInt() / 8
|
||||||
val fis = FileInputStream(file)
|
val fis = FileInputStream(file)
|
||||||
|
|
||||||
val ret = DoubleArray(entrysize) {
|
|
||||||
val inputbuf = ByteArray(8)
|
val inputbuf = ByteArray(8)
|
||||||
|
val ret = DoubleArray(entrysize) {
|
||||||
fis.read(inputbuf)
|
fis.read(inputbuf)
|
||||||
val rawnum = inputbuf.toLittleInt64()
|
val rawnum = inputbuf.toLittleInt64()
|
||||||
Double.fromBits(rawnum)
|
Double.fromBits(rawnum)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package net.torvald.random
|
package net.torvald.random
|
||||||
|
|
||||||
import com.jme3.math.FastMath
|
import com.jme3.math.FastMath
|
||||||
import net.torvald.terrarum.floorInt
|
import net.torvald.terrarum.floorToInt
|
||||||
import net.torvald.terrarum.gameworld.fmod
|
import net.torvald.terrarum.gameworld.fmod
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -45,9 +45,9 @@ class TileableValueNoise(
|
|||||||
try {
|
try {
|
||||||
for (x in 0..width) {
|
for (x in 0..width) {
|
||||||
val thisSampleStart: Int = // 0-256 -> 0-4 -> 0-256(qnt)
|
val thisSampleStart: Int = // 0-256 -> 0-4 -> 0-256(qnt)
|
||||||
(x / width.toFloat() * samples).floorInt() * (width / samples)
|
(x / width.toFloat() * samples).floorToInt() * (width / samples)
|
||||||
val nextSampleStart: Int =
|
val nextSampleStart: Int =
|
||||||
(x / width.toFloat() * samples).floorInt().plus(1) * (width / samples)
|
(x / width.toFloat() * samples).floorToInt().plus(1) * (width / samples)
|
||||||
val stepWithinWindow: Int = x % (nextSampleStart - thisSampleStart)
|
val stepWithinWindow: Int = x % (nextSampleStart - thisSampleStart)
|
||||||
val windowScale: Float = stepWithinWindow.toFloat() / (width / samples)
|
val windowScale: Float = stepWithinWindow.toFloat() / (width / samples)
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion
|
|||||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||||
import net.torvald.terrarum.ItemCodex
|
import net.torvald.terrarum.ItemCodex
|
||||||
import net.torvald.terrarum.Second
|
import net.torvald.terrarum.Second
|
||||||
import net.torvald.terrarum.floor
|
import net.torvald.terrarum.floorToFloat
|
||||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||||
import net.torvald.terrarum.gameitems.GameItem
|
import net.torvald.terrarum.gameitems.GameItem
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
|
||||||
@@ -19,6 +19,7 @@ import net.torvald.terrarum.spriteassembler.ADProperties
|
|||||||
import net.torvald.terrarum.spriteassembler.ADPropertyObject
|
import net.torvald.terrarum.spriteassembler.ADPropertyObject
|
||||||
import net.torvald.terrarum.spriteassembler.AssembleFrameBase
|
import net.torvald.terrarum.spriteassembler.AssembleFrameBase
|
||||||
import net.torvald.terrarum.spriteassembler.AssembleSheetPixmap
|
import net.torvald.terrarum.spriteassembler.AssembleSheetPixmap
|
||||||
|
import net.torvald.terrarum.tryDispose
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -122,8 +123,8 @@ class AssembledSpriteAnimation(
|
|||||||
val drawPos = adp.origin + bodypartPos // imgCentre for held items are (0,0)
|
val drawPos = adp.origin + bodypartPos // imgCentre for held items are (0,0)
|
||||||
val w = image.regionWidth * scale
|
val w = image.regionWidth * scale
|
||||||
val h = image.regionHeight * scale
|
val h = image.regionHeight * scale
|
||||||
val fposX = posX.floor() + drawPos.x * scale
|
val fposX = posX.floorToFloat() + drawPos.x * scale
|
||||||
val fposY = posY.floor() + drawPos.y * scale - h
|
val fposY = posY.floorToFloat() + drawPos.y * scale - h
|
||||||
|
|
||||||
// draw
|
// draw
|
||||||
if (flipHorizontal && flipVertical)
|
if (flipHorizontal && flipVertical)
|
||||||
@@ -146,8 +147,8 @@ class AssembledSpriteAnimation(
|
|||||||
val drawPos = adp.origin + bodypartPos - imgCentre
|
val drawPos = adp.origin + bodypartPos - imgCentre
|
||||||
val w = image.regionWidth * scale
|
val w = image.regionWidth * scale
|
||||||
val h = image.regionHeight * scale
|
val h = image.regionHeight * scale
|
||||||
val fposX = posX.floor() + drawPos.x * scale
|
val fposX = posX.floorToFloat() + drawPos.x * scale
|
||||||
val fposY = posY.floor() + drawPos.y * scale
|
val fposY = posY.floorToFloat() + drawPos.y * scale
|
||||||
|
|
||||||
if (flipHorizontal && flipVertical)
|
if (flipHorizontal && flipVertical)
|
||||||
batch.draw(image, fposX + txFlp, fposY + tyFlp, -w, -h)
|
batch.draw(image, fposX + txFlp, fposY + tyFlp, -w, -h)
|
||||||
@@ -172,7 +173,7 @@ class AssembledSpriteAnimation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
override fun dispose() {
|
||||||
res.values.forEach { try { it?.texture?.dispose() } catch (_: GdxRuntimeException) {} }
|
res.values.forEach { it?.texture?.tryDispose() }
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import net.torvald.terrarum.langpack.Lang;
|
|||||||
import net.torvald.terrarum.modulebasegame.IngameRenderer;
|
import net.torvald.terrarum.modulebasegame.IngameRenderer;
|
||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame;
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame;
|
||||||
import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory;
|
import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory;
|
||||||
import net.torvald.terrarum.savegame.DiskSkimmer;
|
|
||||||
import net.torvald.terrarum.serialise.WriteConfig;
|
import net.torvald.terrarum.serialise.WriteConfig;
|
||||||
import net.torvald.terrarum.ui.Toolkit;
|
import net.torvald.terrarum.ui.Toolkit;
|
||||||
import net.torvald.terrarum.utils.JsonFetcher;
|
import net.torvald.terrarum.utils.JsonFetcher;
|
||||||
@@ -63,9 +62,11 @@ public class App implements ApplicationListener {
|
|||||||
|
|
||||||
public static final String GAME_NAME = TerrarumAppConfiguration.GAME_NAME;
|
public static final String GAME_NAME = TerrarumAppConfiguration.GAME_NAME;
|
||||||
public static final long VERSION_RAW = TerrarumAppConfiguration.VERSION_RAW;
|
public static final long VERSION_RAW = TerrarumAppConfiguration.VERSION_RAW;
|
||||||
|
public static final String VERSION_TAG = TerrarumAppConfiguration.VERSION_TAG;
|
||||||
|
|
||||||
public static final String getVERSION_STRING() {
|
public static final String getVERSION_STRING() {
|
||||||
return String.format("%d.%d.%d", VERSION_RAW >>> 48, (VERSION_RAW & 0xffff000000L) >>> 24, VERSION_RAW & 0xffffffL);
|
return String.format("%d.%d.%d", VERSION_RAW >>> 48, (VERSION_RAW & 0xffff000000L) >>> 24, VERSION_RAW & 0xffffffL) +
|
||||||
|
(VERSION_TAG.isBlank() ? "" : "-"+VERSION_TAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -240,6 +241,7 @@ public class App implements ApplicationListener {
|
|||||||
public static ShaderProgram shaderColLUT;
|
public static ShaderProgram shaderColLUT;
|
||||||
public static ShaderProgram shaderReflect;
|
public static ShaderProgram shaderReflect;
|
||||||
public static ShaderProgram shaderGhastlyWhite;
|
public static ShaderProgram shaderGhastlyWhite;
|
||||||
|
public static Hq2x hq2x;
|
||||||
|
|
||||||
public static Mesh fullscreenQuad;
|
public static Mesh fullscreenQuad;
|
||||||
private static OrthographicCamera camera;
|
private static OrthographicCamera camera;
|
||||||
@@ -267,12 +269,13 @@ public class App implements ApplicationListener {
|
|||||||
Gdx.gl20.glViewport(0, 0, width, height);
|
Gdx.gl20.glViewport(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final float UPDATE_RATE = 1f / 64f; // apparent framerate will be limited by update rate
|
public static final int TICKS = 64;
|
||||||
|
public static final float UPDATE_RATE = 1f / TICKS; // apparent framerate will be limited by update rate
|
||||||
|
|
||||||
private static float loadTimer = 0f;
|
private static float loadTimer = 0f;
|
||||||
private static final float showupTime = 100f / 1000f;
|
private static final float showupTime = 100f / 1000f;
|
||||||
|
|
||||||
private static FloatFrameBuffer renderFBO;
|
private static Float16FrameBuffer renderFBO;
|
||||||
|
|
||||||
public static HashSet<File> tempFilePool = new HashSet<>();
|
public static HashSet<File> tempFilePool = new HashSet<>();
|
||||||
|
|
||||||
@@ -392,6 +395,7 @@ public class App implements ApplicationListener {
|
|||||||
appConfig.useVsync(getConfigBoolean("usevsync"));
|
appConfig.useVsync(getConfigBoolean("usevsync"));
|
||||||
appConfig.setResizable(false);
|
appConfig.setResizable(false);
|
||||||
appConfig.setWindowedMode(width, height);
|
appConfig.setWindowedMode(width, height);
|
||||||
|
appConfig.setTransparentFramebuffer(false);
|
||||||
int fpsActive = Math.min(GLOBAL_FRAMERATE_LIMIT, getConfigInt("displayfps"));
|
int fpsActive = Math.min(GLOBAL_FRAMERATE_LIMIT, getConfigInt("displayfps"));
|
||||||
if (fpsActive <= 0) fpsActive = GLOBAL_FRAMERATE_LIMIT;
|
if (fpsActive <= 0) fpsActive = GLOBAL_FRAMERATE_LIMIT;
|
||||||
int fpsBack = Math.min(GLOBAL_FRAMERATE_LIMIT, getConfigInt("displayfpsidle"));
|
int fpsBack = Math.min(GLOBAL_FRAMERATE_LIMIT, getConfigInt("displayfpsidle"));
|
||||||
@@ -439,13 +443,10 @@ public class App implements ApplicationListener {
|
|||||||
|
|
||||||
glInfo.create();
|
glInfo.create();
|
||||||
|
|
||||||
CommonResourcePool.INSTANCE.addToLoadingList("blockmarkings_common", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/blocks/block_markings_common.tga"), 16, 16, 0, 0, 0, 0, false, false, false));
|
|
||||||
CommonResourcePool.INSTANCE.addToLoadingList("blockmarking_actor", () -> new BlockMarkerActor());
|
|
||||||
CommonResourcePool.INSTANCE.addToLoadingList("loading_circle_64", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/gui/loading_circle_64.tga"), 64, 64, 0, 0, 0, 0, false, false, false));
|
|
||||||
CommonResourcePool.INSTANCE.addToLoadingList("inline_loading_spinner", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/gui/inline_loading_spinner.tga"), 20, 20, 0, 0, 0, 0, false, false, false));
|
|
||||||
CommonResourcePool.INSTANCE.addToLoadingList("inventory_category", () -> new TextureRegionPack("./assets/graphics/gui/inventory/category.tga", 20, 20, 0, 0, 0, 0, false, false, false));
|
|
||||||
CommonResourcePool.INSTANCE.addToLoadingList("title_health1", () -> new Texture(Gdx.files.internal("./assets/graphics/gui/health_take_a_break.tga")));
|
CommonResourcePool.INSTANCE.addToLoadingList("title_health1", () -> new Texture(Gdx.files.internal("./assets/graphics/gui/health_take_a_break.tga")));
|
||||||
CommonResourcePool.INSTANCE.addToLoadingList("title_health2", () -> new Texture(Gdx.files.internal("./assets/graphics/gui/health_distance.tga")));
|
CommonResourcePool.INSTANCE.addToLoadingList("title_health2", () -> new Texture(Gdx.files.internal("./assets/graphics/gui/health_distance.tga")));
|
||||||
|
// make loading list
|
||||||
|
CommonResourcePool.INSTANCE.loadAll();
|
||||||
|
|
||||||
newTempFile("wenquanyi.tga"); // temp file required by the font
|
newTempFile("wenquanyi.tga"); // temp file required by the font
|
||||||
|
|
||||||
@@ -474,12 +475,9 @@ public class App implements ApplicationListener {
|
|||||||
shaderBayerSkyboxFill = loadShaderFromClasspath("shaders/default.vert",
|
shaderBayerSkyboxFill = loadShaderFromClasspath("shaders/default.vert",
|
||||||
"shaders/float_to_disp_dither_static.frag"
|
"shaders/float_to_disp_dither_static.frag"
|
||||||
);
|
);
|
||||||
shaderHicolour = loadShaderFromClasspath("shaders/default.vert", "shaders/hicolour.frag");
|
|
||||||
shaderDebugDiff = loadShaderFromClasspath("shaders/default.vert", "shaders/diff.frag");
|
|
||||||
shaderPassthruRGBA = loadShaderFromClasspath("shaders/gl32spritebatch.vert", "shaders/gl32spritebatch.frag");
|
shaderPassthruRGBA = loadShaderFromClasspath("shaders/gl32spritebatch.vert", "shaders/gl32spritebatch.frag");
|
||||||
shaderColLUT = loadShaderFromClasspath("shaders/default.vert", "shaders/passthrurgb.frag");
|
|
||||||
shaderReflect = loadShaderFromClasspath("shaders/default.vert", "shaders/reflect.frag");
|
shaderReflect = loadShaderFromClasspath("shaders/default.vert", "shaders/reflect.frag");
|
||||||
shaderGhastlyWhite = loadShaderFromClasspath("shaders/default.vert", "shaders/ghastlywhite.frag");
|
hq2x = new Hq2x(2);
|
||||||
|
|
||||||
fullscreenQuad = new Mesh(
|
fullscreenQuad = new Mesh(
|
||||||
true, 4, 6,
|
true, 4, 6,
|
||||||
@@ -487,97 +485,21 @@ public class App implements ApplicationListener {
|
|||||||
VertexAttribute.ColorUnpacked(),
|
VertexAttribute.ColorUnpacked(),
|
||||||
VertexAttribute.TexCoords(0)
|
VertexAttribute.TexCoords(0)
|
||||||
);
|
);
|
||||||
updateFullscreenQuad(scr.getWidth(), scr.getHeight());
|
updateFullscreenQuad(fullscreenQuad, scr.getWidth(), scr.getHeight());
|
||||||
|
|
||||||
|
|
||||||
// set up renderer info variables
|
// set up renderer info variables
|
||||||
renderer = Gdx.graphics.getGLVersion().getRendererString();
|
renderer = Gdx.graphics.getGLVersion().getRendererString();
|
||||||
rendererVendor = Gdx.graphics.getGLVersion().getVendorString();
|
rendererVendor = Gdx.graphics.getGLVersion().getVendorString();
|
||||||
|
|
||||||
|
|
||||||
// make gamepad(s)
|
|
||||||
if (App.getConfigBoolean("usexinput")) {
|
|
||||||
try {
|
|
||||||
gamepad = new XinputControllerAdapter(XInputDevice.getDeviceFor(0));
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
gamepad = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// nullify if not actually connected
|
|
||||||
try {
|
|
||||||
if (!((XinputControllerAdapter) gamepad).getC().isConnected()) {
|
|
||||||
gamepad = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (NullPointerException notQuiteWindows) {
|
|
||||||
gamepad = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gamepad == null) {
|
|
||||||
try {
|
|
||||||
gamepad = new GdxControllerAdapter(Controllers.getControllers().get(0));
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
gamepad = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// tell the game that we have a gamepad
|
|
||||||
environment = RunningEnvironment.PC;
|
|
||||||
|
|
||||||
if (gamepad != null) {
|
|
||||||
String name = gamepad.getName().toLowerCase();
|
|
||||||
for (String allowedName : gamepadWhitelist) {
|
|
||||||
if (name.contains(allowedName)) {
|
|
||||||
environment = RunningEnvironment.CONSOLE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*if (gamepad != null) {
|
|
||||||
environment = RunningEnvironment.CONSOLE;
|
|
||||||
|
|
||||||
// calibrate the sticks
|
|
||||||
printdbg(this, "Calibrating the gamepad...");
|
|
||||||
float[] axesZeroPoints = new float[]{
|
|
||||||
gamepad.getAxisRaw(0),
|
|
||||||
gamepad.getAxisRaw(1),
|
|
||||||
gamepad.getAxisRaw(2),
|
|
||||||
gamepad.getAxisRaw(3)
|
|
||||||
};
|
|
||||||
setConfig("control_gamepad_axiszeropoints", axesZeroPoints);
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
printdbg(this, "Axis " + i + ": " + axesZeroPoints[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
environment = RunningEnvironment.PC;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
fontGame = new TerrarumSansBitmap(FONT_DIR, false, false, false,
|
fontGame = new TerrarumSansBitmap(FONT_DIR, false, false, false,
|
||||||
false,
|
false,
|
||||||
256, false, 0.5f, false
|
256, false, 0.5f, false
|
||||||
);
|
);
|
||||||
fontUITitle = new TerrarumSansBitmap(FONT_DIR, false, false, false,
|
|
||||||
false,
|
|
||||||
64, false, 0.5f, false
|
|
||||||
);
|
|
||||||
fontUITitle.setInterchar(1);
|
|
||||||
fontGameFBO = new TerrarumSansBitmap(FONT_DIR, false, true, false,
|
|
||||||
false,
|
|
||||||
64, false, 203f/255f, false
|
|
||||||
);
|
|
||||||
Lang.invoke();
|
|
||||||
|
|
||||||
// make loading list
|
|
||||||
CommonResourcePool.INSTANCE.loadAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private FrameBuffer postProcessorOutFBO;
|
private FrameBuffer postProcessorOutFBO;
|
||||||
|
private FrameBuffer postProcessorOutFBO2;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render() {
|
public void render() {
|
||||||
@@ -636,30 +558,44 @@ public class App implements ApplicationListener {
|
|||||||
FrameBufferManager.end();
|
FrameBufferManager.end();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// process screenshot request
|
// process screenshot request
|
||||||
if (screenshotRequested) {
|
processScreenshotRequest(postProcessorOutFBO);
|
||||||
FrameBufferManager.begin(postProcessorOutFBO);
|
|
||||||
try {
|
|
||||||
Pixmap p = Pixmap.createFromFrameBuffer(0, 0, scr.getWidth(), scr.getHeight());
|
|
||||||
PixmapIO.writePNG(Gdx.files.absolute(defaultDir+"/Screenshot-"+String.valueOf(System.currentTimeMillis())+".png"), p, 9, true);
|
|
||||||
p.dispose();
|
|
||||||
Terrarum.INSTANCE.getIngame().sendNotification("Screenshot taken");
|
|
||||||
}
|
|
||||||
catch (Throwable e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
Terrarum.INSTANCE.getIngame().sendNotification("Failed to take screenshot: "+e.getMessage());
|
|
||||||
}
|
|
||||||
FrameBufferManager.end();
|
|
||||||
screenshotRequested = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (getConfigString("screenmagnifyingfilter").equals("hq2x") ) {
|
||||||
|
FrameBufferManager.begin(postProcessorOutFBO2);
|
||||||
|
shaderPassthruRGBA.bind();
|
||||||
|
shaderPassthruRGBA.setUniformMatrix("u_projTrans", camera.combined);
|
||||||
|
shaderPassthruRGBA.setUniformi("u_texture", 0);
|
||||||
|
hq2x.renderToScreen(postProcessorOutFBO.getColorBufferTexture());
|
||||||
|
FrameBufferManager.end();
|
||||||
|
|
||||||
shaderPassthruRGBA.bind();
|
shaderPassthruRGBA.bind();
|
||||||
shaderPassthruRGBA.setUniformMatrix("u_projTrans", camera.combined);
|
shaderPassthruRGBA.setUniformMatrix("u_projTrans", camera.combined);
|
||||||
shaderPassthruRGBA.setUniformi("u_texture", 0);
|
shaderPassthruRGBA.setUniformi("u_texture", 0);
|
||||||
|
postProcessorOutFBO2.getColorBufferTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
|
||||||
|
postProcessorOutFBO2.getColorBufferTexture().bind(0);
|
||||||
|
fullscreenQuad.render(shaderPassthruRGBA, GL20.GL_TRIANGLES);
|
||||||
|
}
|
||||||
|
else if (getConfigDouble("screenmagnifying") < 1.01 || getConfigString("screenmagnifyingfilter").equals("none")) {
|
||||||
|
shaderPassthruRGBA.bind();
|
||||||
|
shaderPassthruRGBA.setUniformMatrix("u_projTrans", camera.combined);
|
||||||
|
shaderPassthruRGBA.setUniformi("u_texture", 0);
|
||||||
|
postProcessorOutFBO.getColorBufferTexture().setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest);
|
||||||
postProcessorOutFBO.getColorBufferTexture().bind(0);
|
postProcessorOutFBO.getColorBufferTexture().bind(0);
|
||||||
fullscreenQuad.render(shaderPassthruRGBA, GL20.GL_TRIANGLES);
|
fullscreenQuad.render(shaderPassthruRGBA, GL20.GL_TRIANGLES);
|
||||||
|
}
|
||||||
|
else if (getConfigString("screenmagnifyingfilter").equals("bilinear")) {
|
||||||
|
shaderPassthruRGBA.bind();
|
||||||
|
shaderPassthruRGBA.setUniformMatrix("u_projTrans", camera.combined);
|
||||||
|
shaderPassthruRGBA.setUniformi("u_texture", 0);
|
||||||
|
postProcessorOutFBO.getColorBufferTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
|
||||||
|
postProcessorOutFBO.getColorBufferTexture().bind(0);
|
||||||
|
fullscreenQuad.render(shaderPassthruRGBA, GL20.GL_TRIANGLES);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// process resize request
|
// process resize request
|
||||||
if (resizeRequested) {
|
if (resizeRequested) {
|
||||||
@@ -674,6 +610,26 @@ public class App implements ApplicationListener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void processScreenshotRequest(FrameBuffer fb) {
|
||||||
|
if (screenshotRequested) {
|
||||||
|
String msg = "Screenshot taken";
|
||||||
|
FrameBufferManager.begin(fb);
|
||||||
|
try {
|
||||||
|
Pixmap p = Pixmap.createFromFrameBuffer(0, 0, fb.getWidth(), fb.getHeight());
|
||||||
|
PixmapIO.writePNG(Gdx.files.absolute(defaultDir+"/Screenshot-"+String.valueOf(System.currentTimeMillis())+".png"), p, 9, true);
|
||||||
|
p.dispose();
|
||||||
|
}
|
||||||
|
catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
msg = ("Failed to take screenshot: "+e.getMessage());
|
||||||
|
}
|
||||||
|
FrameBufferManager.end();
|
||||||
|
screenshotRequested = false;
|
||||||
|
|
||||||
|
Terrarum.INSTANCE.getIngame().sendNotification(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Texture getCurrentDitherTex() {
|
public static Texture getCurrentDitherTex() {
|
||||||
int hash = 31 + GLOBAL_RENDER_TIMER + 0x165667B1 + GLOBAL_RENDER_TIMER * 0xC2B2AE3D;
|
int hash = 31 + GLOBAL_RENDER_TIMER + 0x165667B1 + GLOBAL_RENDER_TIMER * 0xC2B2AE3D;
|
||||||
hash = Integer.rotateLeft(hash, 17) * 0x27D4EB2F;
|
hash = Integer.rotateLeft(hash, 17) * 0x27D4EB2F;
|
||||||
@@ -792,18 +748,23 @@ public class App implements ApplicationListener {
|
|||||||
|
|
||||||
if (currentScreen != null) currentScreen.resize(scr.getWidth(), scr.getHeight());
|
if (currentScreen != null) currentScreen.resize(scr.getWidth(), scr.getHeight());
|
||||||
TerrarumPostProcessor.INSTANCE.resize(scr.getWidth(), scr.getHeight());
|
TerrarumPostProcessor.INSTANCE.resize(scr.getWidth(), scr.getHeight());
|
||||||
updateFullscreenQuad(scr.getWidth(), scr.getHeight());
|
updateFullscreenQuad(fullscreenQuad, scr.getWidth(), scr.getHeight());
|
||||||
|
|
||||||
|
|
||||||
if (renderFBO == null ||
|
if (renderFBO == null ||
|
||||||
(renderFBO.getWidth() != scr.getWidth() ||
|
(renderFBO.getWidth() != scr.getWidth() ||
|
||||||
renderFBO.getHeight() != scr.getHeight())
|
renderFBO.getHeight() != scr.getHeight())
|
||||||
) {
|
) {
|
||||||
renderFBO = new FloatFrameBuffer(
|
renderFBO = new Float16FrameBuffer(
|
||||||
scr.getWidth(),
|
scr.getWidth(),
|
||||||
scr.getHeight(),
|
scr.getHeight(),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
postProcessorOutFBO2 = new Float16FrameBuffer(
|
||||||
|
scr.getWidth() * 2,
|
||||||
|
scr.getHeight() * 2,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
if (IS_DEVELOPMENT_BUILD) {
|
if (IS_DEVELOPMENT_BUILD) {
|
||||||
@@ -856,6 +817,7 @@ public class App implements ApplicationListener {
|
|||||||
shaderColLUT.dispose();
|
shaderColLUT.dispose();
|
||||||
shaderReflect.dispose();
|
shaderReflect.dispose();
|
||||||
shaderGhastlyWhite.dispose();
|
shaderGhastlyWhite.dispose();
|
||||||
|
hq2x.dispose();
|
||||||
|
|
||||||
CommonResourcePool.INSTANCE.dispose();
|
CommonResourcePool.INSTANCE.dispose();
|
||||||
fullscreenQuad.dispose();
|
fullscreenQuad.dispose();
|
||||||
@@ -954,6 +916,93 @@ public class App implements ApplicationListener {
|
|||||||
* Init stuffs which needs GL context
|
* Init stuffs which needs GL context
|
||||||
*/
|
*/
|
||||||
private void postInit() {
|
private void postInit() {
|
||||||
|
CommonResourcePool.INSTANCE.addToLoadingList("blockmarkings_common", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/blocks/block_markings_common.tga"), 16, 16, 0, 0, 0, 0, false, false, false));
|
||||||
|
CommonResourcePool.INSTANCE.addToLoadingList("blockmarking_actor", () -> new BlockMarkerActor());
|
||||||
|
CommonResourcePool.INSTANCE.addToLoadingList("loading_circle_64", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/gui/loading_circle_64.tga"), 64, 64, 0, 0, 0, 0, false, false, false));
|
||||||
|
CommonResourcePool.INSTANCE.addToLoadingList("inline_loading_spinner", () -> new TextureRegionPack(Gdx.files.internal("assets/graphics/gui/inline_loading_spinner.tga"), 20, 20, 0, 0, 0, 0, false, false, false));
|
||||||
|
CommonResourcePool.INSTANCE.addToLoadingList("inventory_category", () -> new TextureRegionPack("./assets/graphics/gui/inventory/category.tga", 20, 20, 0, 0, 0, 0, false, false, false));
|
||||||
|
CommonResourcePool.INSTANCE.loadAll();
|
||||||
|
|
||||||
|
shaderHicolour = loadShaderFromClasspath("shaders/default.vert", "shaders/hicolour.frag");
|
||||||
|
shaderDebugDiff = loadShaderFromClasspath("shaders/default.vert", "shaders/diff.frag");
|
||||||
|
shaderColLUT = loadShaderFromClasspath("shaders/default.vert", "shaders/rgbonly.frag");
|
||||||
|
shaderGhastlyWhite = loadShaderFromClasspath("shaders/default.vert", "shaders/ghastlywhite.frag");
|
||||||
|
|
||||||
|
// make gamepad(s)
|
||||||
|
if (App.getConfigBoolean("usexinput")) {
|
||||||
|
try {
|
||||||
|
gamepad = new XinputControllerAdapter(XInputDevice.getDeviceFor(0));
|
||||||
|
}
|
||||||
|
catch (Throwable e) {
|
||||||
|
gamepad = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// nullify if not actually connected
|
||||||
|
try {
|
||||||
|
if (!((XinputControllerAdapter) gamepad).getC().isConnected()) {
|
||||||
|
gamepad = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NullPointerException notQuiteWindows) {
|
||||||
|
gamepad = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gamepad == null) {
|
||||||
|
try {
|
||||||
|
gamepad = new GdxControllerAdapter(Controllers.getControllers().get(0));
|
||||||
|
}
|
||||||
|
catch (Throwable e) {
|
||||||
|
gamepad = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell the game that we have a gamepad
|
||||||
|
environment = RunningEnvironment.PC;
|
||||||
|
|
||||||
|
if (gamepad != null) {
|
||||||
|
String name = gamepad.getName().toLowerCase();
|
||||||
|
for (String allowedName : gamepadWhitelist) {
|
||||||
|
if (name.contains(allowedName)) {
|
||||||
|
environment = RunningEnvironment.CONSOLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*if (gamepad != null) {
|
||||||
|
environment = RunningEnvironment.CONSOLE;
|
||||||
|
|
||||||
|
// calibrate the sticks
|
||||||
|
printdbg(this, "Calibrating the gamepad...");
|
||||||
|
float[] axesZeroPoints = new float[]{
|
||||||
|
gamepad.getAxisRaw(0),
|
||||||
|
gamepad.getAxisRaw(1),
|
||||||
|
gamepad.getAxisRaw(2),
|
||||||
|
gamepad.getAxisRaw(3)
|
||||||
|
};
|
||||||
|
setConfig("control_gamepad_axiszeropoints", axesZeroPoints);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
printdbg(this, "Axis " + i + ": " + axesZeroPoints[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
environment = RunningEnvironment.PC;
|
||||||
|
}*/
|
||||||
|
fontUITitle = new TerrarumSansBitmap(FONT_DIR, false, false, false,
|
||||||
|
false,
|
||||||
|
64, false, 0.5f, false
|
||||||
|
);
|
||||||
|
fontUITitle.setInterchar(1);
|
||||||
|
fontGameFBO = new TerrarumSansBitmap(FONT_DIR, false, true, false,
|
||||||
|
false,
|
||||||
|
64, false, 203f/255f, false
|
||||||
|
);
|
||||||
|
Lang.invoke();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ModMgr.INSTANCE.invoke(); // invoke Module Manager
|
ModMgr.INSTANCE.invoke(); // invoke Module Manager
|
||||||
|
|
||||||
|
|
||||||
@@ -1032,14 +1081,14 @@ public class App implements ApplicationListener {
|
|||||||
logoBatch.setProjectionMatrix(camera.combined);
|
logoBatch.setProjectionMatrix(camera.combined);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateFullscreenQuad(int WIDTH, int HEIGHT) { // NOT y-flipped quads!
|
private void updateFullscreenQuad(Mesh mesh, int WIDTH, int HEIGHT) { // NOT y-flipped quads!
|
||||||
fullscreenQuad.setVertices(new float[]{
|
mesh.setVertices(new float[]{
|
||||||
0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f, 1f,
|
0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f, 1f,
|
||||||
WIDTH, 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f,
|
WIDTH, 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f,
|
||||||
WIDTH, HEIGHT, 0f, 1f, 1f, 1f, 1f, 1f, 0f,
|
WIDTH, HEIGHT, 0f, 1f, 1f, 1f, 1f, 1f, 0f,
|
||||||
0f, HEIGHT, 0f, 1f, 1f, 1f, 1f, 0f, 0f
|
0f, HEIGHT, 0f, 1f, 1f, 1f, 1f, 0f, 0f
|
||||||
});
|
});
|
||||||
fullscreenQuad.setIndices(new short[]{0, 1, 2, 2, 3, 0});
|
mesh.setIndices(new short[]{0, 1, 2, 2, 3, 0});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setGamepadButtonLabels() {
|
public static void setGamepadButtonLabels() {
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ object CommonResourcePool {
|
|||||||
addToLoadingList("itemplaceholder_48") {
|
addToLoadingList("itemplaceholder_48") {
|
||||||
TextureRegion(Texture("assets/item_kari_48.tga")).also { it.flip(false, false) }
|
TextureRegion(Texture("assets/item_kari_48.tga")).also { it.flip(false, false) }
|
||||||
}
|
}
|
||||||
addToLoadingList("test_texture") {
|
/*addToLoadingList("test_texture") {
|
||||||
TextureRegion(Texture("assets/test_texture.tga")).also { it.flip(false, false) }
|
TextureRegion(Texture("assets/test_texture.tga")).also { it.flip(false, false) }
|
||||||
}
|
}*/
|
||||||
loadAll()
|
loadAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ object DefaultConfig {
|
|||||||
"language" to App.getSysLang(),
|
"language" to App.getSysLang(),
|
||||||
"notificationshowuptime" to 4000, // 4s
|
"notificationshowuptime" to 4000, // 4s
|
||||||
"selecteditemnameshowuptime" to 4000, // 4s
|
"selecteditemnameshowuptime" to 4000, // 4s
|
||||||
"autosaveinterval" to 300000, // 5s
|
"autosaveinterval" to 300000, // 5m
|
||||||
"multithread" to true,
|
"multithread" to true,
|
||||||
|
|
||||||
"showhealthmessageonstartup" to true,
|
"showhealthmessageonstartup" to true,
|
||||||
@@ -112,6 +112,7 @@ object DefaultConfig {
|
|||||||
"inputmethod" to "none",
|
"inputmethod" to "none",
|
||||||
|
|
||||||
"screenmagnifying" to 1.0,
|
"screenmagnifying" to 1.0,
|
||||||
|
"screenmagnifyingfilter" to "none", // "none", "bilinear", "hq2x"
|
||||||
|
|
||||||
"fx_newlight" to false,
|
"fx_newlight" to false,
|
||||||
|
|
||||||
@@ -119,6 +120,12 @@ object DefaultConfig {
|
|||||||
"debug_deltat_benchmark_sample_sizes" to 2048,
|
"debug_deltat_benchmark_sample_sizes" to 2048,
|
||||||
|
|
||||||
|
|
||||||
|
"mastervolume" to 1.0,
|
||||||
|
"musicvolume" to 1.0,
|
||||||
|
"bgmvolume" to 1.0,
|
||||||
|
"sfxvolume" to 1.0,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// settings regarding debugger
|
// settings regarding debugger
|
||||||
/*"buildingmakerfavs" to arrayOf(
|
/*"buildingmakerfavs" to arrayOf(
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ object GlslTilingTest : ApplicationAdapter() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
val tilesInHorizontal = (Gdx.graphics.width.toFloat() / TILING_SIZE).ceil() + 1f
|
val tilesInHorizontal = (Gdx.graphics.width.toFloat() / TILING_SIZE).ceilToFloat() + 1f
|
||||||
val tilesInVertical = (Gdx.graphics.height.toFloat() / TILING_SIZE).ceil() + 1f
|
val tilesInVertical = (Gdx.graphics.height.toFloat() / TILING_SIZE).ceilToFloat() + 1f
|
||||||
|
|
||||||
tilesQuad = Mesh(
|
tilesQuad = Mesh(
|
||||||
true, 4, 6,
|
true, 4, 6,
|
||||||
@@ -129,8 +129,8 @@ object GlslTilingTest : ApplicationAdapter() {
|
|||||||
Gdx.gl.glEnable(GL20.GL_BLEND)
|
Gdx.gl.glEnable(GL20.GL_BLEND)
|
||||||
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA)
|
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA)
|
||||||
|
|
||||||
val tilesInHorizontal = (Gdx.graphics.width.toFloat() / TILING_SIZE).ceil() + 1f
|
val tilesInHorizontal = (Gdx.graphics.width.toFloat() / TILING_SIZE).ceilToFloat() + 1f
|
||||||
val tilesInVertical = (Gdx.graphics.height.toFloat() / TILING_SIZE).ceil() + 1f
|
val tilesInVertical = (Gdx.graphics.height.toFloat() / TILING_SIZE).ceilToFloat() + 1f
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
214
src/net/torvald/terrarum/Hq2x.kt
Normal file
214
src/net/torvald/terrarum/Hq2x.kt
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
package net.torvald.terrarum
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx
|
||||||
|
import com.badlogic.gdx.files.FileHandle
|
||||||
|
import com.badlogic.gdx.graphics.*
|
||||||
|
import com.badlogic.gdx.graphics.VertexAttributes.Usage
|
||||||
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||||
|
import com.badlogic.gdx.graphics.glutils.ShaderProgram
|
||||||
|
import com.badlogic.gdx.math.Matrix4
|
||||||
|
import com.badlogic.gdx.utils.Disposable
|
||||||
|
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [HQnX](https://en.wikipedia.org/wiki/Pixel-art_scaling_algorithms#hqnx_family)
|
||||||
|
* upscale algorithm GLSL implementation based on
|
||||||
|
* [CrossVR](https://github.com/CrossVR/hqx-shader/tree/master/glsl) project.
|
||||||
|
*/
|
||||||
|
class Hq2x : Disposable {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TEXTURE_HANDLE0 = 0
|
||||||
|
private const val TEXTURE_HANDLE1 = 1
|
||||||
|
|
||||||
|
private const val U_TEXTURE = "u_texture"
|
||||||
|
private const val U_LUT = "u_lut"
|
||||||
|
private const val U_TEXTURE_SIZE = "u_textureSize"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val mesh = ViewportQuadMesh(
|
||||||
|
VertexAttribute(Usage.Position, 2, "a_position"),
|
||||||
|
VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoord0"))
|
||||||
|
|
||||||
|
private val program: ShaderProgram
|
||||||
|
private val lutTexture: Texture
|
||||||
|
private val scaleFactor: Int
|
||||||
|
|
||||||
|
private var dstBuffer: FrameBuffer? = null
|
||||||
|
private var dstWidth = 0
|
||||||
|
private var dstHeight = 0
|
||||||
|
|
||||||
|
/** @param scaleFactor should be 2, 3 or 4 value. */
|
||||||
|
constructor(scaleFactor: Int) {
|
||||||
|
if (scaleFactor !in 2..4) {
|
||||||
|
throw GdxRuntimeException("Scale factor should be 2, 3 or 4.")
|
||||||
|
}
|
||||||
|
|
||||||
|
program = compileShader(
|
||||||
|
Gdx.files.classpath("shaders/hq2x.vert"),
|
||||||
|
Gdx.files.classpath("shaders/hq2x.frag"),
|
||||||
|
"")
|
||||||
|
|
||||||
|
lutTexture = Texture(Gdx.files.classpath("shaders/hq${scaleFactor}x.png"))
|
||||||
|
|
||||||
|
this.scaleFactor = scaleFactor
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
mesh.dispose()
|
||||||
|
program.dispose()
|
||||||
|
lutTexture.dispose()
|
||||||
|
dstBuffer?.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun rebind() {
|
||||||
|
program.bind()
|
||||||
|
program.setUniformi(U_TEXTURE, TEXTURE_HANDLE0)
|
||||||
|
program.setUniformi(U_LUT, TEXTURE_HANDLE1)
|
||||||
|
program.setUniformf(U_TEXTURE_SIZE,
|
||||||
|
dstWidth / scaleFactor.toFloat(),
|
||||||
|
dstHeight / scaleFactor.toFloat())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun renderToScreen(src: Texture) {
|
||||||
|
validate(src)
|
||||||
|
|
||||||
|
lutTexture.bind(TEXTURE_HANDLE1)
|
||||||
|
src.bind(TEXTURE_HANDLE0)
|
||||||
|
src.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
|
||||||
|
|
||||||
|
program.bind()
|
||||||
|
mesh.render(program)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun renderToBuffer(src: Texture): Texture {
|
||||||
|
validate(src)
|
||||||
|
validateDstBuffer()
|
||||||
|
|
||||||
|
lutTexture.bind(TEXTURE_HANDLE1)
|
||||||
|
src.bind(TEXTURE_HANDLE0)
|
||||||
|
src.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
|
||||||
|
|
||||||
|
dstBuffer!!.begin()
|
||||||
|
program.bind()
|
||||||
|
mesh.render(program)
|
||||||
|
dstBuffer!!.end()
|
||||||
|
|
||||||
|
return dstBuffer!!.colorBufferTexture
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validate(src: Texture) {
|
||||||
|
val targetWidth = src.width * scaleFactor
|
||||||
|
val targetHeight = src.height * scaleFactor
|
||||||
|
|
||||||
|
// println("[Hq2x] $targetWidth x $targetHeight")
|
||||||
|
|
||||||
|
if (dstWidth != targetWidth || dstHeight != targetHeight) {
|
||||||
|
dstWidth = targetWidth
|
||||||
|
dstHeight = targetHeight
|
||||||
|
rebind()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateDstBuffer() {
|
||||||
|
if (dstBuffer == null || dstBuffer!!.width != dstWidth || dstBuffer!!.height != dstHeight) {
|
||||||
|
dstBuffer?.dispose()
|
||||||
|
dstBuffer = FrameBuffer(Pixmap.Format.RGB888, dstWidth, dstHeight, false)
|
||||||
|
dstBuffer!!.colorBufferTexture.setFilter(
|
||||||
|
Texture.TextureFilter.Nearest,
|
||||||
|
Texture.TextureFilter.Nearest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates a fullscreen quad mesh. Geometry is aligned to the viewport corners.
|
||||||
|
*
|
||||||
|
* @author bmanuel
|
||||||
|
* @author metaphore
|
||||||
|
*/
|
||||||
|
private class ViewportQuadMesh : Disposable {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val VERT_SIZE = 16
|
||||||
|
private const val X1 = 0
|
||||||
|
private const val Y1 = 1
|
||||||
|
private const val U1 = 2
|
||||||
|
private const val V1 = 3
|
||||||
|
private const val X2 = 4
|
||||||
|
private const val Y2 = 5
|
||||||
|
private const val U2 = 6
|
||||||
|
private const val V2 = 7
|
||||||
|
private const val X3 = 8
|
||||||
|
private const val Y3 = 9
|
||||||
|
private const val U3 = 10
|
||||||
|
private const val V3 = 11
|
||||||
|
private const val X4 = 12
|
||||||
|
private const val Y4 = 13
|
||||||
|
private const val U4 = 14
|
||||||
|
private const val V4 = 15
|
||||||
|
|
||||||
|
private val verts: FloatArray
|
||||||
|
|
||||||
|
init {
|
||||||
|
verts = FloatArray(VERT_SIZE)
|
||||||
|
|
||||||
|
// Vertex coords
|
||||||
|
verts[X1] = -1f
|
||||||
|
verts[Y1] = -1f
|
||||||
|
verts[X2] = 1f
|
||||||
|
verts[Y2] = -1f
|
||||||
|
verts[X3] = 1f
|
||||||
|
verts[Y3] = 1f
|
||||||
|
verts[X4] = -1f
|
||||||
|
verts[Y4] = 1f
|
||||||
|
|
||||||
|
// Tex coords
|
||||||
|
verts[U1] = 0f
|
||||||
|
verts[V1] = 0f
|
||||||
|
verts[U2] = 1f
|
||||||
|
verts[V2] = 0f
|
||||||
|
verts[U3] = 1f
|
||||||
|
verts[V3] = 1f
|
||||||
|
verts[U4] = 0f
|
||||||
|
verts[V4] = 1f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val mesh: Mesh
|
||||||
|
|
||||||
|
constructor(vararg attributes: VertexAttribute) {
|
||||||
|
mesh = Mesh(true, 4, 0, *attributes)
|
||||||
|
mesh.setVertices(verts)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
mesh.dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Renders the quad with the specified shader program. */
|
||||||
|
fun render(program: ShaderProgram) {
|
||||||
|
mesh.render(program, GL20.GL_TRIANGLE_FAN, 0, 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun compileShader(vertexFile: FileHandle, fragmentFile: FileHandle, defines: String): ShaderProgram {
|
||||||
|
val sb = StringBuilder()
|
||||||
|
sb.append("Compiling \"").append(vertexFile.name()).append('/').append(fragmentFile.name()).append('\"')
|
||||||
|
if (defines.isNotEmpty()) {
|
||||||
|
sb.append(" w/ (").append(defines.replace("\n", ", ")).append(")")
|
||||||
|
}
|
||||||
|
sb.append("...")
|
||||||
|
Gdx.app.log("HqnxEffect", sb.toString())
|
||||||
|
|
||||||
|
val srcVert = vertexFile.readString()
|
||||||
|
val srcFrag = fragmentFile.readString()
|
||||||
|
val shader = ShaderProgram(
|
||||||
|
"$defines\n$srcVert".trimIndent(),
|
||||||
|
"$defines\n$srcFrag".trimIndent())
|
||||||
|
|
||||||
|
if (!shader.isCompiled) {
|
||||||
|
throw GdxRuntimeException("Shader compilation error: ${vertexFile.name()}/${fragmentFile.name()}\n${shader.log}")
|
||||||
|
}
|
||||||
|
return shader
|
||||||
|
}
|
||||||
@@ -32,6 +32,7 @@ import java.nio.file.StandardCopyOption
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.locks.Lock
|
import java.util.concurrent.locks.Lock
|
||||||
import java.util.function.Consumer
|
import java.util.function.Consumer
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Although the game (as product) can have infinitely many stages/planets/etc., those stages must be manually managed by YOU;
|
* Although the game (as product) can have infinitely many stages/planets/etc., those stages must be manually managed by YOU;
|
||||||
@@ -64,7 +65,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
|||||||
lateinit var playerDisk: VirtualDisk; internal set
|
lateinit var playerDisk: VirtualDisk; internal set
|
||||||
lateinit var worldSavefileName: String; internal set
|
lateinit var worldSavefileName: String; internal set
|
||||||
lateinit var playerSavefileName: String; internal set
|
lateinit var playerSavefileName: String; internal set
|
||||||
var savegameNickname: String = "SplinesReticulated"; internal set
|
var worldName: String = "SplinesReticulated"; internal set // worldName is stored as a name of the disk
|
||||||
|
|
||||||
var screenZoom = 1.0f
|
var screenZoom = 1.0f
|
||||||
val ZOOM_MAXIMUM = 4.0f
|
val ZOOM_MAXIMUM = 4.0f
|
||||||
@@ -204,13 +205,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
|||||||
actorContainerInactive.forEach { it.dispose() }
|
actorContainerInactive.forEach { it.dispose() }
|
||||||
world.dispose()
|
world.dispose()
|
||||||
|
|
||||||
disposables.forEach(Consumer {
|
disposables.forEach(Consumer { it.tryDispose() })
|
||||||
try { it.dispose() }
|
|
||||||
catch (_: NullPointerException) { }
|
|
||||||
catch (_: IllegalArgumentException) { }
|
|
||||||
catch (_: GdxRuntimeException) { }
|
|
||||||
catch (_: ConcurrentModificationException) { }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////
|
////////////
|
||||||
@@ -490,7 +485,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
|||||||
val dist2 = (p.getOrd(0) - (t.hitbox.centeredX - world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr()
|
val dist2 = (p.getOrd(0) - (t.hitbox.centeredX - world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr()
|
||||||
val dist3 = (p.getOrd(0) - (t.hitbox.centeredX + world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr()
|
val dist3 = (p.getOrd(0) - (t.hitbox.centeredX + world.width * TILE_SIZE)).sqr() + (p.getOrd(1) - t.hitbox.centeredY).sqr()
|
||||||
|
|
||||||
minOf(dist1, dist2, dist3)
|
min(min(dist1, dist2), dist3)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import net.torvald.terrarum.utils.JsonFetcher;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrapper that launches the bundled JVM and injects VM configs such as -Xmx
|
* Bootstrapper that launches the bundled JVM and injects VM configs such as -Xmx
|
||||||
@@ -25,7 +24,6 @@ public class Principii {
|
|||||||
/** defaultDir + "/config.json" */
|
/** defaultDir + "/config.json" */
|
||||||
private static String configDir;
|
private static String configDir;
|
||||||
|
|
||||||
|
|
||||||
public static void getDefaultDirRoot() {
|
public static void getDefaultDirRoot() {
|
||||||
String OS = OSName.toUpperCase();
|
String OS = OSName.toUpperCase();
|
||||||
if (OS.contains("WIN")) {
|
if (OS.contains("WIN")) {
|
||||||
@@ -63,7 +61,7 @@ public class Principii {
|
|||||||
devMode = true;
|
devMode = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
String extracmd = devMode ? " -ea" : "";
|
String extracmd0 = devMode ? " -ea" : "";
|
||||||
String OS = OSName.toUpperCase();
|
String OS = OSName.toUpperCase();
|
||||||
String CPUARCH = System.getProperty("os.arch").toUpperCase();
|
String CPUARCH = System.getProperty("os.arch").toUpperCase();
|
||||||
String runtimeRoot;
|
String runtimeRoot;
|
||||||
@@ -82,14 +80,14 @@ public class Principii {
|
|||||||
}
|
}
|
||||||
else if (OS.contains("OS X") || OS.contains("MACOS")) { // OpenJDK for mac will still report "Mac OS X" with version number "10.16", even on Big Sur and beyond
|
else if (OS.contains("OS X") || OS.contains("MACOS")) { // OpenJDK for mac will still report "Mac OS X" with version number "10.16", even on Big Sur and beyond
|
||||||
runtimeRoot = "runtime-osx-" + runtimeArch;
|
runtimeRoot = "runtime-osx-" + runtimeArch;
|
||||||
extracmd += " -XstartOnFirstThread";
|
extracmd0 += " -XstartOnFirstThread";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
runtimeRoot = "runtime-linux-" + runtimeArch;
|
runtimeRoot = "runtime-linux-" + runtimeArch;
|
||||||
extracmd += " -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd";
|
extracmd0 += " -Dswing.aatext=true -Dawt.useSystemAAFontSettings=lcd";
|
||||||
}
|
}
|
||||||
|
|
||||||
String runtime = new File("out/"+runtimeRoot+"/bin/java").getAbsolutePath();
|
String runtime = new File("out/"+runtimeRoot+"/bin/Terrarum").getAbsolutePath(); // /bin/Terrarum is just a renamed version of /bin/java
|
||||||
System.out.println("Runtime path: "+runtime);
|
System.out.println("Runtime path: "+runtime);
|
||||||
|
|
||||||
|
|
||||||
@@ -102,13 +100,27 @@ public class Principii {
|
|||||||
|
|
||||||
|
|
||||||
int xmx = getConfigInt("jvm_xmx");
|
int xmx = getConfigInt("jvm_xmx");
|
||||||
String userDefinedExtraCmd = getConfigString("jvm_extra_cmd").trim();
|
String userDefinedExtraCmd0 = getConfigString("jvm_extra_cmd").trim();
|
||||||
if (!userDefinedExtraCmd.isEmpty()) userDefinedExtraCmd = " "+userDefinedExtraCmd;
|
if (!userDefinedExtraCmd0.isEmpty()) userDefinedExtraCmd0 = " "+userDefinedExtraCmd0;
|
||||||
|
|
||||||
|
// String[] cmd = (runtime+extracmd0+userDefinedExtraCmd0+" -Xms1G -Xmx"+xmx+"G -cp ./out/TerrarumBuild.jar net.torvald.terrarum.App").split(" ");
|
||||||
|
|
||||||
|
List<String> extracmds = Arrays.stream(extracmd0.split(" ")).toList();
|
||||||
|
List<String> userDefinedExtraCmds = Arrays.stream(userDefinedExtraCmd0.split(" +")).filter((it) -> !it.isBlank()).toList();
|
||||||
|
ArrayList<String> cmd0 = new ArrayList<>();
|
||||||
|
cmd0.add(runtime);
|
||||||
|
cmd0.addAll(extracmds);
|
||||||
|
cmd0.addAll(userDefinedExtraCmds);
|
||||||
|
cmd0.add("-Xms1G");
|
||||||
|
cmd0.add("-Xmx"+xmx+"G");
|
||||||
|
cmd0.add("-cp");
|
||||||
|
cmd0.add("./out/TerrarumBuild.jar");
|
||||||
|
cmd0.add("net.torvald.terrarum.App");
|
||||||
|
var cmd = cmd0.stream().filter((it) -> !it.isBlank()).toList();
|
||||||
|
|
||||||
|
System.out.println(cmd);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String[] cmd = (runtime+extracmd+userDefinedExtraCmd+" -Xms1G -Xmx"+xmx+"G -cp ./out/TerrarumBuild.jar net.torvald.terrarum.App").split(" ");
|
|
||||||
ProcessBuilder pb = new ProcessBuilder(cmd);
|
ProcessBuilder pb = new ProcessBuilder(cmd);
|
||||||
pb.inheritIO();
|
pb.inheritIO();
|
||||||
System.exit(pb.start().waitFor());
|
System.exit(pb.start().waitFor());
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package net.torvald.terrarum.modulebasegame
|
package net.torvald.terrarum
|
||||||
|
|
||||||
import net.torvald.random.HQRNG
|
import net.torvald.random.HQRNG
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -9,6 +9,7 @@ import com.jme3.math.FastMath
|
|||||||
import net.torvald.terrarum.langpack.Lang
|
import net.torvald.terrarum.langpack.Lang
|
||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||||
import net.torvald.terrarum.ui.Toolkit
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2017-07-13.
|
* Created by minjaesong on 2017-07-13.
|
||||||
@@ -46,7 +47,7 @@ object SanicLoadScreen : LoadScreenBase() {
|
|||||||
|
|
||||||
textFbo = FrameBuffer(
|
textFbo = FrameBuffer(
|
||||||
Pixmap.Format.RGBA4444,
|
Pixmap.Format.RGBA4444,
|
||||||
maxOf(
|
max(
|
||||||
App.fontGame.getWidth(Lang["MENU_IO_LOADING"]),
|
App.fontGame.getWidth(Lang["MENU_IO_LOADING"]),
|
||||||
App.fontGame.getWidth(Lang["ERROR_GENERIC_TEXT"])
|
App.fontGame.getWidth(Lang["ERROR_GENERIC_TEXT"])
|
||||||
),
|
),
|
||||||
@@ -61,7 +62,7 @@ object SanicLoadScreen : LoadScreenBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
val textX: Float; get() = (App.scr.width * 0.72f).floor()
|
val textX: Float; get() = (App.scr.width * 0.72f).floorToFloat()
|
||||||
|
|
||||||
private var genuineSonic = false // the "NOW LOADING..." won't appear unless the arrow first run passes it
|
private var genuineSonic = false // the "NOW LOADING..." won't appear unless the arrow first run passes it
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,27 @@
|
|||||||
package net.torvald.terrarum
|
package net.torvald.terrarum
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
|
import com.badlogic.gdx.graphics.Texture
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||||
|
import com.badlogic.gdx.utils.JsonWriter
|
||||||
import net.torvald.terrarum.App.printdbg
|
import net.torvald.terrarum.App.printdbg
|
||||||
import net.torvald.terrarum.savegame.DiskSkimmer
|
import net.torvald.terrarum.gameactors.AVKey
|
||||||
|
import net.torvald.terrarum.savegame.*
|
||||||
|
import net.torvald.terrarum.savegame.VDFileID.PLAYER_SCREENSHOT
|
||||||
|
import net.torvald.terrarum.savegame.VDFileID.ROOT
|
||||||
|
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
|
||||||
|
import net.torvald.terrarum.savegame.VDFileID.WORLD_SCREENSHOT
|
||||||
|
import net.torvald.terrarum.serialise.Common
|
||||||
|
import net.torvald.terrarum.utils.JsonFetcher
|
||||||
|
import net.torvald.terrarum.utils.forEachSiblings
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.StandardCopyOption
|
import java.nio.file.StandardCopyOption
|
||||||
|
import java.util.*
|
||||||
|
import java.util.zip.GZIPInputStream
|
||||||
import kotlin.io.path.Path
|
import kotlin.io.path.Path
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by minjaesong on 2023-06-24.
|
* Created by minjaesong on 2023-06-24.
|
||||||
@@ -14,7 +29,7 @@ import kotlin.io.path.Path
|
|||||||
class SavegameCollection(files0: List<DiskSkimmer>) {
|
class SavegameCollection(files0: List<DiskSkimmer>) {
|
||||||
|
|
||||||
/** Sorted in reverse by the last modified time of the files, index zero being the most recent */
|
/** Sorted in reverse by the last modified time of the files, index zero being the most recent */
|
||||||
val files = files0.sortedByDescending {
|
val files = files0.sortedBy { it.diskFile.name }.sortedByDescending {
|
||||||
it.getLastModifiedTime().shl(2) or
|
it.getLastModifiedTime().shl(2) or
|
||||||
it.diskFile.extension.matches(Regex("^[abc]${'$'}")).toLong(1) or
|
it.diskFile.extension.matches(Regex("^[abc]${'$'}")).toLong(1) or
|
||||||
it.diskFile.extension.isBlank().toLong(0)
|
it.diskFile.extension.isBlank().toLong(0)
|
||||||
@@ -57,22 +72,161 @@ class SavegameCollection(files0: List<DiskSkimmer>) {
|
|||||||
fun getBaseFile(): DiskSkimmer {
|
fun getBaseFile(): DiskSkimmer {
|
||||||
return files.first { it.diskFile.extension.isBlank() }
|
return files.first { it.diskFile.extension.isBlank() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getUUID(): UUID {
|
||||||
|
var uuid: UUID? = null
|
||||||
|
loadable().getFile(SAVEGAMEINFO)!!.let {
|
||||||
|
JsonFetcher.readFromJsonString(ByteArray64Reader(it.bytes, Common.CHARSET)).forEachSiblings { name, value ->
|
||||||
|
if (name == "worldIndex" || name == "uuid") uuid = UUID.fromString(value.asString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uuid!!
|
||||||
|
}
|
||||||
|
|
||||||
|
fun renamePlayer(name: String) {
|
||||||
|
files.forEach { skimmer ->
|
||||||
|
skimmer.rebuild()
|
||||||
|
skimmer.getFile(SAVEGAMEINFO)!!.let { file ->
|
||||||
|
val json = JsonFetcher.readFromJsonString(ByteArray64Reader(file.bytes, Common.CHARSET))
|
||||||
|
|
||||||
|
json["actorValue"]["hashMap"]["name"]["value"].set(name) // getChild() does NOT work as [] does
|
||||||
|
|
||||||
|
val jsonBytes = json.prettyPrint(JsonWriter.OutputType.json, 0).encodeToByteArray().toByteArray64()
|
||||||
|
val newEntry = DiskEntry(SAVEGAMEINFO, ROOT, skimmer.requestFile(SAVEGAMEINFO)!!.creationDate, App.getTIME_T(), EntryFile(jsonBytes))
|
||||||
|
|
||||||
|
skimmer.appendEntry(newEntry)
|
||||||
|
|
||||||
|
skimmer.setDiskName(name, Common.CHARSET)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun renameWorld(name: String) {
|
||||||
|
files.forEach { skimmer ->
|
||||||
|
skimmer.setDiskName(name, Common.CHARSET)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getThumbnail(width: Int, height: Int, shrinkage: Double) = this.loadable().getThumbnail(width, height, shrinkage)
|
||||||
}
|
}
|
||||||
|
|
||||||
class SavegameCollectionPair(player: SavegameCollection?, world: SavegameCollection?) {
|
fun DiskSkimmer.getTgaGz(vid: EntryID, width: Int, height: Int, shrinkage: Double): TextureRegion? {
|
||||||
|
return this.requestFile(vid).let { file ->
|
||||||
|
if (file != null) {
|
||||||
|
val zippedTga = (file.contents as EntryFile).bytes
|
||||||
|
val gzin = GZIPInputStream(ByteArray64InputStream(zippedTga))
|
||||||
|
val tgaFileContents = gzin.readAllBytes(); gzin.close()
|
||||||
|
val pixmap = Pixmap(tgaFileContents, 0, tgaFileContents.size)
|
||||||
|
TextureRegion(Texture(pixmap)).also {
|
||||||
|
App.disposables.add(it.texture)
|
||||||
|
// do cropping and resizing
|
||||||
|
it.setRegion(
|
||||||
|
((pixmap.width - width*2) / shrinkage).roundToInt(),
|
||||||
|
((pixmap.height - height*2) / shrinkage).roundToInt(),
|
||||||
|
(width * shrinkage).roundToInt(),
|
||||||
|
(height * shrinkage).roundToInt()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun DiskSkimmer.getTgaGzPixmap(vid: EntryID, width: Int, height: Int, shrinkage: Double): Pixmap? {
|
||||||
|
return this.requestFile(vid).let { file ->
|
||||||
|
if (file != null) {
|
||||||
|
val zippedTga = (file.contents as EntryFile).bytes
|
||||||
|
val gzin = GZIPInputStream(ByteArray64InputStream(zippedTga))
|
||||||
|
val tgaFileContents = gzin.readAllBytes(); gzin.close()
|
||||||
|
val pixmap = Pixmap(tgaFileContents, 0, tgaFileContents.size)
|
||||||
|
return pixmap
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun DiskSkimmer.getThumbnail(width: Int, height: Int, shrinkage: Double) =
|
||||||
|
when (this.getSaveKind()) {
|
||||||
|
1 -> this.getTgaGz(PLAYER_SCREENSHOT, width, height, shrinkage)
|
||||||
|
2 -> this.getTgaGz(WORLD_SCREENSHOT, width, height, shrinkage)
|
||||||
|
else -> throw IllegalArgumentException("Unknown save kind: ${this.getSaveKind()}")
|
||||||
|
}
|
||||||
|
fun DiskSkimmer.getThumbnailPixmap(width: Int, height: Int, shrinkage: Double) =
|
||||||
|
when (this.getSaveKind()) {
|
||||||
|
1 -> this.getTgaGzPixmap(PLAYER_SCREENSHOT, width, height, shrinkage)
|
||||||
|
2 -> this.getTgaGzPixmap(WORLD_SCREENSHOT, width, height, shrinkage)
|
||||||
|
else -> throw IllegalArgumentException("Unknown save kind: ${this.getSaveKind()}")
|
||||||
|
}
|
||||||
|
|
||||||
private var manualPlayer: DiskSkimmer? = null
|
class SavegameCollectionPair(private val player: SavegameCollection?, private val world: SavegameCollection?) {
|
||||||
private var manualWorld: DiskSkimmer? = null
|
|
||||||
private var autoPlayer: DiskSkimmer? = null
|
// private var manualPlayer: DiskSkimmer? = null
|
||||||
private var autoWorld: DiskSkimmer? = null
|
// private var manualWorld: DiskSkimmer? = null
|
||||||
|
// private var autoPlayer: DiskSkimmer? = null
|
||||||
|
// private var autoWorld: DiskSkimmer? = null
|
||||||
|
|
||||||
|
/* removing auto/manual discrimination: on Local Asynchronous Multiplayer, if newer autosave is available, there is
|
||||||
|
* no choice but loading one to preserve the data; then why bother having two? */
|
||||||
|
private var playerDisk: DiskSkimmer? = null; private set
|
||||||
|
private var worldDisk: DiskSkimmer? = null; private set
|
||||||
|
|
||||||
var status = 0 // 0: none available, 1: loadable manual save is newer than loadable auto; 2: loadable autosave is newer than loadable manual
|
var status = 0 // 0: none available, 1: loadable manual save is newer than loadable auto; 2: loadable autosave is newer than loadable manual
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var newerSaveIsDamaged = false // only when most recent save is corrupted
|
val newerSaveIsDamaged: Boolean // only when most recent save is corrupted
|
||||||
private set
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
if (player != null && world != null) {
|
||||||
|
printdbg(this, "player files: " + player.files.joinToString { it.diskFile.name })
|
||||||
|
printdbg(this, "world files:" + world.files.joinToString { it.diskFile.name })
|
||||||
|
|
||||||
|
var pc = 0
|
||||||
|
var wc = 0
|
||||||
|
|
||||||
|
playerDisk = player.files[pc]
|
||||||
|
worldDisk = world.files[wc]
|
||||||
|
|
||||||
|
while (pc < player.files.size && wc < world.files.size) {
|
||||||
|
// 0b pw
|
||||||
|
val dmgflag = playerDiskNotDamaged(playerDisk!!).toInt(1) or worldDiskNotDamaged(worldDisk!!).toInt()
|
||||||
|
|
||||||
|
when (dmgflag) {
|
||||||
|
3 -> break
|
||||||
|
2 -> {
|
||||||
|
worldDisk = world.files[++wc]
|
||||||
|
}
|
||||||
|
1 -> {
|
||||||
|
playerDisk = player.files[++pc]
|
||||||
|
}
|
||||||
|
0 -> {
|
||||||
|
worldDisk = world.files[++wc]
|
||||||
|
playerDisk = player.files[++pc]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it's time to exit the loop and all tested saves were damaged:
|
||||||
|
if (pc == player.files.size) playerDisk = null
|
||||||
|
if (wc == world.files.size) worldDisk = null
|
||||||
|
}
|
||||||
|
|
||||||
|
newerSaveIsDamaged = (pc + wc > 0)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newerSaveIsDamaged = false
|
||||||
|
}
|
||||||
|
|
||||||
|
status = if (playerDisk != null && worldDisk != null && (playerDisk!!.isAutosaved() || worldDisk!!.isAutosaved()))
|
||||||
|
2
|
||||||
|
else (player != null && world != null).toInt()
|
||||||
|
|
||||||
|
printdbg(this, "playerDisk = ${playerDisk?.diskFile?.path}")
|
||||||
|
printdbg(this, "worldDisk = ${worldDisk?.diskFile?.path}")
|
||||||
|
printdbg(this, "status = $status")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*init {
|
||||||
printdbg(this, "init ($player, $world)")
|
printdbg(this, "init ($player, $world)")
|
||||||
|
|
||||||
if (player != null && world != null) {
|
if (player != null && world != null) {
|
||||||
@@ -119,11 +273,14 @@ class SavegameCollectionPair(player: SavegameCollection?, world: SavegameCollect
|
|||||||
pc += 1
|
pc += 1
|
||||||
wc += 1
|
wc += 1
|
||||||
}
|
}
|
||||||
else
|
// world is modified after another player playing on the same world but only left an autosave
|
||||||
|
// there is no choice but loading the autosave in such scenario to preserve the data
|
||||||
|
else {
|
||||||
wc += 1
|
wc += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -147,7 +304,7 @@ class SavegameCollectionPair(player: SavegameCollection?, world: SavegameCollect
|
|||||||
printdbg(this, "autoWorld = ${autoWorld?.diskFile?.path}")
|
printdbg(this, "autoWorld = ${autoWorld?.diskFile?.path}")
|
||||||
printdbg(this, "status = $status")
|
printdbg(this, "status = $status")
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
|
|
||||||
private fun DiskSkimmer.isAutosaved() = this.getSaveMode().and(0b0000_0010) != 0
|
private fun DiskSkimmer.isAutosaved() = this.getSaveMode().and(0b0000_0010) != 0
|
||||||
|
|
||||||
@@ -162,7 +319,7 @@ class SavegameCollectionPair(player: SavegameCollection?, world: SavegameCollect
|
|||||||
fun moreRecentAutosaveAvailable() = (status == 2)
|
fun moreRecentAutosaveAvailable() = (status == 2)
|
||||||
fun saveAvaliable() = (status > 0)
|
fun saveAvaliable() = (status > 0)
|
||||||
|
|
||||||
fun getManualSave(): DiskPair? {
|
/*fun getManualSave(): DiskPair? {
|
||||||
if (status == 0) return null
|
if (status == 0) return null
|
||||||
return DiskPair(manualPlayer!!, manualWorld!!)
|
return DiskPair(manualPlayer!!, manualWorld!!)
|
||||||
}
|
}
|
||||||
@@ -178,7 +335,14 @@ class SavegameCollectionPair(player: SavegameCollection?, world: SavegameCollect
|
|||||||
DiskPair(manualPlayer!!, manualWorld!!)
|
DiskPair(manualPlayer!!, manualWorld!!)
|
||||||
else
|
else
|
||||||
DiskPair(autoPlayer!!, autoWorld!!)
|
DiskPair(autoPlayer!!, autoWorld!!)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
fun getLoadableSave(): DiskPair? {
|
||||||
|
return if (status == 0) null
|
||||||
|
else DiskPair(playerDisk!!, worldDisk!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class DiskPair(val player: DiskSkimmer, val world: DiskSkimmer)
|
data class DiskPair(val player: DiskSkimmer, val world: DiskSkimmer) {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
|||||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
import com.badlogic.gdx.graphics.glutils.FrameBuffer
|
||||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer
|
import com.badlogic.gdx.graphics.glutils.ShapeRenderer
|
||||||
import com.badlogic.gdx.utils.Disposable
|
import com.badlogic.gdx.utils.Disposable
|
||||||
import com.badlogic.gdx.utils.JsonReader
|
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||||
import com.jme3.math.FastMath
|
import com.jme3.math.FastMath
|
||||||
import net.torvald.gdx.graphics.Cvec
|
import net.torvald.gdx.graphics.Cvec
|
||||||
import net.torvald.random.HQRNG
|
import net.torvald.random.HQRNG
|
||||||
@@ -26,13 +26,9 @@ import net.torvald.terrarum.gameworld.fmod
|
|||||||
import net.torvald.terrarum.itemproperties.CraftingCodex
|
import net.torvald.terrarum.itemproperties.CraftingCodex
|
||||||
import net.torvald.terrarum.itemproperties.ItemCodex
|
import net.torvald.terrarum.itemproperties.ItemCodex
|
||||||
import net.torvald.terrarum.itemproperties.MaterialCodex
|
import net.torvald.terrarum.itemproperties.MaterialCodex
|
||||||
import net.torvald.terrarum.savegame.ByteArray64Reader
|
|
||||||
import net.torvald.terrarum.savegame.DiskSkimmer
|
import net.torvald.terrarum.savegame.DiskSkimmer
|
||||||
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
|
|
||||||
import net.torvald.terrarum.serialise.Common
|
import net.torvald.terrarum.serialise.Common
|
||||||
import net.torvald.terrarum.ui.UICanvas
|
import net.torvald.terrarum.ui.UICanvas
|
||||||
import net.torvald.terrarum.utils.JsonFetcher
|
|
||||||
import net.torvald.terrarum.utils.forEachSiblings
|
|
||||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||||
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap
|
import net.torvald.terrarumsansbitmap.gdx.TerrarumSansBitmap
|
||||||
import net.torvald.unsafe.UnsafeHelper
|
import net.torvald.unsafe.UnsafeHelper
|
||||||
@@ -40,10 +36,7 @@ import net.torvald.util.CircularArray
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.*
|
||||||
import kotlin.math.round
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typealias RGBA8888 = Int
|
typealias RGBA8888 = Int
|
||||||
@@ -238,16 +231,16 @@ object Terrarum : Disposable {
|
|||||||
get() = WorldCamera.zoomedY + (Gdx.input.y - Gdx.input.deltaY) / (ingame?.screenZoom ?: 1f).times(scr.magn.toDouble())
|
get() = WorldCamera.zoomedY + (Gdx.input.y - Gdx.input.deltaY) / (ingame?.screenZoom ?: 1f).times(scr.magn.toDouble())
|
||||||
/** Position of the cursor in the world, rounded */
|
/** Position of the cursor in the world, rounded */
|
||||||
@JvmStatic val mouseTileX: Int
|
@JvmStatic val mouseTileX: Int
|
||||||
get() = (mouseX / TILE_SIZE).floorInt()
|
get() = (mouseX / TILE_SIZE).floorToInt()
|
||||||
/** Position of the cursor in the world */
|
/** Position of the cursor in the world */
|
||||||
@JvmStatic val mouseTileY: Int
|
@JvmStatic val mouseTileY: Int
|
||||||
get() = (mouseY / TILE_SIZE).floorInt()
|
get() = (mouseY / TILE_SIZE).floorToInt()
|
||||||
/** Position of the cursor in the world, rounded */
|
/** Position of the cursor in the world, rounded */
|
||||||
@JvmStatic val oldMouseTileX: Int
|
@JvmStatic val oldMouseTileX: Int
|
||||||
get() = (oldMouseX / TILE_SIZE).floorInt()
|
get() = (oldMouseX / TILE_SIZE).floorToInt()
|
||||||
/** Position of the cursor in the world */
|
/** Position of the cursor in the world */
|
||||||
@JvmStatic val oldMouseTileY: Int
|
@JvmStatic val oldMouseTileY: Int
|
||||||
get() = (oldMouseY / TILE_SIZE).floorInt()
|
get() = (oldMouseY / TILE_SIZE).floorToInt()
|
||||||
inline val mouseScreenX: Int
|
inline val mouseScreenX: Int
|
||||||
get() = Gdx.input.x.div(scr.magn).roundToInt()
|
get() = Gdx.input.x.div(scr.magn).roundToInt()
|
||||||
inline val mouseScreenY: Int
|
inline val mouseScreenY: Int
|
||||||
@@ -321,8 +314,8 @@ object Terrarum : Disposable {
|
|||||||
|
|
||||||
val mx = mouseX
|
val mx = mouseX
|
||||||
val my = mouseY
|
val my = mouseY
|
||||||
val mtx = (mouseX / TILE_SIZE).floorInt()
|
val mtx = (mouseX / TILE_SIZE).floorToInt()
|
||||||
val mty = (mouseY / TILE_SIZE).floorInt()
|
val mty = (mouseY / TILE_SIZE).floorToInt()
|
||||||
val msx = mx fmod TILE_SIZED
|
val msx = mx fmod TILE_SIZED
|
||||||
val msy = my fmod TILE_SIZED
|
val msy = my fmod TILE_SIZED
|
||||||
val vector = if (msx < SMALLGAP) { // X to the left
|
val vector = if (msx < SMALLGAP) { // X to the left
|
||||||
@@ -399,8 +392,10 @@ inline fun FrameBuffer.inAction(camera: OrthographicCamera?, batch: SpriteBatch?
|
|||||||
//this.begin()
|
//this.begin()
|
||||||
FrameBufferManager.begin(this)
|
FrameBufferManager.begin(this)
|
||||||
|
|
||||||
|
val oldCamPos = camera?.position?.cpy()
|
||||||
|
|
||||||
camera?.setToOrtho(true, this.width.toFloat(), this.height.toFloat())
|
camera?.setToOrtho(true, this.width.toFloat(), this.height.toFloat())
|
||||||
camera?.position?.set((this.width / 2f).round(), (this.height / 2f).round(), 0f) // TODO floor? ceil? round?
|
camera?.position?.set((this.width / 2f).roundToFloat(), (this.height / 2f).roundToFloat(), 0f) // TODO floor? ceil? round?
|
||||||
camera?.update()
|
camera?.update()
|
||||||
batch?.projectionMatrix = camera?.combined
|
batch?.projectionMatrix = camera?.combined
|
||||||
|
|
||||||
@@ -410,6 +405,7 @@ inline fun FrameBuffer.inAction(camera: OrthographicCamera?, batch: SpriteBatch?
|
|||||||
FrameBufferManager.end()
|
FrameBufferManager.end()
|
||||||
|
|
||||||
camera?.setToOrtho(true, App.scr.wf, App.scr.hf)
|
camera?.setToOrtho(true, App.scr.wf, App.scr.hf)
|
||||||
|
camera?.position?.set(oldCamPos)
|
||||||
camera?.update()
|
camera?.update()
|
||||||
batch?.projectionMatrix = camera?.combined
|
batch?.projectionMatrix = camera?.combined
|
||||||
}
|
}
|
||||||
@@ -421,8 +417,10 @@ inline fun FrameBuffer.inActionF(camera: OrthographicCamera?, batch: SpriteBatch
|
|||||||
//this.begin()
|
//this.begin()
|
||||||
FrameBufferManager.begin(this)
|
FrameBufferManager.begin(this)
|
||||||
|
|
||||||
|
val oldCamPos = camera?.position?.cpy()
|
||||||
|
|
||||||
camera?.setToOrtho(false, this.width.toFloat(), this.height.toFloat())
|
camera?.setToOrtho(false, this.width.toFloat(), this.height.toFloat())
|
||||||
camera?.position?.set((this.width / 2f).round(), (this.height / 2f).round(), 0f) // TODO floor? ceil? round?
|
camera?.position?.set((this.width / 2f).roundToFloat(), (this.height / 2f).roundToFloat(), 0f) // TODO floor? ceil? round?
|
||||||
camera?.update()
|
camera?.update()
|
||||||
batch?.projectionMatrix = camera?.combined
|
batch?.projectionMatrix = camera?.combined
|
||||||
|
|
||||||
@@ -432,6 +430,7 @@ inline fun FrameBuffer.inActionF(camera: OrthographicCamera?, batch: SpriteBatch
|
|||||||
FrameBufferManager.end()
|
FrameBufferManager.end()
|
||||||
|
|
||||||
camera?.setToOrtho(true, App.scr.wf, App.scr.hf)
|
camera?.setToOrtho(true, App.scr.wf, App.scr.hf)
|
||||||
|
camera?.position?.set(oldCamPos)
|
||||||
camera?.update()
|
camera?.update()
|
||||||
batch?.projectionMatrix = camera?.combined
|
batch?.projectionMatrix = camera?.combined
|
||||||
}
|
}
|
||||||
@@ -611,28 +610,28 @@ val emphVerb = TerrarumSansBitmap.toColorCode(0xFFF6)
|
|||||||
|
|
||||||
typealias Second = Float
|
typealias Second = Float
|
||||||
|
|
||||||
fun Int.sqr(): Int = this * this
|
inline fun Double.floorToInt() = floor(this).toInt()
|
||||||
fun Double.floorInt() = Math.floor(this).toInt()
|
inline fun Float.floorToInt() = FastMath.floor(this)
|
||||||
fun Float.floorInt() = FastMath.floor(this)
|
inline fun Double.ceilToInt() = Math.ceil(this).toInt()
|
||||||
fun Float.floor() = FastMath.floor(this).toFloat()
|
inline fun Float.ceilToFloat(): Float = FastMath.ceil(this).toFloat()
|
||||||
fun Double.ceilInt() = Math.ceil(this).toInt()
|
inline fun Float.ceilToInt() = FastMath.ceil(this)
|
||||||
fun Float.ceil(): Float = FastMath.ceil(this).toFloat()
|
inline fun Float.floorToFloat() = FastMath.floor(this).toFloat()
|
||||||
fun Float.ceilInt() = FastMath.ceil(this)
|
inline fun Float.roundToFloat(): Float = round(this)
|
||||||
fun Float.round(): Float = round(this)
|
//inline fun Double.round() = Math.round(this).toDouble()
|
||||||
fun Double.round() = Math.round(this).toDouble()
|
inline fun Double.floorToDouble() = floor(this)
|
||||||
fun Double.floor() = Math.floor(this)
|
inline fun Double.ceilToDouble() = ceil(this)
|
||||||
fun Double.ceil() = this.floor() + 1.0
|
inline fun Int.sqr(): Int = this * this
|
||||||
fun Double.abs() = Math.abs(this)
|
inline fun Double.sqr() = this * this
|
||||||
fun Double.sqr() = this * this
|
inline fun Float.sqr() = this * this
|
||||||
fun Float.sqr() = this * this
|
inline fun Double.sqrt() = Math.sqrt(this)
|
||||||
fun Double.sqrt() = Math.sqrt(this)
|
inline fun Float.sqrt() = FastMath.sqrt(this)
|
||||||
fun Float.sqrt() = FastMath.sqrt(this)
|
inline fun Int.abs() = this.absoluteValue
|
||||||
fun Int.abs() = this.absoluteValue
|
inline fun Double.abs() = this.absoluteValue
|
||||||
fun Double.bipolarClamp(limit: Double) = this.coerceIn(-limit, limit)
|
inline fun Double.bipolarClamp(limit: Double) = this.coerceIn(-limit, limit)
|
||||||
fun Boolean.toInt(shift: Int = 0) = if (this) 1.shl(shift) else 0
|
inline fun Boolean.toInt(shift: Int = 0) = if (this) 1.shl(shift) else 0
|
||||||
fun Boolean.toLong(shift: Int = 0) = if (this) 1L.shl(shift) else 0L
|
inline fun Boolean.toLong(shift: Int = 0) = if (this) 1L.shl(shift) else 0L
|
||||||
fun Int.bitCount() = java.lang.Integer.bitCount(this)
|
inline fun Int.bitCount() = java.lang.Integer.bitCount(this)
|
||||||
fun Long.bitCount() = java.lang.Long.bitCount(this)
|
inline fun Long.bitCount() = java.lang.Long.bitCount(this)
|
||||||
|
|
||||||
|
|
||||||
fun absMax(left: Double, right: Double): Double {
|
fun absMax(left: Double, right: Double): Double {
|
||||||
@@ -651,7 +650,6 @@ fun absMax(left: Double, right: Double): Double {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Double.magnSqr() = if (this >= 0.0) this.sqr() else -this.sqr()
|
fun Double.magnSqr() = if (this >= 0.0) this.sqr() else -this.sqr()
|
||||||
fun Double.sign() = if (this > 0.0) 1.0 else if (this < 0.0) -1.0 else 0.0
|
|
||||||
fun interpolateLinear(scale: Double, startValue: Double, endValue: Double): Double {
|
fun interpolateLinear(scale: Double, startValue: Double, endValue: Double): Double {
|
||||||
if (startValue == endValue) {
|
if (startValue == endValue) {
|
||||||
return startValue
|
return startValue
|
||||||
@@ -788,6 +786,7 @@ fun AppUpdateListOfSavegames() {
|
|||||||
|
|
||||||
println("Listing saved worlds...")
|
println("Listing saved worlds...")
|
||||||
|
|
||||||
|
|
||||||
// create list of worlds
|
// create list of worlds
|
||||||
File(worldsDir).listFiles().filter { !it.isDirectory && !it.name.contains('.') }.mapNotNull { file ->
|
File(worldsDir).listFiles().filter { !it.isDirectory && !it.name.contains('.') }.mapNotNull { file ->
|
||||||
try {
|
try {
|
||||||
@@ -800,17 +799,20 @@ fun AppUpdateListOfSavegames() {
|
|||||||
}
|
}
|
||||||
}.sortedByDescending { it.getLastModifiedTime() }.forEachIndexed { index, it ->
|
}.sortedByDescending { it.getLastModifiedTime() }.forEachIndexed { index, it ->
|
||||||
println("${index+1}.\t${it.diskFile.absolutePath}")
|
println("${index+1}.\t${it.diskFile.absolutePath}")
|
||||||
it.rebuild()
|
// it.rebuild()
|
||||||
|
|
||||||
val jsonFile = it.getFile(SAVEGAMEINFO)!!
|
// val jsonFile = it.getFile(SAVEGAMEINFO)!!
|
||||||
var worldUUID: UUID? = null
|
// var worldUUID: UUID? = null
|
||||||
JsonFetcher.readFromJsonString(ByteArray64Reader(jsonFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
|
// JsonFetcher.readFromJsonString(ByteArray64Reader(jsonFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
|
||||||
if (name == "worldIndex") worldUUID = UUID.fromString(value.asString())
|
// if (name == "worldIndex") worldUUID = UUID.fromString(value.asString())
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
val collection = SavegameCollection.collectFromBaseFilename(File(worldsDir), it.diskFile.name)
|
||||||
|
val worldUUID = collection.getUUID()
|
||||||
|
|
||||||
// if multiple valid savegames with same UUID exist, only the most recent one is retained
|
// if multiple valid savegames with same UUID exist, only the most recent one is retained
|
||||||
if (!App.savegameWorlds.contains(worldUUID)) {
|
if (!App.savegameWorlds.contains(worldUUID)) {
|
||||||
App.savegameWorlds[worldUUID] = SavegameCollection.collectFromBaseFilename(File(worldsDir), it.diskFile.name)
|
App.savegameWorlds[worldUUID] = collection
|
||||||
App.savegameWorldsName[worldUUID] = it.getDiskName(Common.CHARSET)
|
App.savegameWorldsName[worldUUID] = it.getDiskName(Common.CHARSET)
|
||||||
App.sortedSavegameWorlds.add(worldUUID)
|
App.sortedSavegameWorlds.add(worldUUID)
|
||||||
}
|
}
|
||||||
@@ -832,22 +834,30 @@ fun AppUpdateListOfSavegames() {
|
|||||||
}
|
}
|
||||||
}.sortedByDescending { it.getLastModifiedTime() }.forEachIndexed { index, it ->
|
}.sortedByDescending { it.getLastModifiedTime() }.forEachIndexed { index, it ->
|
||||||
println("${index+1}.\t${it.diskFile.absolutePath}")
|
println("${index+1}.\t${it.diskFile.absolutePath}")
|
||||||
it.rebuild()
|
// it.rebuild()
|
||||||
|
|
||||||
val jsonFile = it.getFile(SAVEGAMEINFO)!!
|
// val jsonFile = it.getFile(SAVEGAMEINFO)!!
|
||||||
var playerUUID: UUID? = null
|
// var playerUUID: UUID? = null
|
||||||
JsonFetcher.readFromJsonString(ByteArray64Reader(jsonFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
|
// JsonFetcher.readFromJsonString(ByteArray64Reader(jsonFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
|
||||||
if (name == "uuid") playerUUID = UUID.fromString(value.asString())
|
// if (name == "uuid") playerUUID = UUID.fromString(value.asString())
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
val collection = SavegameCollection.collectFromBaseFilename(File(playersDir), it.diskFile.name)
|
||||||
|
val playerUUID = collection.getUUID()
|
||||||
|
|
||||||
// if multiple valid savegames with same UUID exist, only the most recent one is retained
|
// if multiple valid savegames with same UUID exist, only the most recent one is retained
|
||||||
if (!App.savegamePlayers.contains(playerUUID)) {
|
if (!App.savegamePlayers.contains(playerUUID)) {
|
||||||
App.savegamePlayers[playerUUID] = SavegameCollection.collectFromBaseFilename(File(playersDir), it.diskFile.name)
|
App.savegamePlayers[playerUUID] = collection
|
||||||
App.savegamePlayersName[playerUUID] = it.getDiskName(Common.CHARSET)
|
App.savegamePlayersName[playerUUID] = it.getDiskName(Common.CHARSET)
|
||||||
App.sortedPlayers.add(playerUUID)
|
App.sortedPlayers.add(playerUUID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println("SortedPlayers...")
|
||||||
|
App.sortedPlayers.forEach {
|
||||||
|
println(it)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -887,3 +897,11 @@ fun checkForSavegameDamage(skimmer: DiskSkimmer): Boolean {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No lateinit!
|
||||||
|
*/
|
||||||
|
inline fun Disposable.tryDispose() {
|
||||||
|
try { this.dispose() }
|
||||||
|
catch (_: Throwable) {}
|
||||||
|
}
|
||||||
@@ -62,9 +62,12 @@ basegame
|
|||||||
* e.g. 0x02010034 will be translated as 2.1.52
|
* e.g. 0x02010034 will be translated as 2.1.52
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const val VERSION_RAW: Long = 0x0000_000003_000002
|
const val VERSION_RAW: Long = 0x0000_000003_000003
|
||||||
// Commit counts up to the Release 0.3.0: 2259
|
// Commit counts up to the Release 0.3.0: 2259
|
||||||
// Commit counts up to the Release 0.3.1: 2278
|
// Commit counts up to the Release 0.3.1: 2278
|
||||||
|
// Commit counts up to the Release 0.3.2: 2732
|
||||||
|
|
||||||
|
const val VERSION_TAG: String = "test001"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////
|
||||||
// CONFIGURATION FOR TILE MAKER //
|
// CONFIGURATION FOR TILE MAKER //
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.badlogic.gdx.math.Matrix4
|
|||||||
import com.badlogic.gdx.utils.Disposable
|
import com.badlogic.gdx.utils.Disposable
|
||||||
import com.jme3.math.FastMath
|
import com.jme3.math.FastMath
|
||||||
import net.torvald.random.HQRNG
|
import net.torvald.random.HQRNG
|
||||||
|
import net.torvald.terrarum.App.IS_DEVELOPMENT_BUILD
|
||||||
import net.torvald.terrarum.gamecontroller.KeyToggler
|
import net.torvald.terrarum.gamecontroller.KeyToggler
|
||||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow
|
import net.torvald.terrarum.ui.BasicDebugInfoWindow
|
||||||
import net.torvald.terrarum.ui.Toolkit
|
import net.torvald.terrarum.ui.Toolkit
|
||||||
@@ -63,7 +64,7 @@ object TerrarumPostProcessor : Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun resize(w: Int, h: Int) {
|
fun resize(w: Int, h: Int) {
|
||||||
try { outFBO.dispose() } catch (_: UninitializedPropertyAccessException) {}
|
if (::outFBO.isInitialized) outFBO.tryDispose()
|
||||||
outFBO = FrameBuffer(Pixmap.Format.RGBA8888, w, h, false)
|
outFBO = FrameBuffer(Pixmap.Format.RGBA8888, w, h, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,10 +72,10 @@ object TerrarumPostProcessor : Disposable {
|
|||||||
batch.dispose()
|
batch.dispose()
|
||||||
shapeRenderer.dispose()
|
shapeRenderer.dispose()
|
||||||
functionRowHelper.dispose()
|
functionRowHelper.dispose()
|
||||||
try { lutTex.dispose() } catch (_: UninitializedPropertyAccessException) {}
|
|
||||||
shaderPostDither.dispose()
|
shaderPostDither.dispose()
|
||||||
shaderPostNoDither.dispose()
|
shaderPostNoDither.dispose()
|
||||||
outFBO.dispose()
|
if (::lutTex.isInitialized) lutTex.tryDispose()
|
||||||
|
if (::outFBO.isInitialized) outFBO.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var deltatBenchStr = "ΔF: Gathering data"
|
private var deltatBenchStr = "ΔF: Gathering data"
|
||||||
@@ -150,9 +151,10 @@ object TerrarumPostProcessor : Disposable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// draw dev build notifiers
|
// draw dev build notifiers
|
||||||
if (App.IS_DEVELOPMENT_BUILD && Terrarum.ingame != null) {
|
// omitting this screws up HQ2X render for some reason
|
||||||
|
if (Terrarum.ingame != null) {
|
||||||
batch.inUse {
|
batch.inUse {
|
||||||
batch.color = safeAreaCol
|
batch.color = if (IS_DEVELOPMENT_BUILD) safeAreaCol else colourNull
|
||||||
App.fontGame.draw(it, thisIsDebugStr, 5f, App.scr.height - 24f)
|
App.fontGame.draw(it, thisIsDebugStr, 5f, App.scr.height - 24f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,11 +170,11 @@ object TerrarumPostProcessor : Disposable {
|
|||||||
val average = tallies.average()
|
val average = tallies.average()
|
||||||
|
|
||||||
val halfPos = 0.5f * INGAME.deltaTeeBenchmarks.size
|
val halfPos = 0.5f * INGAME.deltaTeeBenchmarks.size
|
||||||
val halfInd = halfPos.floorInt()
|
val halfInd = halfPos.floorToInt()
|
||||||
val low5pos = 0.05f * INGAME.deltaTeeBenchmarks.size
|
val low5pos = 0.05f * INGAME.deltaTeeBenchmarks.size
|
||||||
val low5ind = low5pos.floorInt()
|
val low5ind = low5pos.floorToInt()
|
||||||
val low1pos = 0.01f * INGAME.deltaTeeBenchmarks.size
|
val low1pos = 0.01f * INGAME.deltaTeeBenchmarks.size
|
||||||
val low1ind = low1pos.floorInt()
|
val low1ind = low1pos.floorToInt()
|
||||||
|
|
||||||
val median = FastMath.interpolateLinear(halfPos - halfInd, tallies[halfInd], tallies[halfInd + 1])
|
val median = FastMath.interpolateLinear(halfPos - halfInd, tallies[halfInd], tallies[halfInd + 1])
|
||||||
val low5 = FastMath.interpolateLinear(low5pos - low5ind, tallies[low5ind], tallies[low5ind + 1])
|
val low5 = FastMath.interpolateLinear(low5pos - low5ind, tallies[low5ind], tallies[low5ind + 1])
|
||||||
@@ -192,39 +194,40 @@ object TerrarumPostProcessor : Disposable {
|
|||||||
return outFBO
|
return outFBO
|
||||||
}
|
}
|
||||||
private val rng = HQRNG()
|
private val rng = HQRNG()
|
||||||
|
private val colourNull = Color(0)
|
||||||
|
|
||||||
private fun Double.format(digits: Int) = "%.${digits}f".format(this)
|
private fun Double.format(digits: Int) = "%.${digits}f".format(this)
|
||||||
private fun Float.format(digits: Int) = "%.${digits}f".format(this)
|
private fun Float.format(digits: Int) = "%.${digits}f".format(this)
|
||||||
|
|
||||||
private val swizzler = intArrayOf(
|
private val swizzler = floatArrayOf(
|
||||||
1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1,
|
1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f,
|
||||||
1,0,0,0, 0,1,0,0, 0,0,0,1, 0,0,1,0,
|
1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f, 0f,0f,1f,0f,
|
||||||
1,0,0,0, 0,0,1,0, 0,1,0,0, 0,0,0,1,
|
1f,0f,0f,0f, 0f,0f,1f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f,
|
||||||
1,0,0,0, 0,0,1,0, 0,0,0,1, 0,1,0,0,
|
1f,0f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f, 0f,1f,0f,0f,
|
||||||
1,0,0,0, 0,0,0,1, 0,1,0,0, 0,0,1,0,
|
1f,0f,0f,0f, 0f,0f,0f,1f, 0f,1f,0f,0f, 0f,0f,1f,0f,
|
||||||
1,0,0,0, 0,0,0,1, 0,0,1,0, 0,1,0,0,
|
1f,0f,0f,0f, 0f,0f,0f,1f, 0f,0f,1f,0f, 0f,1f,0f,0f,
|
||||||
|
|
||||||
0,1,0,0, 1,0,0,0, 0,0,1,0, 0,0,0,1,
|
0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f,
|
||||||
0,1,0,0, 1,0,0,0, 0,0,0,1, 0,0,1,0,
|
0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,0f,1f, 0f,0f,1f,0f,
|
||||||
0,1,0,0, 0,0,1,0, 1,0,0,0, 0,0,0,1,
|
0f,1f,0f,0f, 0f,0f,1f,0f, 1f,0f,0f,0f, 0f,0f,0f,1f,
|
||||||
0,1,0,0, 0,0,1,0, 0,0,0,1, 1,0,0,0,
|
0f,1f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f, 1f,0f,0f,0f,
|
||||||
0,1,0,0, 0,0,0,1, 1,0,0,0, 0,0,1,0,
|
0f,1f,0f,0f, 0f,0f,0f,1f, 1f,0f,0f,0f, 0f,0f,1f,0f,
|
||||||
0,1,0,0, 0,0,0,1, 0,0,1,0, 1,0,0,0,
|
0f,1f,0f,0f, 0f,0f,0f,1f, 0f,0f,1f,0f, 1f,0f,0f,0f,
|
||||||
|
|
||||||
0,0,1,0, 1,0,0,0, 0,1,0,0, 0,0,0,1,
|
0f,0f,1f,0f, 1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f,
|
||||||
0,0,1,0, 1,0,0,0, 0,0,0,1, 0,1,0,0,
|
0f,0f,1f,0f, 1f,0f,0f,0f, 0f,0f,0f,1f, 0f,1f,0f,0f,
|
||||||
0,0,1,0, 0,1,0,0, 1,0,0,0, 0,0,0,1,
|
0f,0f,1f,0f, 0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,0f,1f,
|
||||||
0,0,1,0, 0,1,0,0, 0,0,0,1, 1,0,0,0,
|
0f,0f,1f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f, 1f,0f,0f,0f,
|
||||||
0,0,1,0, 0,0,0,1, 1,0,0,0, 0,1,0,0,
|
0f,0f,1f,0f, 0f,0f,0f,1f, 1f,0f,0f,0f, 0f,1f,0f,0f,
|
||||||
0,0,1,0, 0,0,0,1, 0,1,0,0, 1,0,0,0,
|
0f,0f,1f,0f, 0f,0f,0f,1f, 0f,1f,0f,0f, 1f,0f,0f,0f,
|
||||||
|
|
||||||
0,0,0,1, 1,0,0,0, 0,1,0,0, 0,0,1,0,
|
0f,0f,0f,1f, 1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,1f,0f,
|
||||||
0,0,0,1, 1,0,0,0, 0,0,1,0, 0,1,0,0,
|
0f,0f,0f,1f, 1f,0f,0f,0f, 0f,0f,1f,0f, 0f,1f,0f,0f,
|
||||||
0,0,0,1, 0,1,0,0, 1,0,0,0, 0,0,1,0,
|
0f,0f,0f,1f, 0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,1f,0f,
|
||||||
0,0,0,1, 0,1,0,0, 0,0,1,0, 1,0,0,0,
|
0f,0f,0f,1f, 0f,1f,0f,0f, 0f,0f,1f,0f, 1f,0f,0f,0f,
|
||||||
0,0,0,1, 0,0,1,0, 1,0,0,0, 0,1,0,0,
|
0f,0f,0f,1f, 0f,0f,1f,0f, 1f,0f,0f,0f, 0f,1f,0f,0f,
|
||||||
0,0,0,1, 0,0,1,0, 0,1,0,0, 1,0,0,0,
|
0f,0f,0f,1f, 0f,0f,1f,0f, 0f,1f,0f,0f, 1f,0f,0f,0f,
|
||||||
).map { it.toFloat() }.toFloatArray()
|
)
|
||||||
|
|
||||||
private fun postShader(projMat: Matrix4, fbo: FrameBuffer) {
|
private fun postShader(projMat: Matrix4, fbo: FrameBuffer) {
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
package net.torvald.terrarum
|
package net.torvald.terrarum
|
||||||
|
|
||||||
import net.torvald.terrarum.App.printdbg
|
import net.torvald.terrarum.App.printdbg
|
||||||
|
import kotlin.math.max
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
|
class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val minimumW = 1080
|
const val minimumW = 1024
|
||||||
const val minimumH = 720
|
const val minimumH = 720
|
||||||
const val defaultW = 1280
|
const val defaultW = 1280
|
||||||
const val defaultH = 720
|
const val defaultH = 720
|
||||||
@@ -39,7 +40,7 @@ class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
|
|||||||
var windowH: Int = 0; private set
|
var windowH: Int = 0; private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setDimension(maxOf(minimumW, scrw), maxOf(minimumH, scrh), App.getConfigDouble("screenmagnifying").toFloat())
|
setDimension(max(minimumW, scrw), max(minimumH, scrh), App.getConfigDouble("screenmagnifying").toFloat())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setDimension(scrw: Int, scrh: Int, magn: Float,) {
|
fun setDimension(scrw: Int, scrh: Int, magn: Float,) {
|
||||||
@@ -56,8 +57,8 @@ class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
|
|||||||
|
|
||||||
this.magn = magn
|
this.magn = magn
|
||||||
|
|
||||||
windowW = (scrw * magn).ceilInt() and 0x7FFFFFFE
|
windowW = (scrw * magn).ceilToInt() and 0x7FFFFFFE
|
||||||
windowH = (scrh * magn).ceilInt() and 0x7FFFFFFE
|
windowH = (scrh * magn).ceilToInt() and 0x7FFFFFFE
|
||||||
|
|
||||||
|
|
||||||
printdbg(this, "Window dim: $windowW x $windowH, called by:")
|
printdbg(this, "Window dim: $windowW x $windowH, called by:")
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ class UIItemInventoryCatBar(
|
|||||||
// set up underlined indicator
|
// set up underlined indicator
|
||||||
init {
|
init {
|
||||||
// procedurally generate texture
|
// procedurally generate texture
|
||||||
val pixmap = Pixmap(catIcons.tileW + buttonGapSize.floorInt(), 1, Pixmap.Format.RGBA8888)
|
val pixmap = Pixmap(catIcons.tileW + buttonGapSize.floorToInt(), 1, Pixmap.Format.RGBA8888)
|
||||||
for (x in 0 until pixmap.width.plus(1).ushr(1)) { // eqv. of ceiling the half-int
|
for (x in 0 until pixmap.width.plus(1).ushr(1)) { // eqv. of ceiling the half-int
|
||||||
val col = /*if (x == 0)*/ /*0xffffff_80.toInt()*/
|
val col = /*if (x == 0)*/ /*0xffffff_80.toInt()*/
|
||||||
/*else if (x == 1)*/ /*0xffffff_c0.toInt()*/
|
/*else if (x == 1)*/ /*0xffffff_c0.toInt()*/
|
||||||
|
|||||||
@@ -209,8 +209,8 @@ class BlockCodex {
|
|||||||
prop.isSolid = record.boolVal("solid")
|
prop.isSolid = record.boolVal("solid")
|
||||||
//prop.isClear = record.boolVal("clear")
|
//prop.isClear = record.boolVal("clear")
|
||||||
|
|
||||||
prop.isPlatform = prop.tags.contains("PLATFORM")
|
prop.isPlatform = prop.hasTag("PLATFORM")
|
||||||
prop.isActorBlock = prop.tags.contains("ACTORBLOCK")
|
prop.isActorBlock = prop.hasTag("ACTORBLOCK")
|
||||||
|
|
||||||
prop.isWallable = record.boolVal("wall")
|
prop.isWallable = record.boolVal("wall")
|
||||||
prop.maxSupport = record.intVal("grav")
|
prop.maxSupport = record.intVal("grav")
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ class BlockProp {
|
|||||||
BlockCodex[BlockCodex.tileToVirtual[id]!![offset]]._lumCol.lane(channel)
|
BlockCodex[BlockCodex.tileToVirtual[id]!![offset]]._lumCol.lane(channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun hasTag(s: String) = tags.contains(s)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param luminosity
|
* @param luminosity
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ object BlockPropUtil {
|
|||||||
return when (prop.dynamicLuminosityFunction) {
|
return when (prop.dynamicLuminosityFunction) {
|
||||||
1 -> getTorchFlicker(prop)
|
1 -> getTorchFlicker(prop)
|
||||||
2 -> (INGAME.world).globalLight.cpy() // current global light
|
2 -> (INGAME.world).globalLight.cpy() // current global light
|
||||||
3 -> WeatherMixer.getGlobalLightOfTime(INGAME.world, WorldTime.DAY_LENGTH / 2).cpy() // daylight at noon
|
3 -> WeatherMixer.getGlobalLightOfTimeOfNoon().cpy() // daylight at noon
|
||||||
4 -> getSlowBreath(prop)
|
4 -> getSlowBreath(prop)
|
||||||
5 -> getPulsate(prop)
|
5 -> getPulsate(prop)
|
||||||
else -> prop.baseLumCol
|
else -> prop.baseLumCol
|
||||||
|
|||||||
@@ -19,11 +19,12 @@ import net.torvald.terrarum.toInt
|
|||||||
import java.util.concurrent.Callable
|
import java.util.concurrent.Callable
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
import kotlin.math.max
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
object MinimapComposer : Disposable {
|
object MinimapComposer : Disposable {
|
||||||
|
|
||||||
private val threadExecutor = ThreadExecutor(maxOf(1, App.THREAD_COUNT.times(2).div(3)))
|
private val threadExecutor = ThreadExecutor(max(1, App.THREAD_COUNT.times(2).div(3)))
|
||||||
|
|
||||||
const val SQUARE_SIZE = 13 // preferably in odd number
|
const val SQUARE_SIZE = 13 // preferably in odd number
|
||||||
|
|
||||||
|
|||||||
102
src/net/torvald/terrarum/clut/GenerateSkyboxTextureAtlas.kt
Normal file
102
src/net/torvald/terrarum/clut/GenerateSkyboxTextureAtlas.kt
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package net.torvald.terrarum.clut
|
||||||
|
|
||||||
|
import net.torvald.colourutil.CIEXYZ
|
||||||
|
import net.torvald.colourutil.toColor
|
||||||
|
import net.torvald.colourutil.toRGB
|
||||||
|
import net.torvald.parametricsky.ArHosekSkyModel
|
||||||
|
import net.torvald.terrarum.abs
|
||||||
|
import net.torvald.terrarum.clut.Skybox.coerceInSmoothly
|
||||||
|
import net.torvald.terrarum.clut.Skybox.mapCircle
|
||||||
|
import net.torvald.terrarum.clut.Skybox.scaleToFit
|
||||||
|
import net.torvald.terrarum.modulebasegame.worldgenerator.HALF_PI
|
||||||
|
import net.torvald.terrarum.serialise.toLittle
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2023-08-01.
|
||||||
|
*/
|
||||||
|
fun main() {
|
||||||
|
// y: increasing turbidity (1.0 .. 10.0, in steps of 0.333)
|
||||||
|
// x: elevations (-75 .. 75 in steps of 1, then albedo of [0.1, 0.3, 0.5, 0.7, 0.9])
|
||||||
|
val texh = Skybox.gradSize * Skybox.turbCnt
|
||||||
|
val texw = Skybox.elevCnt * Skybox.albedoCnt * 2
|
||||||
|
val TGA_HEADER_SIZE = 18
|
||||||
|
|
||||||
|
val bytes = ByteArray(TGA_HEADER_SIZE + texw * texh * 4 + 26)
|
||||||
|
// write header
|
||||||
|
byteArrayOf(
|
||||||
|
0, // ID field
|
||||||
|
0, // colour map (none)
|
||||||
|
2, // colour type (unmapped RGB)
|
||||||
|
0,0,0,0,0, // colour map spec (empty)
|
||||||
|
0,0, // x origin (0)
|
||||||
|
0,0, // y origin (0)
|
||||||
|
(texw and 255).toByte(),(texw.ushr(8) and 255).toByte(), // width
|
||||||
|
(texh and 255).toByte(),(texh.ushr(8) and 255).toByte(), // height
|
||||||
|
32, // bits-per-pixel (8bpp RGBA)
|
||||||
|
8 // image descriptor
|
||||||
|
).forEachIndexed { i,b -> bytes[i] = b }
|
||||||
|
// write footer
|
||||||
|
"\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000TRUEVISION-XFILE\u002E\u0000".forEachIndexed { i, c -> bytes[18 + texw * texh * 4 + i] =
|
||||||
|
c.code.toByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Generating texture atlas ($texw x $texh)...")
|
||||||
|
|
||||||
|
// write pixels
|
||||||
|
for (gammaPair in 0..1) {
|
||||||
|
for (albedo0 in 0 until Skybox.albedoCnt) {
|
||||||
|
val albedo = Skybox.albedos[albedo0]
|
||||||
|
println("Albedo=$albedo")
|
||||||
|
for (turb0 in 0 until Skybox.turbCnt) {
|
||||||
|
val turbidity = Skybox.turbiditiesD[turb0]
|
||||||
|
println("....... Turbidity=$turbidity")
|
||||||
|
for (elev0 in 0 until Skybox.elevCnt) {
|
||||||
|
val elevationDeg = Skybox.elevationsD[elev0]
|
||||||
|
val elevationRad = Math.toRadians(elevationDeg)
|
||||||
|
// println("... Elevation: $elevationDeg")
|
||||||
|
|
||||||
|
val state =
|
||||||
|
ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevationRad.abs())
|
||||||
|
|
||||||
|
for (yp in 0 until Skybox.gradSize) {
|
||||||
|
val yi = yp - 10
|
||||||
|
val xf = -elevationDeg / 90.0
|
||||||
|
var yf = (yi / 58.0).coerceIn(0.0, 1.0).mapCircle().coerceInSmoothly(0.0, 0.95)
|
||||||
|
|
||||||
|
// experiments visualisation: https://www.desmos.com/calculator/5crifaekwa
|
||||||
|
// if (elevationDeg < 0) yf *= 1.0 - pow(xf, 0.333)
|
||||||
|
// if (elevationDeg < 0) yf *= -2.0 * asin(xf - 1.0) / PI
|
||||||
|
if (elevationDeg < 0) yf *= Skybox.superellipsoidDecay(1.0 / 3.0, xf)
|
||||||
|
val theta = yf * HALF_PI
|
||||||
|
// vertical angle, where 0 is zenith, ±90 is ground (which is odd)
|
||||||
|
|
||||||
|
// println("$yp\t$theta")
|
||||||
|
|
||||||
|
val xyz = CIEXYZ(
|
||||||
|
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, (gammaPair * 2f + 1f) * HALF_PI, 0).toFloat(),
|
||||||
|
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, (gammaPair * 2f + 1f) * HALF_PI, 1).toFloat(),
|
||||||
|
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, (gammaPair * 2f + 1f) * HALF_PI, 2).toFloat()
|
||||||
|
)
|
||||||
|
val xyz2 = xyz.scaleToFit(elevationDeg)
|
||||||
|
val rgb = xyz2.toRGB().toColor()
|
||||||
|
val colour = rgb.toIntBits().toLittle()
|
||||||
|
|
||||||
|
val imgOffX = albedo0 * Skybox.elevCnt + elev0 + Skybox.elevCnt * Skybox.albedoCnt * gammaPair
|
||||||
|
val imgOffY = texh - 1 - (Skybox.gradSize * turb0 + yp)
|
||||||
|
val fileOffset = TGA_HEADER_SIZE + 4 * (imgOffY * texw + imgOffX)
|
||||||
|
for (i in 0..3) {
|
||||||
|
bytes[fileOffset + i] = colour[bytesLut[i]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println("Atlas generation done!")
|
||||||
|
|
||||||
|
File("./assets/clut/skybox.tga").writeBytes(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val bytesLut = arrayOf(2,1,0,3,2,1,0,3) // For some reason BGRA order is what makes it work
|
||||||
289
src/net/torvald/terrarum/clut/Skybox.kt
Normal file
289
src/net/torvald/terrarum/clut/Skybox.kt
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
package net.torvald.terrarum.clut
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap
|
||||||
|
import com.badlogic.gdx.graphics.Texture
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||||
|
import com.badlogic.gdx.utils.Disposable
|
||||||
|
import com.jme3.math.FastMath
|
||||||
|
import net.torvald.colourutil.CIEXYZ
|
||||||
|
import net.torvald.colourutil.toColor
|
||||||
|
import net.torvald.colourutil.toRGB
|
||||||
|
import net.torvald.parametricsky.ArHosekSkyModel
|
||||||
|
import net.torvald.terrarum.App
|
||||||
|
import net.torvald.terrarum.App.printdbg
|
||||||
|
import net.torvald.terrarum.abs
|
||||||
|
import net.torvald.terrarum.floorToInt
|
||||||
|
import net.torvald.terrarum.toInt
|
||||||
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
|
import kotlin.math.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by minjaesong on 2023-07-09.
|
||||||
|
*/
|
||||||
|
object Skybox : Disposable {
|
||||||
|
|
||||||
|
private const val HALF_PI = 1.5707963267948966
|
||||||
|
private const val PI = 3.141592653589793
|
||||||
|
private const val TWO_PI = 6.283185307179586
|
||||||
|
|
||||||
|
const val gradSize = 78
|
||||||
|
|
||||||
|
private lateinit var gradTexBinLowAlbedo: Array<TextureRegion>
|
||||||
|
private lateinit var gradTexBinHighAlbedo: Array<TextureRegion>
|
||||||
|
|
||||||
|
private lateinit var tex: Texture
|
||||||
|
private lateinit var texRegions: TextureRegionPack
|
||||||
|
private lateinit var texStripRegions: TextureRegionPack
|
||||||
|
|
||||||
|
fun loadlut() {
|
||||||
|
tex = Texture(Gdx.files.internal("assets/clut/skybox.png"))
|
||||||
|
tex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
|
||||||
|
tex.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat)
|
||||||
|
texRegions = TextureRegionPack(tex, 2, gradSize - 2, 0, 2, 0, 1)
|
||||||
|
texStripRegions = TextureRegionPack(tex, elevCnt, gradSize - 2, 0, 2, 0, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// use internal LUT
|
||||||
|
/*operator fun get(elevationDeg: Double, turbidity: Double, albedo: Double): TextureRegion {
|
||||||
|
val elev = elevationDeg.coerceIn(-elevBias, elevBias).times(2.0).roundToInt().plus(150)
|
||||||
|
val turb = turbidity.coerceIn(1.0, 10.0).minus(1.0).times(turbDivisor).roundToInt()
|
||||||
|
val alb = albedo.coerceIn(0.1, 0.9).minus(0.1).times(turbDivisor).roundToInt()
|
||||||
|
return gradTexBinLowAlbedo[elev * turbCnt + turb]
|
||||||
|
}*/
|
||||||
|
|
||||||
|
// use external LUT
|
||||||
|
operator fun get(elevationDeg: Double, turbidity: Double, albedo: Double, isAfternoon: Boolean): TextureRegion {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
data class SkyboxRenderInfo(
|
||||||
|
val texture: Texture,
|
||||||
|
val uvs: FloatArray,
|
||||||
|
val turbidityPoint: Float,
|
||||||
|
val albedoPoint: Float,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun getUV(elevationDeg: Double, turbidity: Double, albedo: Double): SkyboxRenderInfo {
|
||||||
|
val turb = turbidity.coerceIn(turbiditiesD.first(), turbiditiesD.last()).minus(1.0).times(turbDivisor)
|
||||||
|
val turbLo = turb.floorToInt()
|
||||||
|
val turbHi = min(turbCnt - 1, turbLo + 1)
|
||||||
|
val alb = albedo.coerceIn(albedos.first(), albedos.last()).times(5.0)
|
||||||
|
val albLo = alb.floorToInt()
|
||||||
|
val albHi = min(albedoCnt - 1, albLo + 1)
|
||||||
|
val elev = elevationDeg.coerceIn(-elevMax, elevMax).plus(elevMax).div(elevations.last.toDouble()).div(albedoCnt * 2).times((elevCnt - 1.0) / elevCnt)
|
||||||
|
|
||||||
|
// A: morn, turbLow, albLow
|
||||||
|
// B: noon, turbLow, albLow
|
||||||
|
// C: morn, turbHigh, albLow
|
||||||
|
// D: noon, turbHigh, albLow
|
||||||
|
// E: morn, turbLow, albHigh
|
||||||
|
// F: noon, turbLow, albHigh
|
||||||
|
// G: morn, turbHigh, albHigh
|
||||||
|
// H: noon, turbHigh, albHigh
|
||||||
|
|
||||||
|
val regionA = texStripRegions.get(albLo + albedoCnt * 0, turbLo)
|
||||||
|
val regionB = texStripRegions.get(albLo + albedoCnt * 1, turbLo)
|
||||||
|
val regionC = texStripRegions.get(albLo + albedoCnt * 0, turbHi)
|
||||||
|
val regionD = texStripRegions.get(albLo + albedoCnt * 1, turbHi)
|
||||||
|
val regionE = texStripRegions.get(albHi + albedoCnt * 0, turbLo)
|
||||||
|
val regionF = texStripRegions.get(albHi + albedoCnt * 1, turbLo)
|
||||||
|
val regionG = texStripRegions.get(albHi + albedoCnt * 0, turbHi)
|
||||||
|
val regionH = texStripRegions.get(albHi + albedoCnt * 1, turbHi)
|
||||||
|
// (0.5f / tex.width): because of the nature of bilinear interpolation, half pixels from the edges must be discarded
|
||||||
|
val uA = regionA.u + (0.5f / tex.width) + elev.toFloat()
|
||||||
|
val uB = regionB.u + (0.5f / tex.width) + elev.toFloat()
|
||||||
|
val uC = regionC.u + (0.5f / tex.width) + elev.toFloat()
|
||||||
|
val uD = regionD.u + (0.5f / tex.width) + elev.toFloat()
|
||||||
|
val uE = regionE.u + (0.5f / tex.width) + elev.toFloat()
|
||||||
|
val uF = regionF.u + (0.5f / tex.width) + elev.toFloat()
|
||||||
|
val uG = regionG.u + (0.5f / tex.width) + elev.toFloat()
|
||||||
|
val uH = regionH.u + (0.5f / tex.width) + elev.toFloat()
|
||||||
|
|
||||||
|
return SkyboxRenderInfo(
|
||||||
|
tex,
|
||||||
|
floatArrayOf(
|
||||||
|
uA, regionA.v, uA, regionA.v2,
|
||||||
|
uB, regionB.v, uB, regionB.v2,
|
||||||
|
uC, regionC.v, uC, regionC.v2,
|
||||||
|
uD, regionD.v, uD, regionD.v2,
|
||||||
|
uE, regionE.v, uE, regionE.v2,
|
||||||
|
uF, regionF.v, uF, regionF.v2,
|
||||||
|
uG, regionG.v, uG, regionG.v2,
|
||||||
|
uH, regionH.v, uH, regionH.v2,
|
||||||
|
),
|
||||||
|
(turb - turbLo).toFloat(),
|
||||||
|
(alb - albLo).toFloat(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Float.scaleFun() =
|
||||||
|
(1f - 1f / 2f.pow(this/6f)) * 0.97f
|
||||||
|
|
||||||
|
internal fun CIEXYZ.scaleToFit(elevationDeg: Double): CIEXYZ {
|
||||||
|
return if (elevationDeg >= 0) {
|
||||||
|
CIEXYZ(
|
||||||
|
this.X.scaleFun(),
|
||||||
|
this.Y.scaleFun(),
|
||||||
|
this.Z.scaleFun(),
|
||||||
|
this.alpha
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// maths model: https://www.desmos.com/calculator/cwi7iyzygg
|
||||||
|
|
||||||
|
val x = -elevationDeg.toFloat()
|
||||||
|
// val elevation2 = elevationDeg.toFloat() / 28.5f
|
||||||
|
val p = 3.5f
|
||||||
|
val q = 7.5f
|
||||||
|
val s = -0.2f
|
||||||
|
val f = (1f - (1f - 1f / 1.8f.pow(x)) * 0.97f).toFloat()
|
||||||
|
// val g = (1.0 - (elevation2.pow(E) / E.pow(elevation2))*0.8).toFloat()
|
||||||
|
val h = ((x / q).pow(p) + 1f).pow(s)
|
||||||
|
CIEXYZ(
|
||||||
|
this.X.scaleFun() * f * h,
|
||||||
|
this.Y.scaleFun() * f * h,
|
||||||
|
this.Z.scaleFun() * f * h,
|
||||||
|
this.alpha
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val elevations = (0..150)
|
||||||
|
val elevMax = elevations.last / 2.0
|
||||||
|
val elevationsD = elevations.map { -elevMax + it } // -75, -74, -73, ..., 74, 75 // (specifically using whole number of angles because angle units any finer than 1.0 would make "hack" sunsut happen too fast)
|
||||||
|
val turbidities = (0..25) // 1, 1.2, 1.4, 1.6, ..., 6.0
|
||||||
|
val turbDivisor = 5.0
|
||||||
|
val turbiditiesD = turbidities.map { 1.0 + it / turbDivisor }
|
||||||
|
val albedos = arrayOf(0.0, 0.2, 0.4, 0.6, 0.8, 1.0)
|
||||||
|
val elevCnt = elevations.count()
|
||||||
|
val turbCnt = turbidities.count()
|
||||||
|
val albedoCnt = albedos.size
|
||||||
|
val gamma = HALF_PI
|
||||||
|
|
||||||
|
internal fun Double.mapCircle() = sin(HALF_PI * this)
|
||||||
|
|
||||||
|
internal fun initiate() {
|
||||||
|
printdbg(this, "Initialising skybox model")
|
||||||
|
|
||||||
|
TODO()
|
||||||
|
|
||||||
|
App.disposables.add(this)
|
||||||
|
|
||||||
|
printdbg(this, "Skybox model generated!")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See https://www.desmos.com/calculator/lcvvsju3p1 for mathematical definition
|
||||||
|
* @param p decay point. 0.0..1.0
|
||||||
|
* @param q polynomial degree. 2+. Larger value means sharper transition around the point p
|
||||||
|
* @param x the 'x' value of the function, as in `y=f(x)`. 0.0..1.0
|
||||||
|
*/
|
||||||
|
internal fun polynomialDecay(p: Double, q: Int, x: Double): Double {
|
||||||
|
val sign = if (q % 2 == 1) -1 else 1
|
||||||
|
val a1 = -1.0 / p
|
||||||
|
val a2 = 1.0 / (1.0 - p)
|
||||||
|
val q = q.toDouble()
|
||||||
|
return if (x < p)
|
||||||
|
sign * a1.pow(q - 1.0) * x.pow(q) + 1.0
|
||||||
|
else
|
||||||
|
sign * a2.pow(q - 1.0) * (x - 1.0).pow(q)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun polynomialDecay2(p: Double, q: Int, x: Double): Double {
|
||||||
|
val sign = if (q % 2 == 1) 1 else -1
|
||||||
|
val a1 = -1.0 / p
|
||||||
|
val a2 = 1.0 / (1.0 - p)
|
||||||
|
val q = q.toDouble()
|
||||||
|
return if (x < p)
|
||||||
|
sign * a1.pow(q - 1.0) * x.pow(q)
|
||||||
|
else
|
||||||
|
sign * a2.pow(q - 1.0) * (x - 1.0).pow(q) + 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun superellipsoidDecay(p: Double, x: Double): Double {
|
||||||
|
return 1.0 - (1.0 - (1.0 - x).pow(1.0 / p)).pow(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Double.coerceInSmoothly(low: Double, high: Double): Double {
|
||||||
|
val x = this.coerceIn(low, high)
|
||||||
|
val x2 = ((x - low) * (high - low).pow(-1.0))
|
||||||
|
// return FastMath.interpolateLinear(polynomialDecay2(0.5, 2, x2), low, high)
|
||||||
|
return FastMath.interpolateLinear(smoothLinear(0.2, x2), low, high)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To get the idea what the fuck is going on here, please refer to https://www.desmos.com/calculator/snqglcu2wl
|
||||||
|
*
|
||||||
|
* Sidenote: the original model involved two cosine curves, but since its Taylor series begins with x^2, I figured
|
||||||
|
* quadratic curve ought to be good enough, and the error against the original model was below 1/255 for
|
||||||
|
* reasonable range of p, and that's the reason I stopped at x^2 rather than also taking x^4 into the approximated
|
||||||
|
* model that is the code below.
|
||||||
|
*/
|
||||||
|
internal fun smoothLinear(p: Double, x0: Double): Double {
|
||||||
|
val x = x0 - 0.5
|
||||||
|
val p1 = sqrt(1.0 - 2.0 * p)
|
||||||
|
val t = 0.5 * p1
|
||||||
|
val y0 = if (x < -t)
|
||||||
|
(1.0 / p) * (x + 0.5).pow(2) - 0.5
|
||||||
|
else if (x > t)
|
||||||
|
-(1.0 / p) * (x - 0.5).pow(2) + 0.5
|
||||||
|
else
|
||||||
|
x * 2.0 / (1.0 + p1)
|
||||||
|
|
||||||
|
return y0 + 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getTexturmaps(albedo: Double): Array<TextureRegion> {
|
||||||
|
return Array(elevCnt * turbCnt) {
|
||||||
|
|
||||||
|
val elevationDeg = elevationsD[it / turbCnt]
|
||||||
|
val elevationRad = Math.toRadians(elevationDeg)
|
||||||
|
val turbidity = turbiditiesD[it % turbCnt]
|
||||||
|
|
||||||
|
val state = ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevationRad.abs())
|
||||||
|
val pixmap = Pixmap(1, gradSize, Pixmap.Format.RGBA8888)
|
||||||
|
|
||||||
|
// printdbg(this, "elev $elevationDeg turb $turbidity")
|
||||||
|
|
||||||
|
for (yp in 0 until gradSize) {
|
||||||
|
val yi = yp - 10
|
||||||
|
val xf = -elevationDeg / 90.0
|
||||||
|
var yf = (yi / 58.0).coerceIn(0.0, 1.0).mapCircle().coerceInSmoothly(0.0, 0.95)
|
||||||
|
|
||||||
|
// experiments visualisation: https://www.desmos.com/calculator/5crifaekwa
|
||||||
|
// if (elevationDeg < 0) yf *= 1.0 - pow(xf, 0.333)
|
||||||
|
// if (elevationDeg < 0) yf *= -2.0 * asin(xf - 1.0) / PI
|
||||||
|
if (elevationDeg < 0) yf *= superellipsoidDecay(1.0 / 3.0, xf)
|
||||||
|
val theta = yf * HALF_PI
|
||||||
|
// vertical angle, where 0 is zenith, ±90 is ground (which is odd)
|
||||||
|
|
||||||
|
// println("$yp\t$theta")
|
||||||
|
|
||||||
|
val xyz = CIEXYZ(
|
||||||
|
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 0).toFloat(),
|
||||||
|
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 1).toFloat(),
|
||||||
|
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 2).toFloat()
|
||||||
|
)
|
||||||
|
val xyz2 = xyz.scaleToFit(elevationDeg)
|
||||||
|
val rgb = xyz2.toRGB().toColor()
|
||||||
|
|
||||||
|
// pixmap.setColor(if (yp in 17 until 17 + 94) Color.LIME else Color.CORAL)
|
||||||
|
pixmap.setColor(rgb)
|
||||||
|
pixmap.drawPixel(0, yp)
|
||||||
|
}
|
||||||
|
|
||||||
|
val texture = Texture(pixmap).also {
|
||||||
|
it.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
|
||||||
|
}
|
||||||
|
pixmap.dispose()
|
||||||
|
TextureRegion(texture)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
if (Skybox::gradTexBinLowAlbedo.isInitialized) gradTexBinLowAlbedo.forEach { it.texture.dispose() }
|
||||||
|
if (Skybox::gradTexBinHighAlbedo.isInitialized) gradTexBinHighAlbedo.forEach { it.texture.dispose() }
|
||||||
|
if (Skybox::tex.isInitialized) tex.dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,7 +36,7 @@ internal object Authenticator : ConsoleCommand {
|
|||||||
println("auth passwd: '$pwd'")
|
println("auth passwd: '$pwd'")
|
||||||
println("hash: $hashedPwd")
|
println("hash: $hashedPwd")
|
||||||
|
|
||||||
if ("09ccf5067db6f58265b004829e33e715e819ba0984f1e1fcef49c36fcd5f745f".equals(hashedPwd, ignoreCase = true)) {
|
if ("2d962f949f55906ac47f16095ded190c9e44d95920259b8f36c2e54bd75df173".equals(hashedPwd, ignoreCase = true)) {
|
||||||
// beedle
|
// beedle
|
||||||
val msg = if (a) "Locked" else "Authenticated"
|
val msg = if (a) "Locked" else "Authenticated"
|
||||||
Echo(msg)
|
Echo(msg)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ internal object SetGlobalLightOverride : ConsoleCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (args.size == 2 && args[1].trim().toLowerCase() == "none") {
|
else if (args.size == 2 && args[1].trim().lowercase() == "none") {
|
||||||
WeatherMixer.globalLightOverridden = false
|
WeatherMixer.globalLightOverridden = false
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -18,12 +18,14 @@ import net.torvald.terrarum.gameitems.ItemID
|
|||||||
import net.torvald.terrarum.gameworld.BlockAddress
|
import net.torvald.terrarum.gameworld.BlockAddress
|
||||||
import net.torvald.terrarum.gameworld.GameWorld
|
import net.torvald.terrarum.gameworld.GameWorld
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||||
|
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||||
import net.torvald.terrarum.realestate.LandUtil
|
import net.torvald.terrarum.realestate.LandUtil
|
||||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||||
import org.dyn4j.geometry.Vector2
|
import org.dyn4j.geometry.Vector2
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
import kotlin.math.max
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
|
||||||
@@ -442,7 +444,7 @@ open class ActorWithBody : Actor {
|
|||||||
@Transient val feetPosPoint: Point2d = Point2d(0.0,0.0)
|
@Transient val feetPosPoint: Point2d = Point2d(0.0,0.0)
|
||||||
//get() = Point2d(hitbox.centeredX, hitbox.endY)
|
//get() = Point2d(hitbox.centeredX, hitbox.endY)
|
||||||
@Transient val feetPosTile: Point2i = Point2i(0,0)
|
@Transient val feetPosTile: Point2i = Point2i(0,0)
|
||||||
//get() = Point2i(hIntTilewiseHitbox.centeredX.floorInt(), hIntTilewiseHitbox.endY.floorInt())
|
//get() = Point2i(hIntTilewiseHitbox.centeredX.floorToInt(), hIntTilewiseHitbox.endY.floorToInt())
|
||||||
|
|
||||||
override fun run() = update(App.UPDATE_RATE)
|
override fun run() = update(App.UPDATE_RATE)
|
||||||
|
|
||||||
@@ -474,23 +476,23 @@ open class ActorWithBody : Actor {
|
|||||||
hitbox.reassign(newHitbox)
|
hitbox.reassign(newHitbox)
|
||||||
|
|
||||||
hIntTilewiseHitbox.setFromTwoPoints(
|
hIntTilewiseHitbox.setFromTwoPoints(
|
||||||
hitbox.startX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
|
hitbox.startX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
|
||||||
hitbox.startY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
|
hitbox.startY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
|
||||||
hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
|
hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
|
||||||
hitbox.endY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5
|
hitbox.endY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5
|
||||||
)
|
)
|
||||||
intTilewiseHitbox.setFromTwoPoints(
|
intTilewiseHitbox.setFromTwoPoints(
|
||||||
hitbox.startX.div(TILE_SIZE).floor(),
|
hitbox.startX.div(TILE_SIZE).floorToDouble(),
|
||||||
hitbox.startY.div(TILE_SIZE).floor(),
|
hitbox.startY.div(TILE_SIZE).floorToDouble(),
|
||||||
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(),
|
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
|
||||||
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor()
|
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble()
|
||||||
)
|
)
|
||||||
|
|
||||||
centrePosVector.set(hitbox.centeredX, hitbox.centeredY)
|
centrePosVector.set(hitbox.centeredX, hitbox.centeredY)
|
||||||
centrePosPoint.set(hitbox.centeredX, hitbox.centeredY)
|
centrePosPoint.set(hitbox.centeredX, hitbox.centeredY)
|
||||||
feetPosVector.set(hitbox.centeredX, hitbox.endY)
|
feetPosVector.set(hitbox.centeredX, hitbox.endY)
|
||||||
feetPosPoint.set(hitbox.centeredX, hitbox.endY)
|
feetPosPoint.set(hitbox.centeredX, hitbox.endY)
|
||||||
feetPosTile.set(hIntTilewiseHitbox.centeredX.floorInt(), hIntTilewiseHitbox.endY.floorInt())
|
feetPosTile.set(hIntTilewiseHitbox.centeredX.floorToInt(), hIntTilewiseHitbox.endY.floorToInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun update(delta: Float) {
|
override fun update(delta: Float) {
|
||||||
@@ -553,7 +555,6 @@ open class ActorWithBody : Actor {
|
|||||||
*/
|
*/
|
||||||
if (!isNoCollideWorld) {
|
if (!isNoCollideWorld) {
|
||||||
displaceHitbox()
|
displaceHitbox()
|
||||||
//collisionInterpolatorRun()
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
stairPenaltyCounter = 999
|
stairPenaltyCounter = 999
|
||||||
@@ -618,23 +619,23 @@ open class ActorWithBody : Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hIntTilewiseHitbox.setFromTwoPoints(
|
hIntTilewiseHitbox.setFromTwoPoints(
|
||||||
hitbox.startX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
|
hitbox.startX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
|
||||||
hitbox.startY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
|
hitbox.startY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
|
||||||
hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
|
hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
|
||||||
hitbox.endY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5
|
hitbox.endY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5
|
||||||
)
|
)
|
||||||
intTilewiseHitbox.setFromTwoPoints(
|
intTilewiseHitbox.setFromTwoPoints(
|
||||||
hitbox.startX.div(TILE_SIZE).floor(),
|
hitbox.startX.div(TILE_SIZE).floorToDouble(),
|
||||||
hitbox.startY.div(TILE_SIZE).floor(),
|
hitbox.startY.div(TILE_SIZE).floorToDouble(),
|
||||||
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(),
|
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
|
||||||
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor()
|
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble()
|
||||||
)
|
)
|
||||||
|
|
||||||
centrePosVector.set(hitbox.centeredX, hitbox.centeredY)
|
centrePosVector.set(hitbox.centeredX, hitbox.centeredY)
|
||||||
centrePosPoint.set(hitbox.centeredX, hitbox.centeredY)
|
centrePosPoint.set(hitbox.centeredX, hitbox.centeredY)
|
||||||
feetPosVector.set(hitbox.centeredX, hitbox.endY)
|
feetPosVector.set(hitbox.centeredX, hitbox.endY)
|
||||||
feetPosPoint.set(hitbox.centeredX, hitbox.endY)
|
feetPosPoint.set(hitbox.centeredX, hitbox.endY)
|
||||||
feetPosTile.set(hIntTilewiseHitbox.centeredX.floorInt(), hIntTilewiseHitbox.endY.floorInt())
|
feetPosTile.set(hIntTilewiseHitbox.centeredX.floorToInt(), hIntTilewiseHitbox.endY.floorToInt())
|
||||||
|
|
||||||
|
|
||||||
if (mouseUp && this.tooltipText != null) INGAME.setTooltipMessage(this.tooltipText)
|
if (mouseUp && this.tooltipText != null) INGAME.setTooltipMessage(this.tooltipText)
|
||||||
@@ -672,16 +673,6 @@ open class ActorWithBody : Actor {
|
|||||||
// this is "close enough" solution and not perfect.
|
// this is "close enough" solution and not perfect.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Event for collision (event gets fired when it collided with the world or other actors)
|
|
||||||
*
|
|
||||||
* This event may fired two or more times per update.
|
|
||||||
*/
|
|
||||||
open fun collided(other: Array<CollisionMessage>) {
|
|
||||||
}
|
|
||||||
|
|
||||||
data class CollisionMessage(val targetID: Int, val AkspfisWorld: Boolean)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply gravitation to the every falling body (unless not levitating)
|
* Apply gravitation to the every falling body (unless not levitating)
|
||||||
*
|
*
|
||||||
@@ -697,6 +688,7 @@ open class ActorWithBody : Actor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun displaceHitbox() {
|
private fun displaceHitbox() {
|
||||||
|
val printdbg1 = true && App.IS_DEVELOPMENT_BUILD
|
||||||
// // HOW IT SHOULD WORK // //
|
// // HOW IT SHOULD WORK // //
|
||||||
// ////////////////////////
|
// ////////////////////////
|
||||||
// combineVeloToMoveDelta now
|
// combineVeloToMoveDelta now
|
||||||
@@ -723,46 +715,8 @@ open class ActorWithBody : Actor {
|
|||||||
|
|
||||||
if (world != null) {
|
if (world != null) {
|
||||||
|
|
||||||
fun debug1(wut: Any?) {
|
|
||||||
// vvvvv set it true to make debug print work
|
|
||||||
if (false) printdbg(this, wut)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun debug2(wut: Any?) {
|
fun Double.modTile() = this.div(TILE_SIZE).floorToInt().times(TILE_SIZE)
|
||||||
// vvvvv set it true to make debug print work
|
|
||||||
if (false) printdbg(this, wut)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun debug3(wut: Any?) {
|
|
||||||
// vvvvv set it true to make debug print work
|
|
||||||
if (false) printdbg(this, wut)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun debug4(wut: Any?) {
|
|
||||||
// vvvvv set it true to make debug print work
|
|
||||||
if (false) printdbg(this, wut)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun BlockAddress.isFeetTile(hitbox: Hitbox): Boolean {
|
|
||||||
val (x, y) = LandUtil.resolveBlockAddr(world!!, this)
|
|
||||||
val newTilewiseHitbox = Hitbox.fromTwoPoints(
|
|
||||||
hitbox.startX.div(TILE_SIZE).floor(),
|
|
||||||
hitbox.startY.div(TILE_SIZE).floor(),
|
|
||||||
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(),
|
|
||||||
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(),
|
|
||||||
true
|
|
||||||
)
|
|
||||||
|
|
||||||
// offset 1 pixel to the down so that friction would work
|
|
||||||
val yMatch = if (gravitation.y >= 0.0)
|
|
||||||
hitbox.endY.plus(A_PIXEL).div(TILE_SIZE).floorInt()
|
|
||||||
else
|
|
||||||
hitbox.startY.minus(A_PIXEL).div(TILE_SIZE).floorInt()
|
|
||||||
return y == yMatch && // copied from forEachFeetTileNum
|
|
||||||
(x in newTilewiseHitbox.startX.toInt()..newTilewiseHitbox.endX.toInt()) // copied from forEachOccupyingTilePos
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Double.modTile() = this.div(TILE_SIZE).floorInt().times(TILE_SIZE)
|
|
||||||
fun Double.modTileDelta() = this - this.modTile()
|
fun Double.modTileDelta() = this - this.modTile()
|
||||||
|
|
||||||
|
|
||||||
@@ -776,10 +730,27 @@ open class ActorWithBody : Actor {
|
|||||||
// the job of the ccd is that the "next hitbox" would not dig into the terrain greater than the tile size,
|
// the job of the ccd is that the "next hitbox" would not dig into the terrain greater than the tile size,
|
||||||
// in which the modTileDelta returns a wrong value
|
// in which the modTileDelta returns a wrong value
|
||||||
val vectorSum = (externalV + controllerV)
|
val vectorSum = (externalV + controllerV)
|
||||||
val ccdSteps = (vectorSum.magnitude / TILE_SIZE).floorInt().coerceIn(2, 16) // adaptive
|
val ccdSteps = (vectorSum.magnitude / TILE_SIZE).ceilToInt().plus(1).times(2).coerceIn(0, 64) // adaptive
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fun debug1(wut: Any?) {
|
||||||
|
// vvvvv set it true to make debug print work
|
||||||
|
if (printdbg1 && vectorSum.magnitudeSquared != 0.0) printdbg(this, wut)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun debug2(wut: Any?) {
|
||||||
|
// vvvvv set it true to make debug print work
|
||||||
|
if (true && printdbg1 && vectorSum.magnitudeSquared != 0.0) printdbg(this, wut)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (printdbg1 && vectorSum.magnitudeSquared != 0.0) println("")
|
||||||
|
debug1("Update Frame: ${INGAME.WORLD_UPDATE_TIMER}")
|
||||||
|
debug1("Hitbox: ${hitbox}")
|
||||||
|
|
||||||
|
debug1("vec dir: ${if (vectorSum.isZero) "." else Math.toDegrees(vectorSum.direction)} deg, value: $vectorSum, magnitude: ${vectorSum.magnitude}")
|
||||||
|
|
||||||
|
|
||||||
// * NEW idea: wall pushes the actors (ref. SM64 explained by dutch pancake) *
|
// * NEW idea: wall pushes the actors (ref. SM64 explained by dutch pancake) *
|
||||||
// direction to push is determined by the velocity
|
// direction to push is determined by the velocity
|
||||||
// proc:
|
// proc:
|
||||||
@@ -792,63 +763,63 @@ open class ActorWithBody : Actor {
|
|||||||
// ignore MOST of the codes below (it might be possible to recycle the structure??)
|
// ignore MOST of the codes below (it might be possible to recycle the structure??)
|
||||||
// and the idea above has not yet implemented, and may never will. --Torvald, 2018-12-30
|
// and the idea above has not yet implemented, and may never will. --Torvald, 2018-12-30
|
||||||
|
|
||||||
val sixteenStep = (0..ccdSteps).map { hitbox.clone().translate(vectorSum * (it / ccdSteps.toDouble())) } // zeroth step is for special condition
|
val downDown = if (this is ActorHumanoid) this.downButtonHeld > 0 else false
|
||||||
|
|
||||||
|
val sixteenStep = (0..ccdSteps).map { hitbox.clone().translate(vectorSum * (it / ccdSteps.toDouble())) }
|
||||||
var collidingStep: Int? = null
|
var collidingStep: Int? = null
|
||||||
|
|
||||||
for (step in 1..ccdSteps) {
|
for (step in 0..ccdSteps) {
|
||||||
|
|
||||||
val stepBox = sixteenStep[step]
|
val stepBox = sixteenStep[step]
|
||||||
|
|
||||||
/*forEachOccupyingTilePos(stepBox) {
|
val goingDownwardDirection = Math.toDegrees(vectorSum.direction).let { it > 0.0 && it < 180.0 }
|
||||||
val tileCoord = LandUtil.resolveBlockAddr(world!!, it)
|
val goingDown = (vectorSum.y >= PHYS_EPSILON_VELO || (vectorSum.y.absoluteValue < PHYS_EPSILON_VELO && !isWalled(stepBox, COLLIDING_BOTTOM))) // TODO reverse gravity adaptation?
|
||||||
val tile = world!!.getTileFromTerrain(tileCoord.first, tileCoord.second) ?: Block.STONE
|
|
||||||
|
|
||||||
if (shouldICollideWithThis(tile) || (it.isFeetTile(stepBox) && shouldICollideWithThisFeet(tile))) {
|
debug2("stepbox[$step]=$stepBox; goingDown=$goingDown, downDown=$downDown, goingDownwardDirection=$goingDownwardDirection")
|
||||||
collidingStep = step
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// trying to use same function as the others, in an effort to eliminate the "contradiction" mentioned below
|
if (collidingStep == null && isColliding(stepBox, goingDown && !downDown && goingDownwardDirection)) {
|
||||||
if (isColliding(stepBox, vectorSum.y > PHYS_EPSILON_DIST)) {
|
|
||||||
collidingStep = step
|
collidingStep = step
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collidingStep != null) break
|
// if (collidingStep != null) break
|
||||||
}
|
}
|
||||||
|
|
||||||
var bounceX = false
|
var bounceX = false
|
||||||
var bounceY = false
|
var bounceY = false
|
||||||
var zeroX = false
|
var zeroX = false
|
||||||
var zeroY = false
|
var zeroY = false
|
||||||
|
|
||||||
|
val newHitbox = if (collidingStep == null) null else hitbox.clone().reassign(sixteenStep[collidingStep])
|
||||||
|
var staircaseStatus = 0
|
||||||
|
var stairHeightLeft = 0.0
|
||||||
|
var stairHeightRight = 0.0
|
||||||
|
val selfCollisionStatus = if (newHitbox == null) 0 else {
|
||||||
|
intArrayOf(1, 2, 4, 8).fold(0) { acc, state ->
|
||||||
|
val (isWalled, stairHeight) = isWalledStairs(newHitbox, state)
|
||||||
|
// also update staircaseStatus while we're iterating
|
||||||
|
if (state and COLLIDING_LR != 0) {
|
||||||
|
staircaseStatus = staircaseStatus or (state * (isWalled == 1).toInt())
|
||||||
|
if (state == COLLIDING_LEFT)
|
||||||
|
stairHeightLeft = stairHeight.toDouble()
|
||||||
|
else
|
||||||
|
stairHeightRight = stairHeight.toDouble()
|
||||||
|
}
|
||||||
|
acc or (state * isWalled.coerceAtMost(1)) // TODO reverse gravity adaptation?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// collision NOT detected
|
// collision NOT detected
|
||||||
if (collidingStep == null) {
|
if (collidingStep == null) {
|
||||||
|
debug1("== Collision step: no collision")
|
||||||
hitbox.translate(vectorSum)
|
hitbox.translate(vectorSum)
|
||||||
// grounded = false
|
// grounded = false
|
||||||
}
|
}
|
||||||
// collision detected
|
// collision detected
|
||||||
else {
|
else {
|
||||||
debug1("== Collision step: $collidingStep / $ccdSteps")
|
debug1("== Collision step: $collidingStep / $ccdSteps")
|
||||||
|
debug1("CCD hitbox: ${newHitbox}")
|
||||||
|
|
||||||
|
val newHitbox = newHitbox!!
|
||||||
val newHitbox = hitbox.reassign(sixteenStep[collidingStep])
|
|
||||||
|
|
||||||
var staircaseStatus = 0
|
|
||||||
var stairHeightLeft = 0.0
|
|
||||||
var stairHeightRight = 0.0
|
|
||||||
val selfCollisionStatus = intArrayOf(1,2,4,8).fold(0) { acc, state ->
|
|
||||||
// also update staircaseStatus while we're iterating
|
|
||||||
if (state and 5 != 0) {
|
|
||||||
isWalledStairs(newHitbox, state).let {
|
|
||||||
staircaseStatus = staircaseStatus or (state * (it.first == 1).toInt())
|
|
||||||
if (state == COLLIDING_LEFT)
|
|
||||||
stairHeightLeft = it.second.toDouble()
|
|
||||||
else
|
|
||||||
stairHeightRight = it.second.toDouble()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
acc or (state * isWalledStairs(newHitbox, state).first.coerceAtMost(1))
|
|
||||||
}
|
|
||||||
|
|
||||||
// superseded by isWalledStairs-related codes
|
// superseded by isWalledStairs-related codes
|
||||||
//if (isWalled(newHitbox, COLLIDING_LEFT)) selfCollisionStatus += COLL_LEFTSIDE // 1
|
//if (isWalled(newHitbox, COLLIDING_LEFT)) selfCollisionStatus += COLL_LEFTSIDE // 1
|
||||||
@@ -858,37 +829,51 @@ open class ActorWithBody : Actor {
|
|||||||
|
|
||||||
// fixme UP and RIGHT && LEFT and DOWN bug
|
// fixme UP and RIGHT && LEFT and DOWN bug
|
||||||
|
|
||||||
//println("collision: $selfCollisionStatus\tstaircasing: $staircaseStatus")
|
debug1("collision: $selfCollisionStatus\tstaircasing: $staircaseStatus")
|
||||||
|
|
||||||
when (selfCollisionStatus) {
|
when (selfCollisionStatus) {
|
||||||
0 -> {
|
/*0 -> {
|
||||||
debug1("[ActorWBMovable] Contradiction -- collision detected by CCD, but isWalled() says otherwise")
|
debug1("Contradiction -- collision detected by CCD, but isWalled() says otherwise")
|
||||||
}
|
}*/
|
||||||
5 -> {
|
/* 5 */ COLLIDING_LR -> {
|
||||||
zeroX = true
|
zeroX = true
|
||||||
}
|
}
|
||||||
10 -> {
|
/* 10 */ COLLIDING_UD -> {
|
||||||
zeroY = true
|
zeroY = true
|
||||||
}
|
}
|
||||||
15 -> {
|
/* 15 */ COLLIDING_ALLSIDE -> {
|
||||||
newHitbox.reassign(sixteenStep[0]); zeroX = true; zeroY = true
|
newHitbox.reassign(sixteenStep[0]); zeroX = true; zeroY = true
|
||||||
|
debug1("reassining hitbox to ${sixteenStep[0]}")
|
||||||
}
|
}
|
||||||
// one-side collision
|
// one-side collision
|
||||||
1, 11 -> {
|
/* 1, 11 */ COLLIDING_LEFT, COLLIDING_LEFT or COLLIDING_UD -> {
|
||||||
newHitbox.translatePosX(TILE_SIZE - newHitbox.startX.modTileDelta()); bounceX = true
|
val t = TILE_SIZE - newHitbox.startX.modTileDelta()
|
||||||
|
newHitbox.translatePosX(t); bounceX = true
|
||||||
|
debug1("translate x by $t")
|
||||||
}
|
}
|
||||||
4, 14 -> {
|
/* 4, 14 */ COLLIDING_RIGHT, COLLIDING_RIGHT or COLLIDING_UD -> {
|
||||||
newHitbox.translatePosX(-newHitbox.endX.modTileDelta()); bounceX = true
|
val t = -newHitbox.endX.modTileDelta()
|
||||||
|
newHitbox.translatePosX(t); bounceX = true
|
||||||
|
debug1("translate x by $t")
|
||||||
}
|
}
|
||||||
8, 13 -> {
|
/* 8, 13 */ COLLIDING_TOP, COLLIDING_TOP or COLLIDING_LR -> {
|
||||||
newHitbox.translatePosY(TILE_SIZE - newHitbox.startY.modTileDelta()); bounceY = true
|
val t = TILE_SIZE - newHitbox.startY.modTileDelta()
|
||||||
|
newHitbox.translatePosY(t); bounceY = true
|
||||||
|
debug1("translate y by $t")
|
||||||
}
|
}
|
||||||
2, 7 -> {
|
/* 2, 7 */ COLLIDING_BOTTOM, COLLIDING_BOTTOM or COLLIDING_LR -> {
|
||||||
newHitbox.translatePosY(-newHitbox.endY.modTileDelta()); bounceY = true
|
val t = -newHitbox.endY.modTileDelta()
|
||||||
|
newHitbox.translatePosY(t); bounceY = true
|
||||||
|
debug1("translate y by $t")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (selfCollisionStatus == 0) {
|
||||||
|
debug1("== selfCollisionStatus was zero, behaving as if (collidingStep = null)")
|
||||||
|
hitbox.translate(vectorSum)
|
||||||
|
}
|
||||||
|
else {
|
||||||
// fire Collision Event with one/two/three-side collision
|
// fire Collision Event with one/two/three-side collision
|
||||||
// for the ease of writing, this jumptable is separated from above.
|
// for the ease of writing, this jumptable is separated from above.
|
||||||
when (selfCollisionStatus) {
|
when (selfCollisionStatus) {
|
||||||
@@ -906,15 +891,15 @@ open class ActorWithBody : Actor {
|
|||||||
|
|
||||||
// points to the EDGE of the tile in world dimension (don't use this directly to get tilewise coord!!)
|
// points to the EDGE of the tile in world dimension (don't use this directly to get tilewise coord!!)
|
||||||
val offendingTileWorldX = if (selfCollisionStatus in listOf(6, 12))
|
val offendingTileWorldX = if (selfCollisionStatus in listOf(6, 12))
|
||||||
newHitbox.endX.div(TILE_SIZE).floor() * TILE_SIZE - PHYS_EPSILON_DIST
|
newHitbox.endX.div(TILE_SIZE).floorToDouble() * TILE_SIZE - PHYS_EPSILON_DIST
|
||||||
else
|
else
|
||||||
newHitbox.startX.div(TILE_SIZE).ceil() * TILE_SIZE
|
newHitbox.startX.div(TILE_SIZE).ceilToDouble() * TILE_SIZE
|
||||||
|
|
||||||
// points to the EDGE of the tile in world dimension (don't use this directly to get tilewise coord!!)
|
// points to the EDGE of the tile in world dimension (don't use this directly to get tilewise coord!!)
|
||||||
val offendingTileWorldY = if (selfCollisionStatus in listOf(3, 6))
|
val offendingTileWorldY = if (selfCollisionStatus in listOf(3, 6))
|
||||||
newHitbox.endY.div(TILE_SIZE).floor() * TILE_SIZE - PHYS_EPSILON_DIST
|
newHitbox.endY.div(TILE_SIZE).floorToDouble() * TILE_SIZE - PHYS_EPSILON_DIST
|
||||||
else
|
else
|
||||||
newHitbox.startY.div(TILE_SIZE).ceil() * TILE_SIZE
|
newHitbox.startY.div(TILE_SIZE).ceilToDouble() * TILE_SIZE
|
||||||
|
|
||||||
val offendingHitboxPointX = if (selfCollisionStatus in listOf(6, 12))
|
val offendingHitboxPointX = if (selfCollisionStatus in listOf(6, 12))
|
||||||
newHitbox.endX
|
newHitbox.endX
|
||||||
@@ -927,7 +912,6 @@ open class ActorWithBody : Actor {
|
|||||||
newHitbox.startY
|
newHitbox.startY
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val angleOfIncidence =
|
val angleOfIncidence =
|
||||||
if (selfCollisionStatus in listOf(3, 9))
|
if (selfCollisionStatus in listOf(3, 9))
|
||||||
vectorSum.direction.toPositiveRad()
|
vectorSum.direction.toPositiveRad()
|
||||||
@@ -942,10 +926,15 @@ open class ActorWithBody : Actor {
|
|||||||
(Vector2(offendingHitboxPointX, offendingHitboxPointY) -
|
(Vector2(offendingHitboxPointX, offendingHitboxPointY) -
|
||||||
Vector2(offendingTileWorldX, offendingTileWorldY)).direction
|
Vector2(offendingTileWorldX, offendingTileWorldY)).direction
|
||||||
|
|
||||||
|
debug1(
|
||||||
|
"incidentAngle: ${Math.toDegrees(angleOfIncidence)}°, threshold: ${
|
||||||
|
Math.toDegrees(
|
||||||
|
angleThreshold
|
||||||
|
)
|
||||||
|
}°"
|
||||||
|
)
|
||||||
|
|
||||||
debug1("vectorSum: $vectorSum, vectorDirRaw: ${vectorSum.direction / Math.PI}pi")
|
debug1("offendingTileWorldY=$offendingTileWorldY, offendingHitboxPointY=$offendingHitboxPointY")
|
||||||
debug1("incidentAngle: ${angleOfIncidence / Math.PI}pi, threshold: ${angleThreshold / Math.PI}pi")
|
|
||||||
|
|
||||||
|
|
||||||
val displacementAbs = Vector2(
|
val displacementAbs = Vector2(
|
||||||
(offendingTileWorldX - offendingHitboxPointX).abs(),
|
(offendingTileWorldX - offendingHitboxPointX).abs(),
|
||||||
@@ -957,35 +946,57 @@ open class ActorWithBody : Actor {
|
|||||||
|
|
||||||
val displacementUnitVector =
|
val displacementUnitVector =
|
||||||
if (angleOfIncidence == angleThreshold)
|
if (angleOfIncidence == angleThreshold)
|
||||||
-vectorSum
|
-vectorSum.signum
|
||||||
else {
|
else {
|
||||||
when (selfCollisionStatus) {
|
when (selfCollisionStatus) {
|
||||||
3 -> if (angleOfIncidence > angleThreshold) Vector2(1.0, 0.0) else Vector2(0.0, -1.0)
|
3 -> if (angleOfIncidence > angleThreshold) Vector2(1.0, 0.0)
|
||||||
6 -> if (angleOfIncidence > angleThreshold) Vector2(0.0, -1.0) else Vector2(-1.0, 0.0)
|
else Vector2(
|
||||||
|
0.0,
|
||||||
|
-1.0
|
||||||
|
)
|
||||||
|
|
||||||
|
6 -> if (angleOfIncidence > angleThreshold) Vector2(0.0, -1.0)
|
||||||
|
else Vector2(
|
||||||
|
-1.0,
|
||||||
|
0.0
|
||||||
|
)
|
||||||
|
|
||||||
9 -> if (angleOfIncidence > angleThreshold) Vector2(0.0, 1.0) else Vector2(1.0, 0.0)
|
9 -> if (angleOfIncidence > angleThreshold) Vector2(0.0, 1.0) else Vector2(1.0, 0.0)
|
||||||
12 -> if (angleOfIncidence > angleThreshold) Vector2(-1.0, 0.0) else Vector2(0.0, 1.0)
|
12 -> if (angleOfIncidence > angleThreshold) Vector2(-1.0, 0.0)
|
||||||
|
else Vector2(
|
||||||
|
0.0,
|
||||||
|
1.0
|
||||||
|
)
|
||||||
|
|
||||||
else -> throw InternalError("Blame hardware or universe")
|
else -> throw InternalError("Blame hardware or universe")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val finalDisplacement =
|
val finalDisplacement =
|
||||||
if (angleOfIncidence == angleThreshold)
|
// if (angleOfIncidence == angleThreshold)
|
||||||
displacementUnitVector
|
// displacementUnitVector
|
||||||
else
|
// else
|
||||||
Vector2(
|
Vector2(
|
||||||
displacementAbs.x * displacementUnitVector.x,
|
displacementAbs.x * displacementUnitVector.x,
|
||||||
displacementAbs.y * displacementUnitVector.y
|
displacementAbs.y * displacementUnitVector.y
|
||||||
)
|
)
|
||||||
|
|
||||||
|
debug1("displacementAbs=$displacementAbs")
|
||||||
|
debug1("displacementUnitVector=$displacementUnitVector")
|
||||||
|
debug1("finalDisplacement=$finalDisplacement")
|
||||||
|
|
||||||
// adjust finalDisplacement for honest-to-god staircasing
|
// adjust finalDisplacement for honest-to-god staircasing
|
||||||
if (physProp.useStairs && vectorSum.y <= 0.0 && staircaseStatus in listOf(1, 4) && selfCollisionStatus in (if (gravitation.y >= 0.0) listOf(3,6) else listOf(9, 12))) {
|
if (physProp.useStairs && vectorSum.y <= 0.0 && staircaseStatus in listOf(1, 4) &&
|
||||||
|
selfCollisionStatus in (if (gravitation.y >= 0.0) listOf(3, 6) else listOf(9, 12))
|
||||||
|
) {
|
||||||
// remove Y displacement
|
// remove Y displacement
|
||||||
// let original X velocity to pass-thru instead of snapping to tiles coded above
|
// let original X velocity to pass-thru instead of snapping to tiles coded above
|
||||||
// pass-thru values are held by the vectorSum
|
// pass-thru values are held by the vectorSum
|
||||||
|
|
||||||
//println("staircasing: $staircaseStatus for $selfCollisionStatus")
|
debug1("staircasing: $staircaseStatus for $selfCollisionStatus")
|
||||||
|
|
||||||
val stairHeight = if (staircaseStatus == COLLIDING_LEFT) stairHeightLeft else stairHeightRight
|
val stairHeight =
|
||||||
|
if (staircaseStatus == COLLIDING_LEFT) stairHeightLeft else stairHeightRight
|
||||||
finalDisplacement.y = -stairHeight
|
finalDisplacement.y = -stairHeight
|
||||||
finalDisplacement.x = vectorSum.x
|
finalDisplacement.x = vectorSum.x
|
||||||
|
|
||||||
@@ -998,7 +1009,8 @@ open class ActorWithBody : Actor {
|
|||||||
// so we also zero the same exact value here for perfect hiding
|
// so we also zero the same exact value here for perfect hiding
|
||||||
if (controllerV != null) {
|
if (controllerV != null) {
|
||||||
val stairRatio = stairHeight / hitbox.height
|
val stairRatio = stairHeight / hitbox.height
|
||||||
stairPenaltyVector = Math.pow(1.0 - (stairRatio), 90 * stairRatio).times(10).coerceIn(0.00005, 1.0)
|
stairPenaltyVector =
|
||||||
|
Math.pow(1.0 - (stairRatio), 90 * stairRatio).times(10).coerceIn(0.00005, 1.0)
|
||||||
controllerV!!.x = 0.0
|
controllerV!!.x = 0.0
|
||||||
stairPenaltyCounter = 0
|
stairPenaltyCounter = 0
|
||||||
stairPenaltyMax = Math.pow(stairRatio, 2.4).times(166).roundToInt().coerceAtMost(64)
|
stairPenaltyMax = Math.pow(stairRatio, 2.4).times(166).roundToInt().coerceAtMost(64)
|
||||||
@@ -1021,7 +1033,6 @@ open class ActorWithBody : Actor {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// bounce X/Y
|
// bounce X/Y
|
||||||
if (bounceX) {
|
if (bounceX) {
|
||||||
externalV.x *= elasticity
|
externalV.x *= elasticity
|
||||||
@@ -1042,6 +1053,7 @@ open class ActorWithBody : Actor {
|
|||||||
|
|
||||||
|
|
||||||
hitbox.reassign(newHitbox)
|
hitbox.reassign(newHitbox)
|
||||||
|
debug1("resulting hitbox: $newHitbox")
|
||||||
|
|
||||||
|
|
||||||
// slam-into-whatever damage (such dirty; much hack; wow)
|
// slam-into-whatever damage (such dirty; much hack; wow)
|
||||||
@@ -1055,104 +1067,87 @@ open class ActorWithBody : Actor {
|
|||||||
// grounded = true
|
// grounded = true
|
||||||
|
|
||||||
// another platform-related hacks
|
// another platform-related hacks
|
||||||
if (this is ActorHumanoid) downDownVirtually = false
|
// if (this is ActorHumanoid) downButtonHeld = false
|
||||||
|
|
||||||
|
}
|
||||||
}// end of collision not detected
|
}// end of collision not detected
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// if collision not detected, just don't care; it's not your job to apply moveDelta
|
// if collision not detected, just don't care; it's not your job to apply moveDelta
|
||||||
|
|
||||||
}
|
} // end of (world != null)
|
||||||
}
|
|
||||||
|
|
||||||
fun collisionInterpolatorRun() {
|
|
||||||
|
|
||||||
fun isWalled2(hitbox: Hitbox, option: Int): Boolean {
|
|
||||||
val newHB = Hitbox.fromTwoPoints(
|
|
||||||
hitbox.startX + A_PIXEL, hitbox.startY + A_PIXEL,
|
|
||||||
hitbox.endX - A_PIXEL, hitbox.endY - A_PIXEL
|
|
||||||
)
|
|
||||||
|
|
||||||
return isWalled(newHB, option)
|
|
||||||
}
|
|
||||||
|
|
||||||
// kinda works but the jump is inconsistent because of the nondeterministic nature of the values (doesn't get fixed to the integer value when collided)
|
|
||||||
|
|
||||||
if (world != null) {
|
|
||||||
val intpStep = 64.0
|
|
||||||
|
|
||||||
// make interpolation even if the "next" position is clear of collision
|
|
||||||
val testHitbox = hitbox.clone()
|
|
||||||
|
|
||||||
// divide the vectors by the constant
|
|
||||||
externalV /= intpStep
|
|
||||||
controllerV?.let { controllerV!! /= intpStep }
|
|
||||||
|
|
||||||
repeat(intpStep.toInt()) { // basically we don't care if we're already been encased (e.g. entrapped by falling sand)
|
|
||||||
|
|
||||||
// change the order and the player gets stuck in the vertical wall
|
|
||||||
// so leave as-is
|
|
||||||
|
|
||||||
testHitbox.translate(externalV + controllerV)
|
|
||||||
|
|
||||||
// vertical collision
|
|
||||||
if (isWalled2(testHitbox, COLLIDING_UD)) {
|
|
||||||
externalV.y *= elasticity // TODO also multiply the friction value
|
|
||||||
controllerV?.let { controllerV!!.y *= elasticity } // TODO also multiply the friction value
|
|
||||||
}
|
|
||||||
// horizontal collision
|
|
||||||
if (isWalled2(testHitbox, COLLIDING_LR)) {
|
|
||||||
externalV.x *= elasticity // TODO also multiply the friction value
|
|
||||||
controllerV?.let { controllerV!!.x *= elasticity } // TODO also multiply the friction value
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
hitbox.reassign(testHitbox)
|
|
||||||
|
|
||||||
// revert the division because the Acceleration depends on being able to integrate onto the velo values
|
|
||||||
// don't want to mess up with the value they're expecting
|
|
||||||
externalV *= intpStep
|
|
||||||
controllerV?.let { controllerV!! *= intpStep }
|
|
||||||
|
|
||||||
// TODO collision damage
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see /work_files/hitbox_collision_detection_compensation.jpg
|
* @see /work_files/hitbox_collision_detection_compensation.jpg
|
||||||
*/
|
*/
|
||||||
private fun isColliding(hitbox: Hitbox, feet: Boolean = false): Boolean {
|
private fun isColliding(hitbox: Hitbox, usePlatformDetection: Boolean = false): Boolean {
|
||||||
if (isNoCollideWorld) return false
|
if (isNoCollideWorld) return false
|
||||||
|
|
||||||
// detectors are inside of the bounding box
|
// detectors are inside of the bounding box
|
||||||
// CONFIRMED
|
|
||||||
val x1 = hitbox.startX
|
val x1 = hitbox.startX
|
||||||
val x2 = hitbox.endX - A_PIXEL
|
val y1 = hitbox.startY - if (gravitation.y < 0) HALF_PIXEL else 0.0
|
||||||
val y1 = hitbox.startY
|
val x2 = hitbox.endX - PHYS_EPSILON_DIST
|
||||||
val y2 = hitbox.endY - A_PIXEL
|
val y2 = hitbox.endY + if (gravitation.y >= 0) HALF_PIXEL else 0.0 // PLUS HALF PIXEL AND NOT MINUS EPSILON to fix issue #48 and #49
|
||||||
|
|
||||||
// this commands and the commands on isWalled WILL NOT match (1 px gap on endX/Y). THIS IS INTENTIONAL!
|
// this commands and the commands on isWalled WILL NOT match (1 px gap on endX/Y). THIS IS INTENTIONAL!
|
||||||
|
|
||||||
val txStart = x1.plus(HALF_PIXEL).floorInt()
|
val txStart = x1/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||||
val txEnd = x2.plus(HALF_PIXEL).floorInt()
|
val txEnd = x2/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||||
val tyStart = y1.plus(HALF_PIXEL).floorInt()
|
val tyStart = y1/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||||
val tyEnd = y2.plus(HALF_PIXEL).floorInt()
|
val tyEnd = y2/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||||
|
|
||||||
return isCollidingInternalStairs(txStart, tyStart, txEnd, tyEnd, feet).first > 0
|
// return isCollidingInternalStairs(txStart, if (feet) tyEnd else tyStart, txEnd, tyEnd, feet).first > 0
|
||||||
|
return isCollidingInternalStairs(txStart, tyStart, txEnd, tyEnd, usePlatformDetection).first > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Hitbox.getWallDetection(option: Int): List<Double> {
|
||||||
|
val x1: Double
|
||||||
|
val x2: Double
|
||||||
|
val y1: Double
|
||||||
|
val y2: Double
|
||||||
|
when (option) {
|
||||||
|
COLLIDING_TOP -> {
|
||||||
|
x1 = this.startX
|
||||||
|
x2 = this.endX - PHYS_EPSILON_DIST
|
||||||
|
y1 = this.startY - A_PIXEL
|
||||||
|
y2 = y1
|
||||||
|
}
|
||||||
|
COLLIDING_BOTTOM -> {
|
||||||
|
x1 = this.startX
|
||||||
|
x2 = this.endX - PHYS_EPSILON_DIST
|
||||||
|
y1 = this.endY - PHYS_EPSILON_DIST + A_PIXEL
|
||||||
|
y2 = y1
|
||||||
|
}
|
||||||
|
COLLIDING_LEFT -> {
|
||||||
|
x1 = this.startX - A_PIXEL
|
||||||
|
x2 = x1
|
||||||
|
y1 = this.startY
|
||||||
|
y2 = this.endY - PHYS_EPSILON_DIST
|
||||||
|
}
|
||||||
|
COLLIDING_RIGHT -> {
|
||||||
|
x1 = this.endX - PHYS_EPSILON_DIST + A_PIXEL
|
||||||
|
x2 = x1
|
||||||
|
y1 = this.startY
|
||||||
|
y2 = this.endY - PHYS_EPSILON_DIST
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("Unknown option $option")
|
||||||
|
}
|
||||||
|
return listOf(x1, x2, y1, y2)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Int.popcnt() = Integer.bitCount(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see /work_files/hitbox_collision_detection_compensation.jpg
|
* @see /work_files/hitbox_collision_detection_compensation.jpg
|
||||||
*/
|
*/
|
||||||
fun isWalled(hitbox: Hitbox, option: Int): Boolean {
|
fun isWalled(hitbox: Hitbox, option: Int): Boolean {
|
||||||
val x1: Double
|
|
||||||
val x2: Double
|
|
||||||
val y1: Double
|
|
||||||
val y2: Double
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The structure:
|
The structure:
|
||||||
|
|
||||||
@@ -1165,30 +1160,15 @@ open class ActorWithBody : Actor {
|
|||||||
IMPORTANT AF NOTE: things are ASYMMETRIC!
|
IMPORTANT AF NOTE: things are ASYMMETRIC!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// AT LEAST THESE ARE CONFIRMED
|
if (option.popcnt() == 1) {
|
||||||
if (option == COLLIDING_TOP) {
|
val (x1, x2, y1, y2) = hitbox.getWallDetection(option)
|
||||||
x1 = hitbox.startX
|
|
||||||
x2 = hitbox.endX - A_PIXEL
|
val txStart = x1/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||||
y1 = hitbox.startY - A_PIXEL
|
val txEnd = x2/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||||
y2 = y1
|
val tyStart = y1/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||||
}
|
val tyEnd = y2/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||||
else if (option == COLLIDING_BOTTOM) {
|
|
||||||
x1 = hitbox.startX
|
return isCollidingInternalStairs(txStart, tyStart, txEnd, tyEnd, option == COLLIDING_BOTTOM).first == 2
|
||||||
x2 = hitbox.endX - A_PIXEL
|
|
||||||
y1 = hitbox.endY + A_PIXEL
|
|
||||||
y2 = y1
|
|
||||||
}
|
|
||||||
else if (option == COLLIDING_LEFT) {
|
|
||||||
x1 = hitbox.startX - A_PIXEL
|
|
||||||
x2 = x1
|
|
||||||
y1 = hitbox.startY
|
|
||||||
y2 = hitbox.endY - A_PIXEL
|
|
||||||
}
|
|
||||||
else if (option == COLLIDING_RIGHT) {
|
|
||||||
x1 = hitbox.endX + A_PIXEL
|
|
||||||
x2 = x1
|
|
||||||
y1 = hitbox.startY
|
|
||||||
y2 = hitbox.endY - A_PIXEL
|
|
||||||
}
|
}
|
||||||
else if (option == COLLIDING_ALLSIDE) {
|
else if (option == COLLIDING_ALLSIDE) {
|
||||||
return isWalled(hitbox, COLLIDING_LEFT) || isWalled(hitbox, COLLIDING_RIGHT) ||
|
return isWalled(hitbox, COLLIDING_LEFT) || isWalled(hitbox, COLLIDING_RIGHT) ||
|
||||||
@@ -1201,25 +1181,14 @@ open class ActorWithBody : Actor {
|
|||||||
else if (option == COLLIDING_UD) {
|
else if (option == COLLIDING_UD) {
|
||||||
return isWalled(hitbox, COLLIDING_BOTTOM) || isWalled(hitbox, COLLIDING_TOP)
|
return isWalled(hitbox, COLLIDING_BOTTOM) || isWalled(hitbox, COLLIDING_TOP)
|
||||||
}
|
}
|
||||||
else throw IllegalArgumentException()
|
else throw IllegalArgumentException("$option")
|
||||||
|
|
||||||
val txStart = x1.plus(HALF_PIXEL).floorInt()
|
|
||||||
val txEnd = x2.plus(HALF_PIXEL).floorInt()
|
|
||||||
val tyStart = y1.plus(HALF_PIXEL).floorInt()
|
|
||||||
val tyEnd = y2.plus(HALF_PIXEL).floorInt()
|
|
||||||
|
|
||||||
return isCollidingInternalStairs(txStart, tyStart, txEnd, tyEnd, option == COLLIDING_BOTTOM).first == 2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return First int: 0 - no collision, 1 - staircasing, 2 - "bonk" to the wall; Second int: stair height
|
* @return First int: 0 - no collision, 1 - staircasing, 2 - "bonk" to the wall; Second int: stair height
|
||||||
*/
|
*/
|
||||||
private fun isWalledStairs(hitbox: Hitbox, option: Int): Pair<Int, Int> {
|
private fun isWalledStairs(hitbox: Hitbox, option: Int): Pair<Int, Int> {
|
||||||
val x1: Double
|
|
||||||
val x2: Double
|
|
||||||
val y1: Double
|
|
||||||
val y2: Double
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The structure:
|
The structure:
|
||||||
|
|
||||||
@@ -1232,81 +1201,36 @@ open class ActorWithBody : Actor {
|
|||||||
IMPORTANT AF NOTE: things are ASYMMETRIC!
|
IMPORTANT AF NOTE: things are ASYMMETRIC!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// AT LEAST THESE ARE CONFIRMED
|
if (option.popcnt() == 1) {
|
||||||
if (option == COLLIDING_TOP) {
|
val (x1, x2, y1, y2) = hitbox.getWallDetection(option)
|
||||||
x1 = hitbox.startX
|
|
||||||
x2 = hitbox.endX - A_PIXEL
|
val pxStart = x1/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||||
y1 = hitbox.startY - A_PIXEL
|
val pxEnd = x2/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||||
y2 = y1
|
val pyStart = y1/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||||
}
|
val pyEnd = y2/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||||
else if (option == COLLIDING_BOTTOM) {
|
|
||||||
x1 = hitbox.startX
|
return isCollidingInternalStairs(pxStart, pyStart, pxEnd, pyEnd, option == COLLIDING_BOTTOM)
|
||||||
x2 = hitbox.endX - A_PIXEL
|
|
||||||
y1 = hitbox.endY + A_PIXEL
|
|
||||||
y2 = y1
|
|
||||||
}
|
|
||||||
else if (option == COLLIDING_LEFT) {
|
|
||||||
x1 = hitbox.startX - A_PIXEL
|
|
||||||
x2 = x1
|
|
||||||
y1 = hitbox.startY
|
|
||||||
y2 = hitbox.endY - A_PIXEL
|
|
||||||
}
|
|
||||||
else if (option == COLLIDING_RIGHT) {
|
|
||||||
x1 = hitbox.endX + A_PIXEL
|
|
||||||
x2 = x1
|
|
||||||
y1 = hitbox.startY
|
|
||||||
y2 = hitbox.endY - A_PIXEL
|
|
||||||
}
|
}
|
||||||
else if (option == COLLIDING_ALLSIDE) {
|
else if (option == COLLIDING_ALLSIDE) {
|
||||||
return maxOf(maxOf(isWalledStairs(hitbox, COLLIDING_LEFT).first,
|
return max(max(isWalledStairs(hitbox, COLLIDING_LEFT).first,
|
||||||
isWalledStairs(hitbox, COLLIDING_RIGHT).first),
|
isWalledStairs(hitbox, COLLIDING_RIGHT).first),
|
||||||
maxOf(isWalledStairs(hitbox, COLLIDING_BOTTOM).first,
|
max(isWalledStairs(hitbox, COLLIDING_BOTTOM).first,
|
||||||
isWalledStairs(hitbox, COLLIDING_TOP).first)) to 0
|
isWalledStairs(hitbox, COLLIDING_TOP).first)) to 0
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (option == COLLIDING_LR) {
|
else if (option == COLLIDING_LR) {
|
||||||
val v1 = isWalledStairs(hitbox, COLLIDING_LEFT)
|
val v1 = isWalledStairs(hitbox, COLLIDING_LEFT)
|
||||||
val v2 = isWalledStairs(hitbox, COLLIDING_RIGHT)
|
val v2 = isWalledStairs(hitbox, COLLIDING_RIGHT)
|
||||||
return maxOf(v1.first, v2.first) to maxOf(v2.first, v2.second)
|
return max(v1.first, v2.first) to max(v2.first, v2.second)
|
||||||
}
|
}
|
||||||
else if (option == COLLIDING_UD) {
|
else if (option == COLLIDING_UD) {
|
||||||
return maxOf(isWalledStairs(hitbox, COLLIDING_BOTTOM).first,
|
return max(isWalledStairs(hitbox, COLLIDING_BOTTOM).first,
|
||||||
isWalledStairs(hitbox, COLLIDING_TOP).first) to 0
|
isWalledStairs(hitbox, COLLIDING_TOP).first) to 0
|
||||||
}
|
}
|
||||||
else throw IllegalArgumentException("$option")
|
else throw IllegalArgumentException("$option")
|
||||||
|
|
||||||
val pxStart = x1.plus(0.5f).floorInt()
|
|
||||||
val pxEnd = x2.plus(0.5f).floorInt()
|
|
||||||
val pyStart = y1.plus(0.5f).floorInt()
|
|
||||||
val pyEnd = y2.plus(0.5f).floorInt()
|
|
||||||
|
|
||||||
return isCollidingInternalStairs(pxStart, pyStart, pxEnd, pyEnd, gravitation.y >= 0.0 && option == COLLIDING_BOTTOM || gravitation.y < 0.0 && option == COLLIDING_TOP)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*private fun isCollidingInternal(txStart: Int, tyStart: Int, txEnd: Int, tyEnd: Int, feet: Boolean = false): Boolean {
|
|
||||||
if (world == null) return false
|
|
||||||
|
|
||||||
for (y in tyStart..tyEnd) {
|
|
||||||
for (x in txStart..txEnd) {
|
|
||||||
val tile = world!!.getTileFromTerrain(x, y)
|
|
||||||
|
|
||||||
if (feet) {
|
|
||||||
if (shouldICollideWithThisFeet(tile))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (shouldICollideWithThis(tile))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// this weird statement means that if's the condition is TRUE, return TRUE;
|
|
||||||
// if the condition is FALSE, do nothing and let succeeding code handle it.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}*/
|
|
||||||
|
|
||||||
private val AUTO_CLIMB_STRIDE: Int
|
private val AUTO_CLIMB_STRIDE: Int
|
||||||
get() = ((actorValue.getAsInt(AVKey.VERTSTRIDE) ?: 8) * scale).toInt()
|
get() = ((actorValue.getAsInt(AVKey.VERTSTRIDE) ?: 8) * scale).toInt()
|
||||||
//private val AUTO_CLIMB_RATE: Int // we'll just climb stairs instantly to make things work wo worrying about the details
|
//private val AUTO_CLIMB_RATE: Int // we'll just climb stairs instantly to make things work wo worrying about the details
|
||||||
@@ -1323,16 +1247,24 @@ open class ActorWithBody : Actor {
|
|||||||
var stairHeight = 0
|
var stairHeight = 0
|
||||||
var hitFloor = false
|
var hitFloor = false
|
||||||
|
|
||||||
|
// if (ys.last != ys.first && feet) throw InternalError("Feet mode collision but pyStart != pyEnd ($pyStart .. $pyEnd)")
|
||||||
|
|
||||||
|
val feetY = (pyEnd / TILE_SIZED).floorToInt() // round down toward negative infinity // TODO reverse gravity adaptation?
|
||||||
|
|
||||||
|
// if (feet && this is IngamePlayer) printdbg(this, "dim=($pxStart,$pyStart)-($pxEnd,$pyEnd), feetY=$feetY")
|
||||||
|
|
||||||
for (y in ys) {
|
for (y in ys) {
|
||||||
|
|
||||||
|
val ty = (y / TILE_SIZED).floorToInt() // round down toward negative infinity
|
||||||
|
// if (this is IngamePlayer) printdbg(this, "ty=${ty}")
|
||||||
|
val isFeetTileHeight = (ty == feetY)
|
||||||
var hasFloor = false
|
var hasFloor = false
|
||||||
|
|
||||||
for (x in pxStart..pxEnd) {
|
for (x in pxStart..pxEnd) {
|
||||||
val tx = (x / TILE_SIZE) - (if (x < 0) 1 else 0) // round down toward negative infinity
|
val tx = (x / TILE_SIZED).floorToInt() // round down toward negative infinity
|
||||||
val ty = (y / TILE_SIZE) - (if (y < 0) 1 else 0) // round down toward negative infinity
|
|
||||||
val tile = world!!.getTileFromTerrain(tx, ty)
|
val tile = world!!.getTileFromTerrain(tx, ty)
|
||||||
|
|
||||||
if (feet) {
|
if (feet && isFeetTileHeight) {
|
||||||
if (shouldICollideWithThisFeet(tile)) {
|
if (shouldICollideWithThisFeet(tile)) {
|
||||||
hasFloor = true
|
hasFloor = true
|
||||||
hitFloor = true
|
hitFloor = true
|
||||||
@@ -1364,7 +1296,7 @@ open class ActorWithBody : Actor {
|
|||||||
//println("-> $stairHeight")
|
//println("-> $stairHeight")
|
||||||
|
|
||||||
// edge-detect mode
|
// edge-detect mode
|
||||||
return if (yheight == 0) hitFloor.toInt() * 2 to stairHeight
|
return if (yheight == 0) hitFloor.toInt(1) to stairHeight
|
||||||
// not an edge-detect && no collision
|
// not an edge-detect && no collision
|
||||||
else if (stairHeight == 0) 0 to 0
|
else if (stairHeight == 0) 0 to 0
|
||||||
// there was collision and stairHeight <= AUTO_CLIMB_STRIDE
|
// there was collision and stairHeight <= AUTO_CLIMB_STRIDE
|
||||||
@@ -1404,7 +1336,7 @@ open class ActorWithBody : Actor {
|
|||||||
// platforms, moving downward AND not "going down"
|
// platforms, moving downward AND not "going down"
|
||||||
(this is ActorHumanoid && BlockCodex[tile].isPlatform &&
|
(this is ActorHumanoid && BlockCodex[tile].isPlatform &&
|
||||||
externalV.y + (controllerV?.y ?: 0.0) >= 0.0 &&
|
externalV.y + (controllerV?.y ?: 0.0) >= 0.0 &&
|
||||||
!downDownVirtually && !this.isDownDown && this.axisY <= 0f) ||
|
this.downButtonHeld == 0 && this.axisY <= 0f) ||
|
||||||
// platforms, moving downward, for the case of NOT ActorHumanoid
|
// platforms, moving downward, for the case of NOT ActorHumanoid
|
||||||
(this !is ActorHumanoid && BlockCodex[tile].isPlatform &&
|
(this !is ActorHumanoid && BlockCodex[tile].isPlatform &&
|
||||||
externalV.y + (controllerV?.y ?: 0.0) >= 0.0)
|
externalV.y + (controllerV?.y ?: 0.0) >= 0.0)
|
||||||
@@ -1744,8 +1676,8 @@ open class ActorWithBody : Actor {
|
|||||||
if (KeyToggler.isOn(Input.Keys.F9)) {
|
if (KeyToggler.isOn(Input.Keys.F9)) {
|
||||||
val blockMark = CommonResourcePool.getAsTextureRegionPack("blockmarkings_common").get(0, 0)
|
val blockMark = CommonResourcePool.getAsTextureRegionPack("blockmarkings_common").get(0, 0)
|
||||||
|
|
||||||
batch.color = HITBOX_COLOURS0
|
for (y in 0..intTilewiseHitbox.height.toInt() + 1) {
|
||||||
for (y in 0..intTilewiseHitbox.height.toInt()) {
|
batch.color = if (y == intTilewiseHitbox.height.toInt() + 1) HITBOX_COLOURS1 else HITBOX_COLOURS0
|
||||||
for (x in 0..intTilewiseHitbox.width.toInt()) {
|
for (x in 0..intTilewiseHitbox.width.toInt()) {
|
||||||
batch.draw(blockMark,
|
batch.draw(blockMark,
|
||||||
(intTilewiseHitbox.startX.toFloat() + x) * TILE_SIZEF,
|
(intTilewiseHitbox.startX.toFloat() + x) * TILE_SIZEF,
|
||||||
@@ -1754,6 +1686,7 @@ open class ActorWithBody : Actor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
batch.color = Color.WHITE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1761,9 +1694,12 @@ open class ActorWithBody : Actor {
|
|||||||
if (world == null) return
|
if (world == null) return
|
||||||
|
|
||||||
val offsetX = 0f
|
val offsetX = 0f
|
||||||
val offsetY = 1f // plant to the ground
|
val offsetY = 0f // for some reason this value must be zero to draw the actor planted to the ground
|
||||||
|
|
||||||
drawBodyInGoodPosition(hitbox.startX.toFloat(), hitbox.startY.toFloat()) { x, y ->
|
val posX = hitbox.startX.plus(PHYS_EPSILON_DIST).toFloat()
|
||||||
|
val posY = hitbox.startY.plus(PHYS_EPSILON_DIST).toFloat()
|
||||||
|
|
||||||
|
drawBodyInGoodPosition(posX, posY) { x, y ->
|
||||||
sprite.render(batch, x + offsetX, y + offsetY, scale.toFloat())
|
sprite.render(batch, x + offsetX, y + offsetY, scale.toFloat())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1890,10 +1826,10 @@ open class ActorWithBody : Actor {
|
|||||||
|
|
||||||
|
|
||||||
val newTilewiseHitbox = Hitbox.fromTwoPoints(
|
val newTilewiseHitbox = Hitbox.fromTwoPoints(
|
||||||
hitbox.startX.div(TILE_SIZE).floor(),
|
hitbox.startX.div(TILE_SIZE).floorToDouble(),
|
||||||
hitbox.startY.div(TILE_SIZE).floor(),
|
hitbox.startY.div(TILE_SIZE).floorToDouble(),
|
||||||
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(),
|
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
|
||||||
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor(),
|
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
|
||||||
true
|
true
|
||||||
) // NOT the same as intTilewiseHitbox !!
|
) // NOT the same as intTilewiseHitbox !!
|
||||||
|
|
||||||
@@ -1914,10 +1850,10 @@ open class ActorWithBody : Actor {
|
|||||||
val tiles = ArrayList<ItemID?>()
|
val tiles = ArrayList<ItemID?>()
|
||||||
|
|
||||||
// offset 1 pixel to the down so that friction would work
|
// offset 1 pixel to the down so that friction would work
|
||||||
val y = hitbox.endY.plus(1.0).div(TILE_SIZE).floorInt()
|
val y = intTilewiseHitbox.height.toInt() + 1
|
||||||
|
|
||||||
for (x in hIntTilewiseHitbox.startX.toInt()..hIntTilewiseHitbox.endX.toInt()) {
|
for (x in 0..intTilewiseHitbox.width.toInt()) {
|
||||||
tiles.add(world!!.getTileFromTerrain(x, y))
|
tiles.add(world!!.getTileFromTerrain(x + intTilewiseHitbox.startX.toInt(), y + intTilewiseHitbox.startY.toInt()))
|
||||||
}
|
}
|
||||||
|
|
||||||
return tiles.forEach(consumer)
|
return tiles.forEach(consumer)
|
||||||
@@ -1930,10 +1866,11 @@ open class ActorWithBody : Actor {
|
|||||||
val tileProps = ArrayList<BlockProp?>()
|
val tileProps = ArrayList<BlockProp?>()
|
||||||
|
|
||||||
// offset 1 pixel to the down so that friction would work
|
// offset 1 pixel to the down so that friction would work
|
||||||
val y = hitbox.endY.plus(1.0).div(TILE_SIZE).floorInt()
|
// val y = hitbox.endY.plus(1.0).div(TILE_SIZE).floorToInt()
|
||||||
|
val y = intTilewiseHitbox.height.toInt() + 1
|
||||||
|
|
||||||
for (x in hIntTilewiseHitbox.startX.toInt()..hIntTilewiseHitbox.endX.toInt()) {
|
for (x in 0..intTilewiseHitbox.width.toInt()) {
|
||||||
tileProps.add(BlockCodex[world!!.getTileFromTerrain(x, y)])
|
tileProps.add(BlockCodex[world!!.getTileFromTerrain(x + intTilewiseHitbox.startX.toInt(), y + intTilewiseHitbox.startY.toInt())])
|
||||||
}
|
}
|
||||||
|
|
||||||
return tileProps.forEach(consumer)
|
return tileProps.forEach(consumer)
|
||||||
@@ -1962,8 +1899,8 @@ open class ActorWithBody : Actor {
|
|||||||
*/
|
*/
|
||||||
@Transient const val GAME_TO_SI_ACC = (Terrarum.PHYS_TIME_FRAME * Terrarum.PHYS_TIME_FRAME) / METER
|
@Transient const val GAME_TO_SI_ACC = (Terrarum.PHYS_TIME_FRAME * Terrarum.PHYS_TIME_FRAME) / METER
|
||||||
|
|
||||||
@Transient const val PHYS_EPSILON_DIST = 1.0 / 65536.0
|
@Transient const val PHYS_EPSILON_DIST = 1.0 / 4096.0
|
||||||
// @Transient const val PHYS_EPSILON_VELO = 1.0 / 8192.0
|
@Transient const val PHYS_EPSILON_VELO = 1.0 / 65536.0
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2004,6 +1941,7 @@ open class ActorWithBody : Actor {
|
|||||||
@Transient private val HITBOX_COLOURS0 = Color(0xFF00FF88.toInt())
|
@Transient private val HITBOX_COLOURS0 = Color(0xFF00FF88.toInt())
|
||||||
@Transient private val HITBOX_COLOURS1 = Color(0xFFFF0088.toInt())
|
@Transient private val HITBOX_COLOURS1 = Color(0xFFFF0088.toInt())
|
||||||
|
|
||||||
|
|
||||||
fun isCloseEnough(a: Double, b: Double) = ((a / b).let { if (it.isNaN()) 0.0 else it } - 1).absoluteValue < PHYS_EPSILON_DIST
|
fun isCloseEnough(a: Double, b: Double) = ((a / b).let { if (it.isNaN()) 0.0 else it } - 1).absoluteValue < PHYS_EPSILON_DIST
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -145,6 +145,9 @@ class Hitbox {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize the hitbox centred around the "canonical" point.
|
||||||
|
*/
|
||||||
fun canonicalResize(w: Double, h: Double): Hitbox {
|
fun canonicalResize(w: Double, h: Double): Hitbox {
|
||||||
// sx_1 + 0.5w_1 = sx_2 + 0.5w_2 // equals because the final point must not move. sx_1: old start-x, sx_2: new start-x which is what we want
|
// sx_1 + 0.5w_1 = sx_2 + 0.5w_2 // equals because the final point must not move. sx_1: old start-x, sx_2: new start-x which is what we want
|
||||||
// sx_2 = sx_1 + 0.5w_1 - 0.5w_2 // move variables to right-hand side to derive final value sx_2
|
// sx_2 = sx_1 + 0.5w_1 - 0.5w_2 // move variables to right-hand side to derive final value sx_2
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import net.torvald.terrarum.ItemCodex
|
|||||||
import net.torvald.terrarum.Terrarum
|
import net.torvald.terrarum.Terrarum
|
||||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||||
import net.torvald.terrarum.controller.TerrarumController
|
import net.torvald.terrarum.controller.TerrarumController
|
||||||
import net.torvald.terrarum.floorInt
|
import net.torvald.terrarum.floorToInt
|
||||||
import net.torvald.terrarum.gameactors.AVKey
|
import net.torvald.terrarum.gameactors.AVKey
|
||||||
import net.torvald.terrarum.gameitems.GameItem
|
import net.torvald.terrarum.gameitems.GameItem
|
||||||
import net.torvald.terrarum.gameworld.fmod
|
import net.torvald.terrarum.gameworld.fmod
|
||||||
@@ -42,10 +42,10 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
|||||||
get() = WorldCamera.y + Gdx.input.y / (terrarumIngame.screenZoom)
|
get() = WorldCamera.y + Gdx.input.y / (terrarumIngame.screenZoom)
|
||||||
/** currently pointing tile coordinate */
|
/** currently pointing tile coordinate */
|
||||||
val mouseTileX: Int
|
val mouseTileX: Int
|
||||||
get() = (mouseX / TILE_SIZE).floorInt()
|
get() = (mouseX / TILE_SIZE).floorToInt()
|
||||||
/** currently pointing tile coordinate */
|
/** currently pointing tile coordinate */
|
||||||
val mouseTileY: Int
|
val mouseTileY: Int
|
||||||
get() = (mouseY / TILE_SIZE).floorInt()
|
get() = (mouseY / TILE_SIZE).floorToInt()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import net.torvald.terrarum.savegame.ByteArray64
|
|||||||
import net.torvald.terrarum.utils.HashArray
|
import net.torvald.terrarum.utils.HashArray
|
||||||
import net.torvald.terrarum.utils.ZipCodedStr
|
import net.torvald.terrarum.utils.ZipCodedStr
|
||||||
import org.dyn4j.geometry.Vector2
|
import org.dyn4j.geometry.Vector2
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
typealias ItemID = String
|
typealias ItemID = String
|
||||||
|
|
||||||
@@ -358,6 +359,8 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun hasTag(s: String) = tags.contains(s)
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@@ -388,7 +391,7 @@ fun mouseInInteractableRange(actor: ActorWithBody, action: () -> Long): Long {
|
|||||||
val mousePos2 = Vector2(Terrarum.mouseX + INGAME.world.width * TILE_SIZED, Terrarum.mouseY)
|
val mousePos2 = Vector2(Terrarum.mouseX + INGAME.world.width * TILE_SIZED, Terrarum.mouseY)
|
||||||
val mousePos3 = Vector2(Terrarum.mouseX - INGAME.world.width * TILE_SIZED, Terrarum.mouseY)
|
val mousePos3 = Vector2(Terrarum.mouseX - INGAME.world.width * TILE_SIZED, Terrarum.mouseY)
|
||||||
val actorPos = actor.centrePosVector
|
val actorPos = actor.centrePosVector
|
||||||
val dist = minOf(actorPos.distanceSquared(mousePos1), actorPos.distanceSquared(mousePos2), actorPos.distanceSquared(mousePos3))
|
val dist = min(min(actorPos.distanceSquared(mousePos1), actorPos.distanceSquared(mousePos2)), actorPos.distanceSquared(mousePos3))
|
||||||
val distMax = actor.actorValue.getAsDouble(AVKey.REACH)!! * (actor.actorValue.getAsDouble(AVKey.REACHBUFF) ?: 1.0) * actor.scale // perform some error checking here
|
val distMax = actor.actorValue.getAsDouble(AVKey.REACH)!! * (actor.actorValue.getAsDouble(AVKey.REACHBUFF) ?: 1.0) * actor.scale // perform some error checking here
|
||||||
if (dist <= distMax.sqr()) return action() else return -1
|
if (dist <= distMax.sqr()) return action() else return -1
|
||||||
}
|
}
|
||||||
@@ -409,13 +412,13 @@ fun mouseInInteractableRangeTools(actor: ActorWithBody, item: GameItem?, reachMu
|
|||||||
val mousePos2 = Vector2(Terrarum.mouseX + INGAME.world.width * TILE_SIZED, Terrarum.mouseY)
|
val mousePos2 = Vector2(Terrarum.mouseX + INGAME.world.width * TILE_SIZED, Terrarum.mouseY)
|
||||||
val mousePos3 = Vector2(Terrarum.mouseX - INGAME.world.width * TILE_SIZED, Terrarum.mouseY)
|
val mousePos3 = Vector2(Terrarum.mouseX - INGAME.world.width * TILE_SIZED, Terrarum.mouseY)
|
||||||
val actorPos = actor.centrePosVector
|
val actorPos = actor.centrePosVector
|
||||||
val dist = minOf(actorPos.distanceSquared(mousePos1), actorPos.distanceSquared(mousePos2), actorPos.distanceSquared(mousePos3))
|
val dist = min(min(actorPos.distanceSquared(mousePos1), actorPos.distanceSquared(mousePos2)), actorPos.distanceSquared(mousePos3))
|
||||||
|
|
||||||
val reachBonus = (actor.actorValue.getAsDouble(AVKey.REACHBUFF) ?: 1.0) * actor.scale
|
val reachBonus = (actor.actorValue.getAsDouble(AVKey.REACHBUFF) ?: 1.0) * actor.scale
|
||||||
val distMax = actor.actorValue.getAsDouble(AVKey.REACH)!! * reachBonus // perform some error checking here
|
val distMax = actor.actorValue.getAsDouble(AVKey.REACH)!! * reachBonus // perform some error checking here
|
||||||
val toolDistMax = (TILE_SIZED * reachMultiplierInTiles(item?.material?.toolReach ?: Int.MAX_VALUE)) * reachBonus
|
val toolDistMax = (TILE_SIZED * reachMultiplierInTiles(item?.material?.toolReach ?: Int.MAX_VALUE)) * reachBonus
|
||||||
|
|
||||||
if (dist <= minOf(toolDistMax, distMax).sqr()) return action() else return false
|
if (dist <= min(toolDistMax, distMax).sqr()) return action() else return false
|
||||||
}
|
}
|
||||||
//fun IntRange.pickRandom() = HQRNG().nextInt(this.last - this.first + 1) + this.first // count() on 200 million entries? Se on vitun hyvää idea
|
//fun IntRange.pickRandom() = HQRNG().nextInt(this.last - this.first + 1) + this.first // count() on 200 million entries? Se on vitun hyvää idea
|
||||||
//fun IntArray.pickRandom(): Int = this[HQRNG().nextInt(this.size)]
|
//fun IntArray.pickRandom(): Int = this[HQRNG().nextInt(this.size)]
|
||||||
|
|||||||
@@ -46,12 +46,12 @@ open class ParticleBase(renderOrder: Actor.RenderOrder, val despawnUponCollision
|
|||||||
if (velocity.isZero ||
|
if (velocity.isZero ||
|
||||||
// simple stuck check
|
// simple stuck check
|
||||||
BlockCodex[(INGAME.world).getTileFromTerrain(
|
BlockCodex[(INGAME.world).getTileFromTerrain(
|
||||||
hitbox.centeredX.div(TerrarumAppConfiguration.TILE_SIZE).floorInt(),
|
hitbox.centeredX.div(TerrarumAppConfiguration.TILE_SIZE).floorToInt(),
|
||||||
hitbox.startY.div(TerrarumAppConfiguration.TILE_SIZE).floorInt()
|
hitbox.startY.div(TerrarumAppConfiguration.TILE_SIZE).floorToInt()
|
||||||
)].isSolid ||
|
)].isSolid ||
|
||||||
BlockCodex[(INGAME.world).getTileFromTerrain(
|
BlockCodex[(INGAME.world).getTileFromTerrain(
|
||||||
hitbox.centeredX.div(TerrarumAppConfiguration.TILE_SIZE).floorInt(),
|
hitbox.centeredX.div(TerrarumAppConfiguration.TILE_SIZE).floorToInt(),
|
||||||
hitbox.endY.div(TerrarumAppConfiguration.TILE_SIZE).floorInt()
|
hitbox.endY.div(TerrarumAppConfiguration.TILE_SIZE).floorToInt()
|
||||||
)].isSolid) {
|
)].isSolid) {
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
|||||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame.Companion.inUpdateRange
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame.Companion.inUpdateRange
|
||||||
import net.torvald.terrarum.modulebasegame.gameactors.*
|
import net.torvald.terrarum.modulebasegame.gameactors.*
|
||||||
import org.dyn4j.geometry.Vector2
|
import org.dyn4j.geometry.Vector2
|
||||||
|
import kotlin.math.min
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -120,10 +121,10 @@ object WorldSimulator {
|
|||||||
|
|
||||||
// kill grasses surrounded by dirts in cruciform formation
|
// kill grasses surrounded by dirts in cruciform formation
|
||||||
// NOPE this part would not work; environment-depending degrassing must be done by the "grass spread simulator"
|
// NOPE this part would not work; environment-depending degrassing must be done by the "grass spread simulator"
|
||||||
/*val for_y_start = (WorldCamera.y.toFloat() / TILE_SIZE).floorInt()
|
/*val for_y_start = (WorldCamera.y.toFloat() / TILE_SIZE).floorToInt()
|
||||||
val for_y_end = for_y_start + BlocksDrawer.tilesInVertical - 1
|
val for_y_end = for_y_start + BlocksDrawer.tilesInVertical - 1
|
||||||
|
|
||||||
val for_x_start = (WorldCamera.x.toFloat() / TILE_SIZE).floorInt()
|
val for_x_start = (WorldCamera.x.toFloat() / TILE_SIZE).floorToInt()
|
||||||
val for_x_end = for_x_start + BlocksDrawer.tilesInHorizontal - 1
|
val for_x_end = for_x_start + BlocksDrawer.tilesInHorizontal - 1
|
||||||
for (y in for_y_start..for_y_end) {
|
for (y in for_y_start..for_y_end) {
|
||||||
for (x in for_x_start..for_x_end) {
|
for (x in for_x_start..for_x_end) {
|
||||||
@@ -354,7 +355,7 @@ object WorldSimulator {
|
|||||||
if (flow > minFlow) {
|
if (flow > minFlow) {
|
||||||
flow *= 0.5f // leads to smoother flow
|
flow *= 0.5f // leads to smoother flow
|
||||||
}
|
}
|
||||||
flow = flow.coerceIn(0f, minOf(maxSpeed, remainingMass))
|
flow = flow.coerceIn(0f, min(maxSpeed, remainingMass))
|
||||||
|
|
||||||
fluidNewMap[y][x] -= flow
|
fluidNewMap[y][x] -= flow
|
||||||
fluidNewMap[y + 1][x] += flow
|
fluidNewMap[y + 1][x] += flow
|
||||||
@@ -404,7 +405,7 @@ object WorldSimulator {
|
|||||||
if (flow > minFlow) {
|
if (flow > minFlow) {
|
||||||
flow *= 0.5f
|
flow *= 0.5f
|
||||||
}
|
}
|
||||||
flow = flow.coerceIn(0f, minOf(maxSpeed, remainingMass))
|
flow = flow.coerceIn(0f, min(maxSpeed, remainingMass))
|
||||||
|
|
||||||
fluidNewMap[y][x] -= flow
|
fluidNewMap[y][x] -= flow
|
||||||
fluidNewMap[y - 1][x] += flow
|
fluidNewMap[y - 1][x] += flow
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user