mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-16 21:44:05 +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
|
||||
|
||||
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 kotlin.coroutines.*
|
||||
import net.torvald.terrarum.*
|
||||
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
||||
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.FixtureBase
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.FixtureInventory
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import net.torvald.terrarum.ui.UICanvas
|
||||
import net.torvald.terrarum.modulecomputers.ui.UIHomeComputer
|
||||
import net.torvald.tsvm.*
|
||||
import net.torvald.tsvm.peripheral.AdapterConfig
|
||||
import net.torvald.tsvm.peripheral.GraphicsAdapter
|
||||
import net.torvald.tsvm.peripheral.VMProgramRom
|
||||
import net.torvald.unicode.*
|
||||
|
||||
/**
|
||||
* 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",
|
||||
"t":dislplayKeyLayouts,
|
||||
"l":"bgBG",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,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
|
||||
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",
|
||||
"tf":states.layouttable,
|
||||
"l":"elGR",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,altgrin,lowlayerkey)=>{
|
||||
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",
|
||||
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
||||
"l":"koKR",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,altgrin)=>{
|
||||
let layer = 1*shiftin// + 2*altgrin
|
||||
states.code = 1
|
||||
|
||||
let s = states.keylayouts[headkey][layer]
|
||||
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
|
||||
|
||||
if (isHangul(s)) {
|
||||
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",
|
||||
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
||||
"l":"koKR",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,altgrin)=>{
|
||||
let layer = 1*shiftin// + 2*altgrin
|
||||
states.code = 1
|
||||
|
||||
let s = states.keylayouts[headkey][layer]
|
||||
let s = states.keylayouts[headkey][layer] || states.keylayouts[headkey][0]
|
||||
|
||||
if (isHangul(s)) {
|
||||
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",
|
||||
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
||||
"l":"koKR",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,altgrin)=>{
|
||||
let layer = 1*shiftin// + 2*altgrin
|
||||
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
|
||||
|
||||
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",
|
||||
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
||||
"l":"koKR",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,altgrin)=>{
|
||||
let layer = 1*shiftin// + 2*altgrin
|
||||
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
|
||||
|
||||
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",
|
||||
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
||||
"l":"koKR",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,altgrin)=>{
|
||||
let layer = 1*shiftin// + 2*altgrin
|
||||
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 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",
|
||||
"t":states.keylayouts.map(it => [it[0],it[1]]),
|
||||
"l":"koKR",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,altgrin)=>{
|
||||
let layer = 1*shiftin// + 2*altgrin
|
||||
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 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",
|
||||
"t":states.keylayouts,
|
||||
"l":"ruRU",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,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
|
||||
if (isDiacritics(s)) {
|
||||
|
||||
@@ -27,7 +27,7 @@ let states = {"keylayouts":[[""],[undefined],
|
||||
[undefined],
|
||||
[undefined],
|
||||
["ф","Ф","ƒ","ƒ"],
|
||||
["и","И"],
|
||||
["и","И","и","И"],
|
||||
["с","С","≠","≠"],
|
||||
["в","В","ћ","Ћ"],
|
||||
["у","У","ќ","Ќ"],
|
||||
@@ -69,10 +69,10 @@ let states = {"keylayouts":[[""],[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",
|
||||
"t":states.keylayouts,
|
||||
"l":"ruRU",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,altgrin)=>{
|
||||
let layer = 1*shiftin + 2*altgrin
|
||||
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)) {
|
||||
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",
|
||||
"tf":states.layouttable,
|
||||
"l":"ruRU",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,altgrin,lowlayerkey)=>{
|
||||
let layer = 1*shiftin// + 2*altgrin
|
||||
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",
|
||||
"t":states.keylayouts,
|
||||
"l":"thTH",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,altgrin)=>{
|
||||
let layer = 1*shiftin + 2*altgrin // use AltGr to type conventional numbers
|
||||
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]
|
||||
},
|
||||
"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",
|
||||
"t":states.keylayouts,
|
||||
"l":"thTH",
|
||||
// return: [displayed output, composed output]
|
||||
// return: [delete count, composed output]
|
||||
"accept":(headkey,shiftin,altgrin)=>{
|
||||
let layer = 1*shiftin + 2*altgrin // use AltGr to type conventional numbers
|
||||
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]
|
||||
},
|
||||
"backspace":()=>{
|
||||
|
||||
@@ -276,7 +276,7 @@ return Object.freeze({"n":"五仓简体 Qwerty","v":"many","c":"CuriousTo\uA75Bv
|
||||
"accept":(headkey,shiftin,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)
|
||||
|
||||
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)=>{
|
||||
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)
|
||||
|
||||
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",
|
||||
"MENU_LABEL_PRESS_START_SYMBOL": "Press >",
|
||||
"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_CHARACTER": "Character",
|
||||
"CONTEXT_TIME_MINUTE_PLURAL": "Minutes",
|
||||
"CONTEXT_TIME_SECOND_PLURAL": "Seconds",
|
||||
"MENU_LABEL_SYSTEM_INFO": "System Info",
|
||||
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "Show notification for",
|
||||
"MENU_LABEL_STREAMING": "Livestreaming",
|
||||
"MENU_LABEL_EXTRA_JVM_ARGUMENTS": "Extra Arguments",
|
||||
"MENU_IO_MANUAL_SAVE": "Manual Save",
|
||||
"COPYRIGHT_ALL_RIGHTS_RESERVED": "All rights reserved",
|
||||
"COPYRIGHT_GNU_GPL_3": "Distributed under GNU GPL 3",
|
||||
"GAME_ACTION_MOVE_VERB" : "Move",
|
||||
"GAME_ACTION_ZOOM" : "Zoom",
|
||||
"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_WARNING2": "아래 링크에서 최신 64비트 Java를 내려받아 설치해주세요.",
|
||||
"GAME_32BIT_WARNING3": "https://www.java.com/ko/download/",
|
||||
"GAME_APPLE_ROSETTA_WARNING1": "Apple Silicon이 탑재된 Mac을 사용 중이지만 x86 빌드의 게임을 실행 중입니다.",
|
||||
"GAME_APPLE_ROSETTA_WARNING2": "최적의 성능과 게임 경험을 위해 Apple Silicon용 빌드의 게임을 이용해 주십시오.",
|
||||
"APP_NOMODULE_1": "현재 불러와진 모듈이 없습니다.",
|
||||
"APP_NOMODULE_2": "다음의 파일에서 불러오기 순서를 설정하고 게임을 재시작하십시오.",
|
||||
"MENU_LABEL_KEYCONFIG_HELP1": "키캡을 클릭해 컨트롤을 배정하십시오",
|
||||
"GAME_PREV_SAVE_WAS_LOADED1": "가장 최근에 저장된 게임이 손상되었습니다.",
|
||||
"GAME_PREV_SAVE_WAS_LOADED2": "이전에 저장된 게임을 불러왔습니다.",
|
||||
"GAME_MORE_RECENT_AUTOSAVE1": "자동 저장된 게임이 수동으로 저장한 게임보다 더 최신입니다.",
|
||||
"GAME_MORE_RECENT_AUTOSAVE2": "불러올 게임을 선택해 주십시오.",
|
||||
"MENU_LABEL_SAVE_WILL_BE_DELETED": "선택된 세이브가 삭제됩니다.",
|
||||
"MENU_LABEL_UNSAVED_PROGRESSES_WILL_BE_LOST": "저장하지 않은 변동사항을 잃게 됩니다."
|
||||
"GAME_32BIT_WARNING1": "It looks like you’re running a 32-Bit version of Java.",
|
||||
"GAME_32BIT_WARNING2": "Please download and install the latest 64-Bit Java at:",
|
||||
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
|
||||
"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": "Please use the native build for improved performance and gameplay experiences.",
|
||||
"APP_NOMODULE_1": "No Module is currently loaded.",
|
||||
"APP_NOMODULE_2": "Please configure your Load Order and restart:",
|
||||
"MENU_LABEL_KEYCONFIG_HELP1": "Click On the Keycap to Assign Actions",
|
||||
"GAME_PREV_SAVE_WAS_LOADED1": "The most recently saved game was corrupted.",
|
||||
"GAME_PREV_SAVE_WAS_LOADED2": "The previously saved game was loaded.",
|
||||
"GAME_MORE_RECENT_AUTOSAVE1": "The Autosave is more recent than the manual save.",
|
||||
"GAME_MORE_RECENT_AUTOSAVE2": "Please select the saved game you wish to play:",
|
||||
"MENU_LABEL_SAVE_WILL_BE_DELETED": "The selected save file will be deleted.",
|
||||
"MENU_LABEL_UNSAVED_PROGRESS_WILL_BE_LOST": "Unsaved progress will be lost."
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
"GAME_ACTION_MOVE_VERB" : "हिलना",
|
||||
"GAME_ACTION_ZOOM" : "ज़ूम",
|
||||
"MENU_LABEL_RESET" : "रीसेट",
|
||||
"MENU_OPTION_STREAMERS_LAYOUT": "Chat Overlay",
|
||||
"MENU_OPTIONS_STREAMERS_LAYOUT": "Chat Overlay",
|
||||
"MENU_LABEL_RESTART_REQUIRED": "पुनः शुरआत जरुरी है",
|
||||
"MENU_LABEL_KEYBOARD_LAYOUT": "कीबोर्ड विन्यास",
|
||||
"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": "경고—건강과 안전을 위하여",
|
||||
"MENU_LABEL_PRESS_START_SYMBOL": ">을 누르세요",
|
||||
"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_CHARACTER": "캐릭터",
|
||||
"CONTEXT_TIME_MINUTE_PLURAL": "분",
|
||||
"CONTEXT_TIME_SECOND_PLURAL": "초",
|
||||
"MENU_LABEL_SYSTEM_INFO": "시스템 정보",
|
||||
"MENU_OPTIONS_NOTIFICATION_DISPLAY_DURATION": "알림 표시 시간",
|
||||
"MENU_LABEL_STREAMING": "실시간 방송",
|
||||
"MENU_LABEL_EXTRA_JVM_ARGUMENTS": "추가 명령 인수",
|
||||
"MENU_IO_MANUAL_SAVE": "수동 저장",
|
||||
"COPYRIGHT_ALL_RIGHTS_RESERVED": "모든 권리 보유",
|
||||
"COPYRIGHT_GNU_GPL_3": "GNU GPL 3에 따라 배포됨",
|
||||
"GAME_ACTION_MOVE_VERB" : "이동하기",
|
||||
"GAME_ACTION_ZOOM" : "확대·축소",
|
||||
"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_MORE_RECENT_AUTOSAVE1": "자동 저장된 게임이 수동으로 저장한 게임보다 더 최신입니다.",
|
||||
"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_WARNING2": "请下载并安装最新的64位Java :",
|
||||
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
|
||||
"MENU_OPTION_STREAMERS_LAYOUT": "聊天叠加",
|
||||
"MENU_OPTIONS_STREAMERS_LAYOUT": "聊天叠加",
|
||||
"MENU_LABEL_RESTART_REQUIRED": "需要重新启动",
|
||||
"MENU_LABEL_KEYBOARD_LAYOUT": "键盘布局",
|
||||
"MENU_LABEL_IME": "输入法",
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
"GAME_32BIT_WARNING1": "看起來您正在運行32位版本的Java。",
|
||||
"GAME_32BIT_WARNING2": "請下載並安裝最新的64位Java :",
|
||||
"GAME_32BIT_WARNING3": "https://www.java.com/en/download/",
|
||||
"MENU_OPTION_STREAMERS_LAYOUT": "聊天疊加",
|
||||
"MENU_OPTIONS_STREAMERS_LAYOUT": "聊天疊加",
|
||||
"MENU_LABEL_RESTART_REQUIRED": "需要重新啟動",
|
||||
"MENU_LABEL_KEYBOARD_LAYOUT": "鍵盤配置",
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
@@ -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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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,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,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,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,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,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"
|
||||
"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"
|
||||
@@ -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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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"
|
||||
"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,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,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,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"
|
||||
"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"
|
||||
@@ -188,6 +188,7 @@
|
||||
## 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.
|
||||
## - 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 ##
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 179 and column 37.
|
@@ -22,6 +22,8 @@ Seed
|
||||
SetAV
|
||||
SetBulletin
|
||||
SetScale
|
||||
SetSol
|
||||
SetTurb
|
||||
SetTime
|
||||
SetTimeDelta
|
||||
SpawnPhysTestBall
|
||||
|
||||
|
@@ -8,6 +8,7 @@ id;classname
|
||||
8;net.torvald.terrarum.modulebasegame.gameitems.ItemLogicSignalEmitter
|
||||
9;net.torvald.terrarum.modulebasegame.gameitems.WireCutterAll
|
||||
10;net.torvald.terrarum.modulebasegame.gameitems.ItemTypewriter
|
||||
11;net.torvald.terrarum.modulebasegame.gameitems.ItemWallCalendar
|
||||
|
||||
256;net.torvald.terrarum.modulebasegame.gameitems.ItemSwingingDoorOak
|
||||
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",
|
||||
"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",
|
||||
"CONTEXT_GENERATOR_SEED": "Seed",
|
||||
"MENU_LABEL_PREV_SAVES": "Previous Saves",
|
||||
"MENU_LABEL_RENAME": "Rename",
|
||||
"GAME_ACTION_CRAFT": "Craft",
|
||||
"GAME_ACTION_GRAPPLE": "Grapple",
|
||||
"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",
|
||||
"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_FULL_COLLISION": "Urist Berdanrifot",
|
||||
"ACTORBLOCK_NO_COLLISION": "Urist Zafal",
|
||||
"ACTORBLOCK_NO_PASS_RIGHT": "Urist McPassLeft",
|
||||
"ACTORBLOCK_NO_PASS_LEFT": "Urist McPassRight",
|
||||
"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"
|
||||
"ACTORBLOCK_TILING_PLACEHOLDER": "Urist Berdanurdim"
|
||||
}
|
||||
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": "새 세계",
|
||||
"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": "메뉴",
|
||||
"CONTEXT_ITEM_MAP": "지도",
|
||||
"CONTEXT_GENERATOR_SEED": "시드",
|
||||
"MENU_LABEL_PREV_SAVES": "이전 세이브",
|
||||
"MENU_LABEL_RENAME": "이름 바꾸기",
|
||||
"MENU_MONITOR_CALI_TITLE": "모니터 확인",
|
||||
"GAME_ACTION_CRAFT": "제작하기",
|
||||
"GAME_ACTION_GRAPPLE": "매달리기",
|
||||
"GAME_ACTION_QUICKSEL": "빠른 선택",
|
||||
"GAME_ACTION_CRAFT": "제작하기",
|
||||
"GAME_CRAFTING": "제작",
|
||||
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템",
|
||||
"MENU_LABEL_RENAME": "이름 바꾸기",
|
||||
"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_STONE_MARBLE": "대리석",
|
||||
|
||||
"ITEM_STORAGE_CHEST": "보관상자",
|
||||
"ITEM_WIRE": "전선",
|
||||
"ITEM_WIRE_CUTTER": "전선 절단기",
|
||||
"ITEM_CALENDAR": "달력",
|
||||
"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",
|
||||
"daylightClut": "clut_daylight.tga",
|
||||
"classification": "generic",
|
||||
"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
|
||||
mkdir $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
|
||||
cp -r "../assets_release" $DESTDIR/
|
||||
|
||||
@@ -25,6 +25,7 @@ chmod +x $DESTDIR/AppRun
|
||||
# Copy over a Java runtime
|
||||
mkdir $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
|
||||
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%/*}"
|
||||
SRCFILES="terrarummac_arm"
|
||||
DESTDIR="out/TerrarumMac.arm.app"
|
||||
APPDIR="./TerrarumMac.arm.app"
|
||||
DESTDIR="out/$APPDIR"
|
||||
RUNTIME="runtime-osx-arm"
|
||||
|
||||
if [ ! -d "../assets_release" ]; then
|
||||
@@ -27,10 +28,15 @@ chmod +x $DESTDIR/Contents/MacOS/Terrarum.sh
|
||||
# Copy over a Java runtime
|
||||
mkdir $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
|
||||
cp -r "../assets_release" $DESTDIR/Contents/MacOS/
|
||||
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
|
||||
cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/
|
||||
|
||||
cd "out"
|
||||
rm $APPDIR.zip
|
||||
7z a -tzip $APPDIR.zip $APPDIR
|
||||
|
||||
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%/*}"
|
||||
SRCFILES="terrarummac_x86"
|
||||
DESTDIR="out/TerrarumMac.x86.app"
|
||||
APPDIR="./TerrarumMac.x86.app"
|
||||
DESTDIR="out/$APPDIR"
|
||||
RUNTIME="runtime-osx-x86"
|
||||
|
||||
if [ ! -d "../assets_release" ]; then
|
||||
@@ -27,10 +28,15 @@ chmod +x $DESTDIR/Contents/MacOS/Terrarum.sh
|
||||
# Copy over a Java runtime
|
||||
mkdir $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
|
||||
cp -r "../assets_release" $DESTDIR/Contents/MacOS/
|
||||
mv $DESTDIR/Contents/MacOS/assets_release $DESTDIR/Contents/MacOS/assets
|
||||
cp "../out/TerrarumBuild.jar" $DESTDIR/Contents/MacOS/out/
|
||||
|
||||
cd "out"
|
||||
rm $APPDIR.zip
|
||||
7z a -tzip $APPDIR.zip $APPDIR
|
||||
|
||||
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;
|
||||
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
|
||||
mkdir $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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
* 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
|
||||
* into half precision (16 bit).
|
||||
@@ -876,31 +867,6 @@ final public class FastMath {
|
||||
| ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00)
|
||||
| ((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) {
|
||||
while (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 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])
|
||||
}
|
||||
@@ -123,7 +123,7 @@ fun RGB.linearise(): RGB {
|
||||
}
|
||||
val step = value.clampOne() * 255f // 0.0 .. 255.0
|
||||
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])
|
||||
}
|
||||
@@ -192,6 +192,16 @@ fun CIEXYZ.toColorRaw(): Color {
|
||||
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 {
|
||||
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.badlogic.gdx.graphics.Color
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* OBSOLETE; use CIELchUtil for natural-looking colour
|
||||
@@ -75,8 +77,8 @@ object HSVUtil {
|
||||
val g = color.g
|
||||
val b = color.b
|
||||
|
||||
val rgbMin = FastMath.min(r, g, b)
|
||||
val rgbMax = FastMath.max(r, g, b)
|
||||
val rgbMin = min(min(r, g), b)
|
||||
val rgbMax = max(max(r, g), b)
|
||||
|
||||
var h: Float
|
||||
val s: Float
|
||||
|
||||
@@ -110,7 +110,7 @@ public class HUSLColorConverter {
|
||||
float x = intersectLineLine(line, new float[]{-1 / m1, 0});
|
||||
float length = distanceFromPole(new float[]{x, b1 + x * m1});
|
||||
|
||||
min = FastMath.min(min, length);
|
||||
min = Math.min(min, length);
|
||||
}
|
||||
|
||||
return min;
|
||||
@@ -125,7 +125,7 @@ public class HUSLColorConverter {
|
||||
for (float[] bound : bounds) {
|
||||
Length length = lengthOfRayUntilIntersect(hrad, bound);
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
*
|
||||
* @param r the red component
|
||||
|
||||
@@ -104,10 +104,10 @@ internal class UnsafeCvecArray(val width: Int, val height: Int) {
|
||||
// operators
|
||||
fun max(x: Int, y: Int, other: Cvec) {
|
||||
val a = toAddr(x, y)
|
||||
array.setFloat(a + 0, maxOf(array.getFloat(a + 0), other.r))
|
||||
array.setFloat(a + 1, maxOf(array.getFloat(a + 1), other.g))
|
||||
array.setFloat(a + 2, maxOf(array.getFloat(a + 2), other.b))
|
||||
array.setFloat(a + 3, maxOf(array.getFloat(a + 3), other.a))
|
||||
array.setFloat(a + 0, kotlin.math.max(array.getFloat(a + 0), other.r))
|
||||
array.setFloat(a + 1, kotlin.math.max(array.getFloat(a + 1), other.g))
|
||||
array.setFloat(a + 2, kotlin.math.max(array.getFloat(a + 2), other.b))
|
||||
array.setFloat(a + 3, kotlin.math.max(array.getFloat(a + 3), other.a))
|
||||
}
|
||||
fun mul(x: Int, y: Int, scalar: Float) {
|
||||
val a = toAddr(x, y)
|
||||
@@ -202,10 +202,10 @@ internal class TestCvecArr(val width: Int, val height: Int) {
|
||||
|
||||
// operators
|
||||
inline fun max(x: Int, y: Int, other: Cvec) {
|
||||
setR(x, y, maxOf(getR(x, y), other.r))
|
||||
setG(x, y, maxOf(getG(x, y), other.g))
|
||||
setB(x, y, maxOf(getB(x, y), other.b))
|
||||
setA(x, y, maxOf(getA(x, y), other.a))
|
||||
setR(x, y, kotlin.math.max(getR(x, y), other.r))
|
||||
setG(x, y, kotlin.math.max(getG(x, y), other.g))
|
||||
setB(x, y, kotlin.math.max(getB(x, y), other.b))
|
||||
setA(x, y, kotlin.math.max(getA(x, y), other.a))
|
||||
}
|
||||
inline fun mul(x: Int, y: Int, scalar: Float) {
|
||||
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.colourutil.*
|
||||
import net.torvald.parametricsky.datasets.DatasetCIEXYZ
|
||||
import net.torvald.parametricsky.datasets.DatasetRGB
|
||||
import net.torvald.parametricsky.datasets.DatasetSpectral
|
||||
import net.torvald.terrarum.abs
|
||||
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.modulebasegame.worldgenerator.HALF_PI
|
||||
import net.torvald.terrarum.modulebasegame.worldgenerator.TWO_PI
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Dimension
|
||||
import java.lang.Math.pow
|
||||
import javax.swing.*
|
||||
import kotlin.math.PI
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.*
|
||||
|
||||
|
||||
const val WIDTH = 1200
|
||||
const val HEIGHT = 600
|
||||
val INITIAL_TURBIDITY = 4.0
|
||||
val INITIAL_ALBEDO = 0.1
|
||||
val INITIAL_ELEV = 0.0
|
||||
|
||||
|
||||
/**
|
||||
* 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:
|
||||
* 1. Canvas Y (theta)
|
||||
@@ -53,12 +65,12 @@ class Application : Game() {
|
||||
private lateinit var oneScreen: Pixmap
|
||||
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 albedo = 0.1
|
||||
var elevation = 0.0
|
||||
var scalefactor = 1f
|
||||
var solarBearing = Math.toRadians(90.0)
|
||||
var cameraHeading = Math.toRadians(90.0)
|
||||
|
||||
override fun getScreen(): Screen {
|
||||
return super.getScreen()
|
||||
@@ -68,20 +80,38 @@ class Application : Game() {
|
||||
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() {
|
||||
Gdx.graphics.setTitle("Daylight Model $EMDASH F: ${Gdx.graphics.framesPerSecond}")
|
||||
|
||||
if (turbidity <= 0) throw IllegalStateException()
|
||||
|
||||
// we need to use different modelstate to accomodate different albedo for each spectral band but oh well...
|
||||
genTexLoop(ArHosekSkyModel.arhosek_xyz_skymodelstate_alloc_init(turbidity, albedo, elevation))
|
||||
// we need to use different model-state to accommodate different albedo for each spectral band but oh well...
|
||||
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)
|
||||
tex.setFilter(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest)
|
||||
tex.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
|
||||
|
||||
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()
|
||||
@@ -103,14 +133,48 @@ class Application : Game() {
|
||||
oneScreen.dispose()
|
||||
}
|
||||
|
||||
val outTexWidth = 256
|
||||
val outTexHeight = 256
|
||||
val outTexWidth = 1
|
||||
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;
|
||||
* 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 {
|
||||
var v = y.coerceAtLeast(0.0)
|
||||
@@ -120,20 +184,49 @@ class Application : Game() {
|
||||
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) {
|
||||
val gamma = (x / oneScreen.width.toDouble()) * TWO_PI // 0deg..360deg
|
||||
val theta = (1.0 - (y / oneScreen.height.toDouble())) * HALF_PI // 90deg..0deg
|
||||
for (y in 0 until oneScreen.height) {
|
||||
|
||||
// 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(
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 0).toFloat().times(scalefactor / 10f),
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 1).toFloat().times(scalefactor / 10f),
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, gamma, 2).toFloat().times(scalefactor / 10f)
|
||||
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 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
|
||||
|
||||
/*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.drawPixel(x, y)
|
||||
|
||||
@@ -142,140 +235,148 @@ class Application : Game() {
|
||||
|
||||
}
|
||||
|
||||
ymaxDisp.text = "${ys.max()}"
|
||||
ymaxDisp2.text = "${ys2.max()}"
|
||||
|
||||
//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() {
|
||||
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
|
||||
DatasetRGB
|
||||
// DatasetRGB
|
||||
|
||||
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 turbidityControl = JSpinner(SpinnerNumberModel(5.0, 1.0, 10.0, 0.1))
|
||||
val albedoControl = JSpinner(SpinnerNumberModel(0.1, 0.0, 1.0, 0.05))
|
||||
val elevationControl = JSpinner(SpinnerNumberModel(0.0, 0.0, 90.0, 0.5))
|
||||
val scalefactorControl = JSpinner(SpinnerNumberModel(1.0, 0.0, 2.0, 0.01))
|
||||
|
||||
init {
|
||||
val turbidityPanel = JPanel()
|
||||
val albedoPanel = JPanel()
|
||||
val elevationPanel = JPanel()
|
||||
val scalefactorPanel = JPanel()
|
||||
|
||||
turbidityControl.preferredSize = Dimension(45, 18)
|
||||
albedoControl.preferredSize = Dimension(45, 18)
|
||||
elevationControl.preferredSize = Dimension(45, 18)
|
||||
scalefactorControl.preferredSize = Dimension(45, 18)
|
||||
|
||||
turbidityPanel.add(JLabel("Turbidity"))
|
||||
turbidityPanel.add(turbidityControl)
|
||||
|
||||
albedoPanel.add(JLabel("Albedo"))
|
||||
albedoPanel.add(albedoControl)
|
||||
|
||||
elevationPanel.add(JLabel("Elevation"))
|
||||
elevationPanel.add(elevationControl)
|
||||
|
||||
scalefactorPanel.add(JLabel("Scaling Factor"))
|
||||
scalefactorPanel.add(scalefactorControl)
|
||||
|
||||
mainPanel.add(turbidityPanel)
|
||||
mainPanel.add(albedoPanel)
|
||||
mainPanel.add(elevationPanel)
|
||||
mainPanel.add(scalefactorPanel)
|
||||
mainPanel.layout = BoxLayout(mainPanel, BoxLayout.Y_AXIS)
|
||||
JPanel().also {
|
||||
it.layout = BorderLayout()
|
||||
it.add(JPanel().also { it.add(JLabel("Atmosphere")) }, BorderLayout.NORTH)
|
||||
it.add(atmosPanel, BorderLayout.CENTER)
|
||||
it.add(JSeparator(), BorderLayout.SOUTH)
|
||||
mainPanel.add(it)
|
||||
}
|
||||
JPanel().also {
|
||||
it.layout = BorderLayout()
|
||||
it.add(JPanel().also { it.add(JLabel("Sun")) }, BorderLayout.NORTH)
|
||||
it.add(sunPanel, BorderLayout.CENTER)
|
||||
it.add(JSeparator(), BorderLayout.SOUTH)
|
||||
mainPanel.add(it)
|
||||
}
|
||||
JPanel().also {
|
||||
it.layout = BorderLayout()
|
||||
it.add(JPanel().also { it.add(JLabel("Camera")) }, BorderLayout.NORTH)
|
||||
it.add(cameraPanel, BorderLayout.CENTER)
|
||||
it.add(JSeparator(), BorderLayout.SOUTH)
|
||||
mainPanel.add(it)
|
||||
}
|
||||
JPanel().also {
|
||||
it.layout = BorderLayout()
|
||||
it.add(JPanel().also { it.add(JLabel("Statistics")) }, BorderLayout.NORTH)
|
||||
it.add(statsPanel, BorderLayout.CENTER)
|
||||
mainPanel.add(it)
|
||||
}
|
||||
|
||||
this.isVisible = true
|
||||
this.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
|
||||
this.size = Dimension(300, 400)
|
||||
|
||||
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()
|
||||
}
|
||||
this.size = Dimension(300, 600)
|
||||
this.add(mainPanel, BorderLayout.CENTER)
|
||||
|
||||
}
|
||||
|
||||
@@ -285,7 +386,10 @@ class Application : Game() {
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
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 fis = FileInputStream(file)
|
||||
|
||||
val ret = DoubleArray(entrysize) {
|
||||
val inputbuf = ByteArray(8)
|
||||
val ret = DoubleArray(entrysize) {
|
||||
fis.read(inputbuf)
|
||||
val rawnum = inputbuf.toLittleInt64()
|
||||
Double.fromBits(rawnum)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package net.torvald.random
|
||||
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.floorInt
|
||||
import net.torvald.terrarum.floorToInt
|
||||
import net.torvald.terrarum.gameworld.fmod
|
||||
import java.util.*
|
||||
|
||||
@@ -45,9 +45,9 @@ class TileableValueNoise(
|
||||
try {
|
||||
for (x in 0..width) {
|
||||
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 =
|
||||
(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 windowScale: Float = stepWithinWindow.toFloat() / (width / samples)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import net.torvald.terrarum.ItemCodex
|
||||
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.gameitems.GameItem
|
||||
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.AssembleFrameBase
|
||||
import net.torvald.terrarum.spriteassembler.AssembleSheetPixmap
|
||||
import net.torvald.terrarum.tryDispose
|
||||
import java.io.InputStream
|
||||
import java.util.*
|
||||
|
||||
@@ -122,8 +123,8 @@ class AssembledSpriteAnimation(
|
||||
val drawPos = adp.origin + bodypartPos // imgCentre for held items are (0,0)
|
||||
val w = image.regionWidth * scale
|
||||
val h = image.regionHeight * scale
|
||||
val fposX = posX.floor() + drawPos.x * scale
|
||||
val fposY = posY.floor() + drawPos.y * scale - h
|
||||
val fposX = posX.floorToFloat() + drawPos.x * scale
|
||||
val fposY = posY.floorToFloat() + drawPos.y * scale - h
|
||||
|
||||
// draw
|
||||
if (flipHorizontal && flipVertical)
|
||||
@@ -146,8 +147,8 @@ class AssembledSpriteAnimation(
|
||||
val drawPos = adp.origin + bodypartPos - imgCentre
|
||||
val w = image.regionWidth * scale
|
||||
val h = image.regionHeight * scale
|
||||
val fposX = posX.floor() + drawPos.x * scale
|
||||
val fposY = posY.floor() + drawPos.y * scale
|
||||
val fposX = posX.floorToFloat() + drawPos.x * scale
|
||||
val fposY = posY.floorToFloat() + drawPos.y * scale
|
||||
|
||||
if (flipHorizontal && flipVertical)
|
||||
batch.draw(image, fposX + txFlp, fposY + tyFlp, -w, -h)
|
||||
@@ -172,7 +173,7 @@ class AssembledSpriteAnimation(
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
res.values.forEach { try { it?.texture?.dispose() } catch (_: GdxRuntimeException) {} }
|
||||
res.values.forEach { it?.texture?.tryDispose() }
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -31,7 +31,6 @@ import net.torvald.terrarum.langpack.Lang;
|
||||
import net.torvald.terrarum.modulebasegame.IngameRenderer;
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame;
|
||||
import net.torvald.terrarum.modulebasegame.ui.ItemSlotImageFactory;
|
||||
import net.torvald.terrarum.savegame.DiskSkimmer;
|
||||
import net.torvald.terrarum.serialise.WriteConfig;
|
||||
import net.torvald.terrarum.ui.Toolkit;
|
||||
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 long VERSION_RAW = TerrarumAppConfiguration.VERSION_RAW;
|
||||
public static final String VERSION_TAG = TerrarumAppConfiguration.VERSION_TAG;
|
||||
|
||||
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 shaderReflect;
|
||||
public static ShaderProgram shaderGhastlyWhite;
|
||||
public static Hq2x hq2x;
|
||||
|
||||
public static Mesh fullscreenQuad;
|
||||
private static OrthographicCamera camera;
|
||||
@@ -267,12 +269,13 @@ public class App implements ApplicationListener {
|
||||
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 final float showupTime = 100f / 1000f;
|
||||
|
||||
private static FloatFrameBuffer renderFBO;
|
||||
private static Float16FrameBuffer renderFBO;
|
||||
|
||||
public static HashSet<File> tempFilePool = new HashSet<>();
|
||||
|
||||
@@ -392,6 +395,7 @@ public class App implements ApplicationListener {
|
||||
appConfig.useVsync(getConfigBoolean("usevsync"));
|
||||
appConfig.setResizable(false);
|
||||
appConfig.setWindowedMode(width, height);
|
||||
appConfig.setTransparentFramebuffer(false);
|
||||
int fpsActive = Math.min(GLOBAL_FRAMERATE_LIMIT, getConfigInt("displayfps"));
|
||||
if (fpsActive <= 0) fpsActive = GLOBAL_FRAMERATE_LIMIT;
|
||||
int fpsBack = Math.min(GLOBAL_FRAMERATE_LIMIT, getConfigInt("displayfpsidle"));
|
||||
@@ -439,13 +443,10 @@ public class App implements ApplicationListener {
|
||||
|
||||
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_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
|
||||
|
||||
@@ -474,12 +475,9 @@ public class App implements ApplicationListener {
|
||||
shaderBayerSkyboxFill = loadShaderFromClasspath("shaders/default.vert",
|
||||
"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");
|
||||
shaderColLUT = loadShaderFromClasspath("shaders/default.vert", "shaders/passthrurgb.frag");
|
||||
shaderReflect = loadShaderFromClasspath("shaders/default.vert", "shaders/reflect.frag");
|
||||
shaderGhastlyWhite = loadShaderFromClasspath("shaders/default.vert", "shaders/ghastlywhite.frag");
|
||||
hq2x = new Hq2x(2);
|
||||
|
||||
fullscreenQuad = new Mesh(
|
||||
true, 4, 6,
|
||||
@@ -487,97 +485,21 @@ public class App implements ApplicationListener {
|
||||
VertexAttribute.ColorUnpacked(),
|
||||
VertexAttribute.TexCoords(0)
|
||||
);
|
||||
updateFullscreenQuad(scr.getWidth(), scr.getHeight());
|
||||
|
||||
updateFullscreenQuad(fullscreenQuad, scr.getWidth(), scr.getHeight());
|
||||
|
||||
// set up renderer info variables
|
||||
renderer = Gdx.graphics.getGLVersion().getRendererString();
|
||||
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,
|
||||
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 postProcessorOutFBO2;
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
@@ -636,30 +558,44 @@ public class App implements ApplicationListener {
|
||||
FrameBufferManager.end();
|
||||
|
||||
|
||||
|
||||
// process screenshot request
|
||||
if (screenshotRequested) {
|
||||
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;
|
||||
}
|
||||
processScreenshotRequest(postProcessorOutFBO);
|
||||
|
||||
|
||||
|
||||
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.setUniformMatrix("u_projTrans", camera.combined);
|
||||
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);
|
||||
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
|
||||
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() {
|
||||
int hash = 31 + GLOBAL_RENDER_TIMER + 0x165667B1 + GLOBAL_RENDER_TIMER * 0xC2B2AE3D;
|
||||
hash = Integer.rotateLeft(hash, 17) * 0x27D4EB2F;
|
||||
@@ -792,18 +748,23 @@ public class App implements ApplicationListener {
|
||||
|
||||
if (currentScreen != null) currentScreen.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 ||
|
||||
(renderFBO.getWidth() != scr.getWidth() ||
|
||||
renderFBO.getHeight() != scr.getHeight())
|
||||
) {
|
||||
renderFBO = new FloatFrameBuffer(
|
||||
renderFBO = new Float16FrameBuffer(
|
||||
scr.getWidth(),
|
||||
scr.getHeight(),
|
||||
false
|
||||
);
|
||||
postProcessorOutFBO2 = new Float16FrameBuffer(
|
||||
scr.getWidth() * 2,
|
||||
scr.getHeight() * 2,
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
if (IS_DEVELOPMENT_BUILD) {
|
||||
@@ -856,6 +817,7 @@ public class App implements ApplicationListener {
|
||||
shaderColLUT.dispose();
|
||||
shaderReflect.dispose();
|
||||
shaderGhastlyWhite.dispose();
|
||||
hq2x.dispose();
|
||||
|
||||
CommonResourcePool.INSTANCE.dispose();
|
||||
fullscreenQuad.dispose();
|
||||
@@ -954,6 +916,93 @@ public class App implements ApplicationListener {
|
||||
* Init stuffs which needs GL context
|
||||
*/
|
||||
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
|
||||
|
||||
|
||||
@@ -1032,14 +1081,14 @@ public class App implements ApplicationListener {
|
||||
logoBatch.setProjectionMatrix(camera.combined);
|
||||
}
|
||||
|
||||
private void updateFullscreenQuad(int WIDTH, int HEIGHT) { // NOT y-flipped quads!
|
||||
fullscreenQuad.setVertices(new float[]{
|
||||
private void updateFullscreenQuad(Mesh mesh, int WIDTH, int HEIGHT) { // NOT y-flipped quads!
|
||||
mesh.setVertices(new float[]{
|
||||
0f, 0f, 0f, 1f, 1f, 1f, 1f, 0f, 1f,
|
||||
WIDTH, 0f, 0f, 1f, 1f, 1f, 1f, 1f, 1f,
|
||||
WIDTH, HEIGHT, 0f, 1f, 1f, 1f, 1f, 1f, 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() {
|
||||
|
||||
@@ -33,9 +33,9 @@ object CommonResourcePool {
|
||||
addToLoadingList("itemplaceholder_48") {
|
||||
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) }
|
||||
}
|
||||
}*/
|
||||
loadAll()
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ object DefaultConfig {
|
||||
"language" to App.getSysLang(),
|
||||
"notificationshowuptime" to 4000, // 4s
|
||||
"selecteditemnameshowuptime" to 4000, // 4s
|
||||
"autosaveinterval" to 300000, // 5s
|
||||
"autosaveinterval" to 300000, // 5m
|
||||
"multithread" to true,
|
||||
|
||||
"showhealthmessageonstartup" to true,
|
||||
@@ -112,6 +112,7 @@ object DefaultConfig {
|
||||
"inputmethod" to "none",
|
||||
|
||||
"screenmagnifying" to 1.0,
|
||||
"screenmagnifyingfilter" to "none", // "none", "bilinear", "hq2x"
|
||||
|
||||
"fx_newlight" to false,
|
||||
|
||||
@@ -119,6 +120,12 @@ object DefaultConfig {
|
||||
"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
|
||||
/*"buildingmakerfavs" to arrayOf(
|
||||
|
||||
@@ -64,8 +64,8 @@ object GlslTilingTest : ApplicationAdapter() {
|
||||
|
||||
|
||||
|
||||
val tilesInHorizontal = (Gdx.graphics.width.toFloat() / TILING_SIZE).ceil() + 1f
|
||||
val tilesInVertical = (Gdx.graphics.height.toFloat() / TILING_SIZE).ceil() + 1f
|
||||
val tilesInHorizontal = (Gdx.graphics.width.toFloat() / TILING_SIZE).ceilToFloat() + 1f
|
||||
val tilesInVertical = (Gdx.graphics.height.toFloat() / TILING_SIZE).ceilToFloat() + 1f
|
||||
|
||||
tilesQuad = Mesh(
|
||||
true, 4, 6,
|
||||
@@ -129,8 +129,8 @@ object GlslTilingTest : ApplicationAdapter() {
|
||||
Gdx.gl.glEnable(GL20.GL_BLEND)
|
||||
Gdx.gl.glBlendFunc(GL20.GL_SRC_ALPHA, GL20.GL_ONE_MINUS_SRC_ALPHA)
|
||||
|
||||
val tilesInHorizontal = (Gdx.graphics.width.toFloat() / TILING_SIZE).ceil() + 1f
|
||||
val tilesInVertical = (Gdx.graphics.height.toFloat() / TILING_SIZE).ceil() + 1f
|
||||
val tilesInHorizontal = (Gdx.graphics.width.toFloat() / TILING_SIZE).ceilToFloat() + 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.concurrent.locks.Lock
|
||||
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;
|
||||
@@ -64,7 +65,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
||||
lateinit var playerDisk: VirtualDisk; internal set
|
||||
lateinit var worldSavefileName: 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
|
||||
val ZOOM_MAXIMUM = 4.0f
|
||||
@@ -204,13 +205,7 @@ open class IngameInstance(val batch: FlippingSpriteBatch, val isMultiplayer: Boo
|
||||
actorContainerInactive.forEach { it.dispose() }
|
||||
world.dispose()
|
||||
|
||||
disposables.forEach(Consumer {
|
||||
try { it.dispose() }
|
||||
catch (_: NullPointerException) { }
|
||||
catch (_: IllegalArgumentException) { }
|
||||
catch (_: GdxRuntimeException) { }
|
||||
catch (_: ConcurrentModificationException) { }
|
||||
})
|
||||
disposables.forEach(Consumer { it.tryDispose() })
|
||||
}
|
||||
|
||||
////////////
|
||||
@@ -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 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.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Bootstrapper that launches the bundled JVM and injects VM configs such as -Xmx
|
||||
@@ -25,7 +24,6 @@ public class Principii {
|
||||
/** defaultDir + "/config.json" */
|
||||
private static String configDir;
|
||||
|
||||
|
||||
public static void getDefaultDirRoot() {
|
||||
String OS = OSName.toUpperCase();
|
||||
if (OS.contains("WIN")) {
|
||||
@@ -63,7 +61,7 @@ public class Principii {
|
||||
devMode = true;
|
||||
}
|
||||
|
||||
String extracmd = devMode ? " -ea" : "";
|
||||
String extracmd0 = devMode ? " -ea" : "";
|
||||
String OS = OSName.toUpperCase();
|
||||
String CPUARCH = System.getProperty("os.arch").toUpperCase();
|
||||
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
|
||||
runtimeRoot = "runtime-osx-" + runtimeArch;
|
||||
extracmd += " -XstartOnFirstThread";
|
||||
extracmd0 += " -XstartOnFirstThread";
|
||||
}
|
||||
else {
|
||||
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);
|
||||
|
||||
|
||||
@@ -102,13 +100,27 @@ public class Principii {
|
||||
|
||||
|
||||
int xmx = getConfigInt("jvm_xmx");
|
||||
String userDefinedExtraCmd = getConfigString("jvm_extra_cmd").trim();
|
||||
if (!userDefinedExtraCmd.isEmpty()) userDefinedExtraCmd = " "+userDefinedExtraCmd;
|
||||
String userDefinedExtraCmd0 = getConfigString("jvm_extra_cmd").trim();
|
||||
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 {
|
||||
String[] cmd = (runtime+extracmd+userDefinedExtraCmd+" -Xms1G -Xmx"+xmx+"G -cp ./out/TerrarumBuild.jar net.torvald.terrarum.App").split(" ");
|
||||
ProcessBuilder pb = new ProcessBuilder(cmd);
|
||||
pb.inheritIO();
|
||||
System.exit(pb.start().waitFor());
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package net.torvald.terrarum.modulebasegame
|
||||
package net.torvald.terrarum
|
||||
|
||||
import net.torvald.random.HQRNG
|
||||
import java.util.*
|
||||
@@ -9,6 +9,7 @@ import com.jme3.math.FastMath
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
import kotlin.math.max
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2017-07-13.
|
||||
@@ -46,7 +47,7 @@ object SanicLoadScreen : LoadScreenBase() {
|
||||
|
||||
textFbo = FrameBuffer(
|
||||
Pixmap.Format.RGBA4444,
|
||||
maxOf(
|
||||
max(
|
||||
App.fontGame.getWidth(Lang["MENU_IO_LOADING"]),
|
||||
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
|
||||
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
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.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.IOException
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.StandardCopyOption
|
||||
import java.util.*
|
||||
import java.util.zip.GZIPInputStream
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-06-24.
|
||||
@@ -14,7 +29,7 @@ import kotlin.io.path.Path
|
||||
class SavegameCollection(files0: List<DiskSkimmer>) {
|
||||
|
||||
/** 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.diskFile.extension.matches(Regex("^[abc]${'$'}")).toLong(1) or
|
||||
it.diskFile.extension.isBlank().toLong(0)
|
||||
@@ -57,22 +72,161 @@ class SavegameCollection(files0: List<DiskSkimmer>) {
|
||||
fun getBaseFile(): DiskSkimmer {
|
||||
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!!
|
||||
}
|
||||
|
||||
class SavegameCollectionPair(player: SavegameCollection?, world: SavegameCollection?) {
|
||||
fun renamePlayer(name: String) {
|
||||
files.forEach { skimmer ->
|
||||
skimmer.rebuild()
|
||||
skimmer.getFile(SAVEGAMEINFO)!!.let { file ->
|
||||
val json = JsonFetcher.readFromJsonString(ByteArray64Reader(file.bytes, Common.CHARSET))
|
||||
|
||||
private var manualPlayer: DiskSkimmer? = null
|
||||
private var manualWorld: DiskSkimmer? = null
|
||||
private var autoPlayer: DiskSkimmer? = null
|
||||
private var autoWorld: DiskSkimmer? = null
|
||||
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)
|
||||
}
|
||||
|
||||
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()}")
|
||||
}
|
||||
|
||||
class SavegameCollectionPair(private val player: SavegameCollection?, private val world: SavegameCollection?) {
|
||||
|
||||
// private var manualPlayer: 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
|
||||
private set
|
||||
|
||||
var newerSaveIsDamaged = false // only when most recent save is corrupted
|
||||
private set
|
||||
val newerSaveIsDamaged: Boolean // only when most recent save is corrupted
|
||||
|
||||
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)")
|
||||
|
||||
if (player != null && world != null) {
|
||||
@@ -119,11 +273,14 @@ class SavegameCollectionPair(player: SavegameCollection?, world: SavegameCollect
|
||||
pc += 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -147,7 +304,7 @@ class SavegameCollectionPair(player: SavegameCollection?, world: SavegameCollect
|
||||
printdbg(this, "autoWorld = ${autoWorld?.diskFile?.path}")
|
||||
printdbg(this, "status = $status")
|
||||
}
|
||||
}
|
||||
} */
|
||||
|
||||
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 saveAvaliable() = (status > 0)
|
||||
|
||||
fun getManualSave(): DiskPair? {
|
||||
/*fun getManualSave(): DiskPair? {
|
||||
if (status == 0) return null
|
||||
return DiskPair(manualPlayer!!, manualWorld!!)
|
||||
}
|
||||
@@ -178,7 +335,14 @@ class SavegameCollectionPair(player: SavegameCollection?, world: SavegameCollect
|
||||
DiskPair(manualPlayer!!, manualWorld!!)
|
||||
else
|
||||
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.ShapeRenderer
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.badlogic.gdx.utils.JsonReader
|
||||
import com.badlogic.gdx.utils.GdxRuntimeException
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.gdx.graphics.Cvec
|
||||
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.ItemCodex
|
||||
import net.torvald.terrarum.itemproperties.MaterialCodex
|
||||
import net.torvald.terrarum.savegame.ByteArray64Reader
|
||||
import net.torvald.terrarum.savegame.DiskSkimmer
|
||||
import net.torvald.terrarum.savegame.VDFileID.SAVEGAMEINFO
|
||||
import net.torvald.terrarum.serialise.Common
|
||||
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.terrarumsansbitmap.gdx.TerrarumSansBitmap
|
||||
import net.torvald.unsafe.UnsafeHelper
|
||||
@@ -40,10 +36,7 @@ import net.torvald.util.CircularArray
|
||||
import java.io.File
|
||||
import java.io.PrintStream
|
||||
import java.util.*
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.round
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
import kotlin.math.*
|
||||
|
||||
|
||||
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())
|
||||
/** Position of the cursor in the world, rounded */
|
||||
@JvmStatic val mouseTileX: Int
|
||||
get() = (mouseX / TILE_SIZE).floorInt()
|
||||
get() = (mouseX / TILE_SIZE).floorToInt()
|
||||
/** Position of the cursor in the world */
|
||||
@JvmStatic val mouseTileY: Int
|
||||
get() = (mouseY / TILE_SIZE).floorInt()
|
||||
get() = (mouseY / TILE_SIZE).floorToInt()
|
||||
/** Position of the cursor in the world, rounded */
|
||||
@JvmStatic val oldMouseTileX: Int
|
||||
get() = (oldMouseX / TILE_SIZE).floorInt()
|
||||
get() = (oldMouseX / TILE_SIZE).floorToInt()
|
||||
/** Position of the cursor in the world */
|
||||
@JvmStatic val oldMouseTileY: Int
|
||||
get() = (oldMouseY / TILE_SIZE).floorInt()
|
||||
get() = (oldMouseY / TILE_SIZE).floorToInt()
|
||||
inline val mouseScreenX: Int
|
||||
get() = Gdx.input.x.div(scr.magn).roundToInt()
|
||||
inline val mouseScreenY: Int
|
||||
@@ -321,8 +314,8 @@ object Terrarum : Disposable {
|
||||
|
||||
val mx = mouseX
|
||||
val my = mouseY
|
||||
val mtx = (mouseX / TILE_SIZE).floorInt()
|
||||
val mty = (mouseY / TILE_SIZE).floorInt()
|
||||
val mtx = (mouseX / TILE_SIZE).floorToInt()
|
||||
val mty = (mouseY / TILE_SIZE).floorToInt()
|
||||
val msx = mx fmod TILE_SIZED
|
||||
val msy = my fmod TILE_SIZED
|
||||
val vector = if (msx < SMALLGAP) { // X to the left
|
||||
@@ -399,8 +392,10 @@ inline fun FrameBuffer.inAction(camera: OrthographicCamera?, batch: SpriteBatch?
|
||||
//this.begin()
|
||||
FrameBufferManager.begin(this)
|
||||
|
||||
val oldCamPos = camera?.position?.cpy()
|
||||
|
||||
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()
|
||||
batch?.projectionMatrix = camera?.combined
|
||||
|
||||
@@ -410,6 +405,7 @@ inline fun FrameBuffer.inAction(camera: OrthographicCamera?, batch: SpriteBatch?
|
||||
FrameBufferManager.end()
|
||||
|
||||
camera?.setToOrtho(true, App.scr.wf, App.scr.hf)
|
||||
camera?.position?.set(oldCamPos)
|
||||
camera?.update()
|
||||
batch?.projectionMatrix = camera?.combined
|
||||
}
|
||||
@@ -421,8 +417,10 @@ inline fun FrameBuffer.inActionF(camera: OrthographicCamera?, batch: SpriteBatch
|
||||
//this.begin()
|
||||
FrameBufferManager.begin(this)
|
||||
|
||||
val oldCamPos = camera?.position?.cpy()
|
||||
|
||||
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()
|
||||
batch?.projectionMatrix = camera?.combined
|
||||
|
||||
@@ -432,6 +430,7 @@ inline fun FrameBuffer.inActionF(camera: OrthographicCamera?, batch: SpriteBatch
|
||||
FrameBufferManager.end()
|
||||
|
||||
camera?.setToOrtho(true, App.scr.wf, App.scr.hf)
|
||||
camera?.position?.set(oldCamPos)
|
||||
camera?.update()
|
||||
batch?.projectionMatrix = camera?.combined
|
||||
}
|
||||
@@ -611,28 +610,28 @@ val emphVerb = TerrarumSansBitmap.toColorCode(0xFFF6)
|
||||
|
||||
typealias Second = Float
|
||||
|
||||
fun Int.sqr(): Int = this * this
|
||||
fun Double.floorInt() = Math.floor(this).toInt()
|
||||
fun Float.floorInt() = FastMath.floor(this)
|
||||
fun Float.floor() = FastMath.floor(this).toFloat()
|
||||
fun Double.ceilInt() = Math.ceil(this).toInt()
|
||||
fun Float.ceil(): Float = FastMath.ceil(this).toFloat()
|
||||
fun Float.ceilInt() = FastMath.ceil(this)
|
||||
fun Float.round(): Float = round(this)
|
||||
fun Double.round() = Math.round(this).toDouble()
|
||||
fun Double.floor() = Math.floor(this)
|
||||
fun Double.ceil() = this.floor() + 1.0
|
||||
fun Double.abs() = Math.abs(this)
|
||||
fun Double.sqr() = this * this
|
||||
fun Float.sqr() = this * this
|
||||
fun Double.sqrt() = Math.sqrt(this)
|
||||
fun Float.sqrt() = FastMath.sqrt(this)
|
||||
fun Int.abs() = this.absoluteValue
|
||||
fun Double.bipolarClamp(limit: Double) = this.coerceIn(-limit, limit)
|
||||
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
|
||||
fun Int.bitCount() = java.lang.Integer.bitCount(this)
|
||||
fun Long.bitCount() = java.lang.Long.bitCount(this)
|
||||
inline fun Double.floorToInt() = floor(this).toInt()
|
||||
inline fun Float.floorToInt() = FastMath.floor(this)
|
||||
inline fun Double.ceilToInt() = Math.ceil(this).toInt()
|
||||
inline fun Float.ceilToFloat(): Float = FastMath.ceil(this).toFloat()
|
||||
inline fun Float.ceilToInt() = FastMath.ceil(this)
|
||||
inline fun Float.floorToFloat() = FastMath.floor(this).toFloat()
|
||||
inline fun Float.roundToFloat(): Float = round(this)
|
||||
//inline fun Double.round() = Math.round(this).toDouble()
|
||||
inline fun Double.floorToDouble() = floor(this)
|
||||
inline fun Double.ceilToDouble() = ceil(this)
|
||||
inline fun Int.sqr(): Int = this * this
|
||||
inline fun Double.sqr() = this * this
|
||||
inline fun Float.sqr() = this * this
|
||||
inline fun Double.sqrt() = Math.sqrt(this)
|
||||
inline fun Float.sqrt() = FastMath.sqrt(this)
|
||||
inline fun Int.abs() = this.absoluteValue
|
||||
inline fun Double.abs() = this.absoluteValue
|
||||
inline fun Double.bipolarClamp(limit: Double) = this.coerceIn(-limit, limit)
|
||||
inline fun Boolean.toInt(shift: Int = 0) = if (this) 1.shl(shift) else 0
|
||||
inline fun Boolean.toLong(shift: Int = 0) = if (this) 1L.shl(shift) else 0L
|
||||
inline fun Int.bitCount() = java.lang.Integer.bitCount(this)
|
||||
inline fun Long.bitCount() = java.lang.Long.bitCount(this)
|
||||
|
||||
|
||||
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.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 {
|
||||
if (startValue == endValue) {
|
||||
return startValue
|
||||
@@ -788,6 +786,7 @@ fun AppUpdateListOfSavegames() {
|
||||
|
||||
println("Listing saved worlds...")
|
||||
|
||||
|
||||
// create list of worlds
|
||||
File(worldsDir).listFiles().filter { !it.isDirectory && !it.name.contains('.') }.mapNotNull { file ->
|
||||
try {
|
||||
@@ -800,17 +799,20 @@ fun AppUpdateListOfSavegames() {
|
||||
}
|
||||
}.sortedByDescending { it.getLastModifiedTime() }.forEachIndexed { index, it ->
|
||||
println("${index+1}.\t${it.diskFile.absolutePath}")
|
||||
it.rebuild()
|
||||
// it.rebuild()
|
||||
|
||||
val jsonFile = it.getFile(SAVEGAMEINFO)!!
|
||||
var worldUUID: UUID? = null
|
||||
JsonFetcher.readFromJsonString(ByteArray64Reader(jsonFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
|
||||
if (name == "worldIndex") worldUUID = UUID.fromString(value.asString())
|
||||
}
|
||||
// val jsonFile = it.getFile(SAVEGAMEINFO)!!
|
||||
// var worldUUID: UUID? = null
|
||||
// JsonFetcher.readFromJsonString(ByteArray64Reader(jsonFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
|
||||
// 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 (!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.sortedSavegameWorlds.add(worldUUID)
|
||||
}
|
||||
@@ -832,22 +834,30 @@ fun AppUpdateListOfSavegames() {
|
||||
}
|
||||
}.sortedByDescending { it.getLastModifiedTime() }.forEachIndexed { index, it ->
|
||||
println("${index+1}.\t${it.diskFile.absolutePath}")
|
||||
it.rebuild()
|
||||
// it.rebuild()
|
||||
|
||||
val jsonFile = it.getFile(SAVEGAMEINFO)!!
|
||||
var playerUUID: UUID? = null
|
||||
JsonFetcher.readFromJsonString(ByteArray64Reader(jsonFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
|
||||
if (name == "uuid") playerUUID = UUID.fromString(value.asString())
|
||||
}
|
||||
// val jsonFile = it.getFile(SAVEGAMEINFO)!!
|
||||
// var playerUUID: UUID? = null
|
||||
// JsonFetcher.readFromJsonString(ByteArray64Reader(jsonFile.bytes, Common.CHARSET)).forEachSiblings { name, value ->
|
||||
// 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 (!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.sortedPlayers.add(playerUUID)
|
||||
}
|
||||
}
|
||||
|
||||
println("SortedPlayers...")
|
||||
App.sortedPlayers.forEach {
|
||||
println(it)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -887,3 +897,11 @@ fun checkForSavegameDamage(skimmer: DiskSkimmer): Boolean {
|
||||
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
|
||||
*
|
||||
*/
|
||||
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.1: 2278
|
||||
// Commit counts up to the Release 0.3.2: 2732
|
||||
|
||||
const val VERSION_TAG: String = "test001"
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
// CONFIGURATION FOR TILE MAKER //
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.badlogic.gdx.math.Matrix4
|
||||
import com.badlogic.gdx.utils.Disposable
|
||||
import com.jme3.math.FastMath
|
||||
import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.App.IS_DEVELOPMENT_BUILD
|
||||
import net.torvald.terrarum.gamecontroller.KeyToggler
|
||||
import net.torvald.terrarum.ui.BasicDebugInfoWindow
|
||||
import net.torvald.terrarum.ui.Toolkit
|
||||
@@ -63,7 +64,7 @@ object TerrarumPostProcessor : Disposable {
|
||||
}
|
||||
|
||||
fun resize(w: Int, h: Int) {
|
||||
try { outFBO.dispose() } catch (_: UninitializedPropertyAccessException) {}
|
||||
if (::outFBO.isInitialized) outFBO.tryDispose()
|
||||
outFBO = FrameBuffer(Pixmap.Format.RGBA8888, w, h, false)
|
||||
}
|
||||
|
||||
@@ -71,10 +72,10 @@ object TerrarumPostProcessor : Disposable {
|
||||
batch.dispose()
|
||||
shapeRenderer.dispose()
|
||||
functionRowHelper.dispose()
|
||||
try { lutTex.dispose() } catch (_: UninitializedPropertyAccessException) {}
|
||||
shaderPostDither.dispose()
|
||||
shaderPostNoDither.dispose()
|
||||
outFBO.dispose()
|
||||
if (::lutTex.isInitialized) lutTex.tryDispose()
|
||||
if (::outFBO.isInitialized) outFBO.dispose()
|
||||
}
|
||||
|
||||
private var deltatBenchStr = "ΔF: Gathering data"
|
||||
@@ -150,9 +151,10 @@ object TerrarumPostProcessor : Disposable {
|
||||
}
|
||||
|
||||
// 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.color = safeAreaCol
|
||||
batch.color = if (IS_DEVELOPMENT_BUILD) safeAreaCol else colourNull
|
||||
App.fontGame.draw(it, thisIsDebugStr, 5f, App.scr.height - 24f)
|
||||
}
|
||||
}
|
||||
@@ -168,11 +170,11 @@ object TerrarumPostProcessor : Disposable {
|
||||
val average = tallies.average()
|
||||
|
||||
val halfPos = 0.5f * INGAME.deltaTeeBenchmarks.size
|
||||
val halfInd = halfPos.floorInt()
|
||||
val halfInd = halfPos.floorToInt()
|
||||
val low5pos = 0.05f * INGAME.deltaTeeBenchmarks.size
|
||||
val low5ind = low5pos.floorInt()
|
||||
val low5ind = low5pos.floorToInt()
|
||||
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 low5 = FastMath.interpolateLinear(low5pos - low5ind, tallies[low5ind], tallies[low5ind + 1])
|
||||
@@ -192,39 +194,40 @@ object TerrarumPostProcessor : Disposable {
|
||||
return outFBO
|
||||
}
|
||||
private val rng = HQRNG()
|
||||
private val colourNull = Color(0)
|
||||
|
||||
private fun Double.format(digits: Int) = "%.${digits}f".format(this)
|
||||
private fun Float.format(digits: Int) = "%.${digits}f".format(this)
|
||||
|
||||
private val swizzler = intArrayOf(
|
||||
1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1,
|
||||
1,0,0,0, 0,1,0,0, 0,0,0,1, 0,0,1,0,
|
||||
1,0,0,0, 0,0,1,0, 0,1,0,0, 0,0,0,1,
|
||||
1,0,0,0, 0,0,1,0, 0,0,0,1, 0,1,0,0,
|
||||
1,0,0,0, 0,0,0,1, 0,1,0,0, 0,0,1,0,
|
||||
1,0,0,0, 0,0,0,1, 0,0,1,0, 0,1,0,0,
|
||||
private val swizzler = floatArrayOf(
|
||||
1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f,
|
||||
1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f, 0f,0f,1f,0f,
|
||||
1f,0f,0f,0f, 0f,0f,1f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f,
|
||||
1f,0f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f, 0f,1f,0f,0f,
|
||||
1f,0f,0f,0f, 0f,0f,0f,1f, 0f,1f,0f,0f, 0f,0f,1f,0f,
|
||||
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,
|
||||
0,1,0,0, 1,0,0,0, 0,0,0,1, 0,0,1,0,
|
||||
0,1,0,0, 0,0,1,0, 1,0,0,0, 0,0,0,1,
|
||||
0,1,0,0, 0,0,1,0, 0,0,0,1, 1,0,0,0,
|
||||
0,1,0,0, 0,0,0,1, 1,0,0,0, 0,0,1,0,
|
||||
0,1,0,0, 0,0,0,1, 0,0,1,0, 1,0,0,0,
|
||||
0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f,
|
||||
0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,0f,1f, 0f,0f,1f,0f,
|
||||
0f,1f,0f,0f, 0f,0f,1f,0f, 1f,0f,0f,0f, 0f,0f,0f,1f,
|
||||
0f,1f,0f,0f, 0f,0f,1f,0f, 0f,0f,0f,1f, 1f,0f,0f,0f,
|
||||
0f,1f,0f,0f, 0f,0f,0f,1f, 1f,0f,0f,0f, 0f,0f,1f,0f,
|
||||
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,
|
||||
0,0,1,0, 1,0,0,0, 0,0,0,1, 0,1,0,0,
|
||||
0,0,1,0, 0,1,0,0, 1,0,0,0, 0,0,0,1,
|
||||
0,0,1,0, 0,1,0,0, 0,0,0,1, 1,0,0,0,
|
||||
0,0,1,0, 0,0,0,1, 1,0,0,0, 0,1,0,0,
|
||||
0,0,1,0, 0,0,0,1, 0,1,0,0, 1,0,0,0,
|
||||
0f,0f,1f,0f, 1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f,
|
||||
0f,0f,1f,0f, 1f,0f,0f,0f, 0f,0f,0f,1f, 0f,1f,0f,0f,
|
||||
0f,0f,1f,0f, 0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,0f,1f,
|
||||
0f,0f,1f,0f, 0f,1f,0f,0f, 0f,0f,0f,1f, 1f,0f,0f,0f,
|
||||
0f,0f,1f,0f, 0f,0f,0f,1f, 1f,0f,0f,0f, 0f,1f,0f,0f,
|
||||
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,
|
||||
0,0,0,1, 1,0,0,0, 0,0,1,0, 0,1,0,0,
|
||||
0,0,0,1, 0,1,0,0, 1,0,0,0, 0,0,1,0,
|
||||
0,0,0,1, 0,1,0,0, 0,0,1,0, 1,0,0,0,
|
||||
0,0,0,1, 0,0,1,0, 1,0,0,0, 0,1,0,0,
|
||||
0,0,0,1, 0,0,1,0, 0,1,0,0, 1,0,0,0,
|
||||
).map { it.toFloat() }.toFloatArray()
|
||||
0f,0f,0f,1f, 1f,0f,0f,0f, 0f,1f,0f,0f, 0f,0f,1f,0f,
|
||||
0f,0f,0f,1f, 1f,0f,0f,0f, 0f,0f,1f,0f, 0f,1f,0f,0f,
|
||||
0f,0f,0f,1f, 0f,1f,0f,0f, 1f,0f,0f,0f, 0f,0f,1f,0f,
|
||||
0f,0f,0f,1f, 0f,1f,0f,0f, 0f,0f,1f,0f, 1f,0f,0f,0f,
|
||||
0f,0f,0f,1f, 0f,0f,1f,0f, 1f,0f,0f,0f, 0f,1f,0f,0f,
|
||||
0f,0f,0f,1f, 0f,0f,1f,0f, 0f,1f,0f,0f, 1f,0f,0f,0f,
|
||||
)
|
||||
|
||||
private fun postShader(projMat: Matrix4, fbo: FrameBuffer) {
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package net.torvald.terrarum
|
||||
|
||||
import net.torvald.terrarum.App.printdbg
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
|
||||
|
||||
companion object {
|
||||
const val minimumW = 1080
|
||||
const val minimumW = 1024
|
||||
const val minimumH = 720
|
||||
const val defaultW = 1280
|
||||
const val defaultH = 720
|
||||
@@ -39,7 +40,7 @@ class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
|
||||
var windowH: Int = 0; private set
|
||||
|
||||
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,) {
|
||||
@@ -56,8 +57,8 @@ class TerrarumScreenSize(scrw: Int = defaultW, scrh: Int = defaultH) {
|
||||
|
||||
this.magn = magn
|
||||
|
||||
windowW = (scrw * magn).ceilInt() and 0x7FFFFFFE
|
||||
windowH = (scrh * magn).ceilInt() and 0x7FFFFFFE
|
||||
windowW = (scrw * magn).ceilToInt() and 0x7FFFFFFE
|
||||
windowH = (scrh * magn).ceilToInt() and 0x7FFFFFFE
|
||||
|
||||
|
||||
printdbg(this, "Window dim: $windowW x $windowH, called by:")
|
||||
|
||||
@@ -166,7 +166,7 @@ class UIItemInventoryCatBar(
|
||||
// set up underlined indicator
|
||||
init {
|
||||
// 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
|
||||
val col = /*if (x == 0)*/ /*0xffffff_80.toInt()*/
|
||||
/*else if (x == 1)*/ /*0xffffff_c0.toInt()*/
|
||||
|
||||
@@ -209,8 +209,8 @@ class BlockCodex {
|
||||
prop.isSolid = record.boolVal("solid")
|
||||
//prop.isClear = record.boolVal("clear")
|
||||
|
||||
prop.isPlatform = prop.tags.contains("PLATFORM")
|
||||
prop.isActorBlock = prop.tags.contains("ACTORBLOCK")
|
||||
prop.isPlatform = prop.hasTag("PLATFORM")
|
||||
prop.isActorBlock = prop.hasTag("ACTORBLOCK")
|
||||
|
||||
prop.isWallable = record.boolVal("wall")
|
||||
prop.maxSupport = record.intVal("grav")
|
||||
|
||||
@@ -75,6 +75,8 @@ class BlockProp {
|
||||
BlockCodex[BlockCodex.tileToVirtual[id]!![offset]]._lumCol.lane(channel)
|
||||
}
|
||||
|
||||
fun hasTag(s: String) = tags.contains(s)
|
||||
|
||||
/**
|
||||
* @param luminosity
|
||||
*/
|
||||
|
||||
@@ -108,7 +108,7 @@ object BlockPropUtil {
|
||||
return when (prop.dynamicLuminosityFunction) {
|
||||
1 -> getTorchFlicker(prop)
|
||||
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)
|
||||
5 -> getPulsate(prop)
|
||||
else -> prop.baseLumCol
|
||||
|
||||
@@ -19,11 +19,12 @@ import net.torvald.terrarum.toInt
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
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
|
||||
|
||||
|
||||
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("hash: $hashedPwd")
|
||||
|
||||
if ("09ccf5067db6f58265b004829e33e715e819ba0984f1e1fcef49c36fcd5f745f".equals(hashedPwd, ignoreCase = true)) {
|
||||
if ("2d962f949f55906ac47f16095ded190c9e44d95920259b8f36c2e54bd75df173".equals(hashedPwd, ignoreCase = true)) {
|
||||
// beedle
|
||||
val msg = if (a) "Locked" else "Authenticated"
|
||||
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
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -18,12 +18,14 @@ import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.gameworld.BlockAddress
|
||||
import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.IngamePlayer
|
||||
import net.torvald.terrarum.realestate.LandUtil
|
||||
import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import java.util.*
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.math.max
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
@@ -442,7 +444,7 @@ open class ActorWithBody : Actor {
|
||||
@Transient val feetPosPoint: Point2d = Point2d(0.0,0.0)
|
||||
//get() = Point2d(hitbox.centeredX, hitbox.endY)
|
||||
@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)
|
||||
|
||||
@@ -474,23 +476,23 @@ open class ActorWithBody : Actor {
|
||||
hitbox.reassign(newHitbox)
|
||||
|
||||
hIntTilewiseHitbox.setFromTwoPoints(
|
||||
hitbox.startX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
|
||||
hitbox.startY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
|
||||
hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
|
||||
hitbox.endY.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).floorToDouble() + 0.5,
|
||||
hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
|
||||
hitbox.endY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5
|
||||
)
|
||||
intTilewiseHitbox.setFromTwoPoints(
|
||||
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()
|
||||
hitbox.startX.div(TILE_SIZE).floorToDouble(),
|
||||
hitbox.startY.div(TILE_SIZE).floorToDouble(),
|
||||
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
|
||||
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble()
|
||||
)
|
||||
|
||||
centrePosVector.set(hitbox.centeredX, hitbox.centeredY)
|
||||
centrePosPoint.set(hitbox.centeredX, hitbox.centeredY)
|
||||
feetPosVector.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) {
|
||||
@@ -553,7 +555,6 @@ open class ActorWithBody : Actor {
|
||||
*/
|
||||
if (!isNoCollideWorld) {
|
||||
displaceHitbox()
|
||||
//collisionInterpolatorRun()
|
||||
}
|
||||
else {
|
||||
stairPenaltyCounter = 999
|
||||
@@ -618,23 +619,23 @@ open class ActorWithBody : Actor {
|
||||
}
|
||||
|
||||
hIntTilewiseHitbox.setFromTwoPoints(
|
||||
hitbox.startX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
|
||||
hitbox.startY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
|
||||
hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floor() + 0.5,
|
||||
hitbox.endY.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).floorToDouble() + 0.5,
|
||||
hitbox.endX.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5,
|
||||
hitbox.endY.plus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble() + 0.5
|
||||
)
|
||||
intTilewiseHitbox.setFromTwoPoints(
|
||||
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()
|
||||
hitbox.startX.div(TILE_SIZE).floorToDouble(),
|
||||
hitbox.startY.div(TILE_SIZE).floorToDouble(),
|
||||
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
|
||||
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble()
|
||||
)
|
||||
|
||||
centrePosVector.set(hitbox.centeredX, hitbox.centeredY)
|
||||
centrePosPoint.set(hitbox.centeredX, hitbox.centeredY)
|
||||
feetPosVector.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)
|
||||
@@ -672,16 +673,6 @@ open class ActorWithBody : Actor {
|
||||
// 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)
|
||||
*
|
||||
@@ -697,6 +688,7 @@ open class ActorWithBody : Actor {
|
||||
}
|
||||
|
||||
private fun displaceHitbox() {
|
||||
val printdbg1 = true && App.IS_DEVELOPMENT_BUILD
|
||||
// // HOW IT SHOULD WORK // //
|
||||
// ////////////////////////
|
||||
// combineVeloToMoveDelta now
|
||||
@@ -723,46 +715,8 @@ open class ActorWithBody : Actor {
|
||||
|
||||
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?) {
|
||||
// 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.modTile() = this.div(TILE_SIZE).floorToInt().times(TILE_SIZE)
|
||||
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,
|
||||
// in which the modTileDelta returns a wrong value
|
||||
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) *
|
||||
// direction to push is determined by the velocity
|
||||
// proc:
|
||||
@@ -792,63 +763,63 @@ open class ActorWithBody : Actor {
|
||||
// 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
|
||||
|
||||
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
|
||||
|
||||
for (step in 1..ccdSteps) {
|
||||
for (step in 0..ccdSteps) {
|
||||
|
||||
val stepBox = sixteenStep[step]
|
||||
|
||||
/*forEachOccupyingTilePos(stepBox) {
|
||||
val tileCoord = LandUtil.resolveBlockAddr(world!!, it)
|
||||
val tile = world!!.getTileFromTerrain(tileCoord.first, tileCoord.second) ?: Block.STONE
|
||||
val goingDownwardDirection = Math.toDegrees(vectorSum.direction).let { it > 0.0 && it < 180.0 }
|
||||
val goingDown = (vectorSum.y >= PHYS_EPSILON_VELO || (vectorSum.y.absoluteValue < PHYS_EPSILON_VELO && !isWalled(stepBox, COLLIDING_BOTTOM))) // TODO reverse gravity adaptation?
|
||||
|
||||
if (shouldICollideWithThis(tile) || (it.isFeetTile(stepBox) && shouldICollideWithThisFeet(tile))) {
|
||||
collidingStep = step
|
||||
}
|
||||
}*/
|
||||
debug2("stepbox[$step]=$stepBox; goingDown=$goingDown, downDown=$downDown, goingDownwardDirection=$goingDownwardDirection")
|
||||
|
||||
// trying to use same function as the others, in an effort to eliminate the "contradiction" mentioned below
|
||||
if (isColliding(stepBox, vectorSum.y > PHYS_EPSILON_DIST)) {
|
||||
if (collidingStep == null && isColliding(stepBox, goingDown && !downDown && goingDownwardDirection)) {
|
||||
collidingStep = step
|
||||
}
|
||||
|
||||
if (collidingStep != null) break
|
||||
// if (collidingStep != null) break
|
||||
}
|
||||
|
||||
var bounceX = false
|
||||
var bounceY = false
|
||||
var zeroX = 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
|
||||
if (collidingStep == null) {
|
||||
debug1("== Collision step: no collision")
|
||||
hitbox.translate(vectorSum)
|
||||
// grounded = false
|
||||
}
|
||||
// collision detected
|
||||
else {
|
||||
debug1("== Collision step: $collidingStep / $ccdSteps")
|
||||
debug1("CCD hitbox: ${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))
|
||||
}
|
||||
val newHitbox = newHitbox!!
|
||||
|
||||
// superseded by isWalledStairs-related codes
|
||||
//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
|
||||
|
||||
//println("collision: $selfCollisionStatus\tstaircasing: $staircaseStatus")
|
||||
debug1("collision: $selfCollisionStatus\tstaircasing: $staircaseStatus")
|
||||
|
||||
when (selfCollisionStatus) {
|
||||
0 -> {
|
||||
debug1("[ActorWBMovable] Contradiction -- collision detected by CCD, but isWalled() says otherwise")
|
||||
}
|
||||
5 -> {
|
||||
/*0 -> {
|
||||
debug1("Contradiction -- collision detected by CCD, but isWalled() says otherwise")
|
||||
}*/
|
||||
/* 5 */ COLLIDING_LR -> {
|
||||
zeroX = true
|
||||
}
|
||||
10 -> {
|
||||
/* 10 */ COLLIDING_UD -> {
|
||||
zeroY = true
|
||||
}
|
||||
15 -> {
|
||||
/* 15 */ COLLIDING_ALLSIDE -> {
|
||||
newHitbox.reassign(sixteenStep[0]); zeroX = true; zeroY = true
|
||||
debug1("reassining hitbox to ${sixteenStep[0]}")
|
||||
}
|
||||
// one-side collision
|
||||
1, 11 -> {
|
||||
newHitbox.translatePosX(TILE_SIZE - newHitbox.startX.modTileDelta()); bounceX = true
|
||||
/* 1, 11 */ COLLIDING_LEFT, COLLIDING_LEFT or COLLIDING_UD -> {
|
||||
val t = TILE_SIZE - newHitbox.startX.modTileDelta()
|
||||
newHitbox.translatePosX(t); bounceX = true
|
||||
debug1("translate x by $t")
|
||||
}
|
||||
4, 14 -> {
|
||||
newHitbox.translatePosX(-newHitbox.endX.modTileDelta()); bounceX = true
|
||||
/* 4, 14 */ COLLIDING_RIGHT, COLLIDING_RIGHT or COLLIDING_UD -> {
|
||||
val t = -newHitbox.endX.modTileDelta()
|
||||
newHitbox.translatePosX(t); bounceX = true
|
||||
debug1("translate x by $t")
|
||||
}
|
||||
8, 13 -> {
|
||||
newHitbox.translatePosY(TILE_SIZE - newHitbox.startY.modTileDelta()); bounceY = true
|
||||
/* 8, 13 */ COLLIDING_TOP, COLLIDING_TOP or COLLIDING_LR -> {
|
||||
val t = TILE_SIZE - newHitbox.startY.modTileDelta()
|
||||
newHitbox.translatePosY(t); bounceY = true
|
||||
debug1("translate y by $t")
|
||||
}
|
||||
2, 7 -> {
|
||||
newHitbox.translatePosY(-newHitbox.endY.modTileDelta()); bounceY = true
|
||||
/* 2, 7 */ COLLIDING_BOTTOM, COLLIDING_BOTTOM or COLLIDING_LR -> {
|
||||
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
|
||||
// for the ease of writing, this jumptable is separated from above.
|
||||
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!!)
|
||||
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
|
||||
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!!)
|
||||
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
|
||||
newHitbox.startY.div(TILE_SIZE).ceil() * TILE_SIZE
|
||||
newHitbox.startY.div(TILE_SIZE).ceilToDouble() * TILE_SIZE
|
||||
|
||||
val offendingHitboxPointX = if (selfCollisionStatus in listOf(6, 12))
|
||||
newHitbox.endX
|
||||
@@ -927,7 +912,6 @@ open class ActorWithBody : Actor {
|
||||
newHitbox.startY
|
||||
|
||||
|
||||
|
||||
val angleOfIncidence =
|
||||
if (selfCollisionStatus in listOf(3, 9))
|
||||
vectorSum.direction.toPositiveRad()
|
||||
@@ -942,10 +926,15 @@ open class ActorWithBody : Actor {
|
||||
(Vector2(offendingHitboxPointX, offendingHitboxPointY) -
|
||||
Vector2(offendingTileWorldX, offendingTileWorldY)).direction
|
||||
|
||||
debug1(
|
||||
"incidentAngle: ${Math.toDegrees(angleOfIncidence)}°, threshold: ${
|
||||
Math.toDegrees(
|
||||
angleThreshold
|
||||
)
|
||||
}°"
|
||||
)
|
||||
|
||||
debug1("vectorSum: $vectorSum, vectorDirRaw: ${vectorSum.direction / Math.PI}pi")
|
||||
debug1("incidentAngle: ${angleOfIncidence / Math.PI}pi, threshold: ${angleThreshold / Math.PI}pi")
|
||||
|
||||
debug1("offendingTileWorldY=$offendingTileWorldY, offendingHitboxPointY=$offendingHitboxPointY")
|
||||
|
||||
val displacementAbs = Vector2(
|
||||
(offendingTileWorldX - offendingHitboxPointX).abs(),
|
||||
@@ -957,35 +946,57 @@ open class ActorWithBody : Actor {
|
||||
|
||||
val displacementUnitVector =
|
||||
if (angleOfIncidence == angleThreshold)
|
||||
-vectorSum
|
||||
-vectorSum.signum
|
||||
else {
|
||||
when (selfCollisionStatus) {
|
||||
3 -> if (angleOfIncidence > angleThreshold) 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)
|
||||
3 -> if (angleOfIncidence > angleThreshold) 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)
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
val finalDisplacement =
|
||||
if (angleOfIncidence == angleThreshold)
|
||||
displacementUnitVector
|
||||
else
|
||||
// if (angleOfIncidence == angleThreshold)
|
||||
// displacementUnitVector
|
||||
// else
|
||||
Vector2(
|
||||
displacementAbs.x * displacementUnitVector.x,
|
||||
displacementAbs.y * displacementUnitVector.y
|
||||
)
|
||||
|
||||
debug1("displacementAbs=$displacementAbs")
|
||||
debug1("displacementUnitVector=$displacementUnitVector")
|
||||
debug1("finalDisplacement=$finalDisplacement")
|
||||
|
||||
// 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
|
||||
// let original X velocity to pass-thru instead of snapping to tiles coded above
|
||||
// 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.x = vectorSum.x
|
||||
|
||||
@@ -998,7 +1009,8 @@ open class ActorWithBody : Actor {
|
||||
// so we also zero the same exact value here for perfect hiding
|
||||
if (controllerV != null) {
|
||||
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
|
||||
stairPenaltyCounter = 0
|
||||
stairPenaltyMax = Math.pow(stairRatio, 2.4).times(166).roundToInt().coerceAtMost(64)
|
||||
@@ -1021,7 +1033,6 @@ open class ActorWithBody : Actor {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// bounce X/Y
|
||||
if (bounceX) {
|
||||
externalV.x *= elasticity
|
||||
@@ -1042,6 +1053,7 @@ open class ActorWithBody : Actor {
|
||||
|
||||
|
||||
hitbox.reassign(newHitbox)
|
||||
debug1("resulting hitbox: $newHitbox")
|
||||
|
||||
|
||||
// slam-into-whatever damage (such dirty; much hack; wow)
|
||||
@@ -1055,104 +1067,87 @@ open class ActorWithBody : Actor {
|
||||
// grounded = true
|
||||
|
||||
// another platform-related hacks
|
||||
if (this is ActorHumanoid) downDownVirtually = false
|
||||
// if (this is ActorHumanoid) downButtonHeld = false
|
||||
|
||||
}
|
||||
}// end of collision not detected
|
||||
|
||||
|
||||
|
||||
|
||||
return
|
||||
|
||||
|
||||
|
||||
// if collision not detected, just don't care; it's not your job to apply moveDelta
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
} // end of (world != null)
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
// detectors are inside of the bounding box
|
||||
// CONFIRMED
|
||||
val x1 = hitbox.startX
|
||||
val x2 = hitbox.endX - A_PIXEL
|
||||
val y1 = hitbox.startY
|
||||
val y2 = hitbox.endY - A_PIXEL
|
||||
val y1 = hitbox.startY - if (gravitation.y < 0) HALF_PIXEL else 0.0
|
||||
val x2 = hitbox.endX - PHYS_EPSILON_DIST
|
||||
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!
|
||||
|
||||
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()
|
||||
val txStart = x1/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||
val txEnd = x2/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||
val tyStart = y1/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||
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
|
||||
*/
|
||||
fun isWalled(hitbox: Hitbox, option: Int): Boolean {
|
||||
val x1: Double
|
||||
val x2: Double
|
||||
val y1: Double
|
||||
val y2: Double
|
||||
|
||||
/*
|
||||
The structure:
|
||||
|
||||
@@ -1165,30 +1160,15 @@ open class ActorWithBody : Actor {
|
||||
IMPORTANT AF NOTE: things are ASYMMETRIC!
|
||||
*/
|
||||
|
||||
// AT LEAST THESE ARE CONFIRMED
|
||||
if (option == COLLIDING_TOP) {
|
||||
x1 = hitbox.startX
|
||||
x2 = hitbox.endX - A_PIXEL
|
||||
y1 = hitbox.startY - A_PIXEL
|
||||
y2 = y1
|
||||
}
|
||||
else if (option == COLLIDING_BOTTOM) {
|
||||
x1 = hitbox.startX
|
||||
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
|
||||
if (option.popcnt() == 1) {
|
||||
val (x1, x2, y1, y2) = hitbox.getWallDetection(option)
|
||||
|
||||
val txStart = x1/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||
val txEnd = x2/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||
val tyStart = y1/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||
val tyEnd = y2/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||
|
||||
return isCollidingInternalStairs(txStart, tyStart, txEnd, tyEnd, option == COLLIDING_BOTTOM).first == 2
|
||||
}
|
||||
else if (option == COLLIDING_ALLSIDE) {
|
||||
return isWalled(hitbox, COLLIDING_LEFT) || isWalled(hitbox, COLLIDING_RIGHT) ||
|
||||
@@ -1201,25 +1181,14 @@ open class ActorWithBody : Actor {
|
||||
else if (option == COLLIDING_UD) {
|
||||
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
|
||||
*/
|
||||
private fun isWalledStairs(hitbox: Hitbox, option: Int): Pair<Int, Int> {
|
||||
val x1: Double
|
||||
val x2: Double
|
||||
val y1: Double
|
||||
val y2: Double
|
||||
|
||||
/*
|
||||
The structure:
|
||||
|
||||
@@ -1232,81 +1201,36 @@ open class ActorWithBody : Actor {
|
||||
IMPORTANT AF NOTE: things are ASYMMETRIC!
|
||||
*/
|
||||
|
||||
// AT LEAST THESE ARE CONFIRMED
|
||||
if (option == COLLIDING_TOP) {
|
||||
x1 = hitbox.startX
|
||||
x2 = hitbox.endX - A_PIXEL
|
||||
y1 = hitbox.startY - A_PIXEL
|
||||
y2 = y1
|
||||
}
|
||||
else if (option == COLLIDING_BOTTOM) {
|
||||
x1 = hitbox.startX
|
||||
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
|
||||
if (option.popcnt() == 1) {
|
||||
val (x1, x2, y1, y2) = hitbox.getWallDetection(option)
|
||||
|
||||
val pxStart = x1/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||
val pxEnd = x2/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||
val pyStart = y1/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||
val pyEnd = y2/*.plus(HALF_PIXEL)*/.floorToInt()
|
||||
|
||||
return isCollidingInternalStairs(pxStart, pyStart, pxEnd, pyEnd, option == COLLIDING_BOTTOM)
|
||||
}
|
||||
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),
|
||||
maxOf(isWalledStairs(hitbox, COLLIDING_BOTTOM).first,
|
||||
max(isWalledStairs(hitbox, COLLIDING_BOTTOM).first,
|
||||
isWalledStairs(hitbox, COLLIDING_TOP).first)) to 0
|
||||
|
||||
}
|
||||
else if (option == COLLIDING_LR) {
|
||||
val v1 = isWalledStairs(hitbox, COLLIDING_LEFT)
|
||||
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) {
|
||||
return maxOf(isWalledStairs(hitbox, COLLIDING_BOTTOM).first,
|
||||
return max(isWalledStairs(hitbox, COLLIDING_BOTTOM).first,
|
||||
isWalledStairs(hitbox, COLLIDING_TOP).first) to 0
|
||||
}
|
||||
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
|
||||
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
|
||||
@@ -1323,16 +1247,24 @@ open class ActorWithBody : Actor {
|
||||
var stairHeight = 0
|
||||
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) {
|
||||
|
||||
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
|
||||
|
||||
for (x in pxStart..pxEnd) {
|
||||
val tx = (x / TILE_SIZE) - (if (x < 0) 1 else 0) // round down toward negative infinity
|
||||
val ty = (y / TILE_SIZE) - (if (y < 0) 1 else 0) // round down toward negative infinity
|
||||
val tx = (x / TILE_SIZED).floorToInt() // round down toward negative infinity
|
||||
val tile = world!!.getTileFromTerrain(tx, ty)
|
||||
|
||||
if (feet) {
|
||||
if (feet && isFeetTileHeight) {
|
||||
if (shouldICollideWithThisFeet(tile)) {
|
||||
hasFloor = true
|
||||
hitFloor = true
|
||||
@@ -1364,7 +1296,7 @@ open class ActorWithBody : Actor {
|
||||
//println("-> $stairHeight")
|
||||
|
||||
// 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
|
||||
else if (stairHeight == 0) 0 to 0
|
||||
// there was collision and stairHeight <= AUTO_CLIMB_STRIDE
|
||||
@@ -1404,7 +1336,7 @@ open class ActorWithBody : Actor {
|
||||
// platforms, moving downward AND not "going down"
|
||||
(this is ActorHumanoid && BlockCodex[tile].isPlatform &&
|
||||
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
|
||||
(this !is ActorHumanoid && BlockCodex[tile].isPlatform &&
|
||||
externalV.y + (controllerV?.y ?: 0.0) >= 0.0)
|
||||
@@ -1744,8 +1676,8 @@ open class ActorWithBody : Actor {
|
||||
if (KeyToggler.isOn(Input.Keys.F9)) {
|
||||
val blockMark = CommonResourcePool.getAsTextureRegionPack("blockmarkings_common").get(0, 0)
|
||||
|
||||
batch.color = HITBOX_COLOURS0
|
||||
for (y in 0..intTilewiseHitbox.height.toInt()) {
|
||||
for (y in 0..intTilewiseHitbox.height.toInt() + 1) {
|
||||
batch.color = if (y == intTilewiseHitbox.height.toInt() + 1) HITBOX_COLOURS1 else HITBOX_COLOURS0
|
||||
for (x in 0..intTilewiseHitbox.width.toInt()) {
|
||||
batch.draw(blockMark,
|
||||
(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
|
||||
|
||||
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())
|
||||
}
|
||||
}
|
||||
@@ -1890,10 +1826,10 @@ open class ActorWithBody : Actor {
|
||||
|
||||
|
||||
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(),
|
||||
hitbox.startX.div(TILE_SIZE).floorToDouble(),
|
||||
hitbox.startY.div(TILE_SIZE).floorToDouble(),
|
||||
hitbox.endX.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
|
||||
hitbox.endY.minus(PHYS_EPSILON_DIST).div(TILE_SIZE).floorToDouble(),
|
||||
true
|
||||
) // NOT the same as intTilewiseHitbox !!
|
||||
|
||||
@@ -1914,10 +1850,10 @@ open class ActorWithBody : Actor {
|
||||
val tiles = ArrayList<ItemID?>()
|
||||
|
||||
// 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()) {
|
||||
tiles.add(world!!.getTileFromTerrain(x, y))
|
||||
for (x in 0..intTilewiseHitbox.width.toInt()) {
|
||||
tiles.add(world!!.getTileFromTerrain(x + intTilewiseHitbox.startX.toInt(), y + intTilewiseHitbox.startY.toInt()))
|
||||
}
|
||||
|
||||
return tiles.forEach(consumer)
|
||||
@@ -1930,10 +1866,11 @@ open class ActorWithBody : Actor {
|
||||
val tileProps = ArrayList<BlockProp?>()
|
||||
|
||||
// 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()) {
|
||||
tileProps.add(BlockCodex[world!!.getTileFromTerrain(x, y)])
|
||||
for (x in 0..intTilewiseHitbox.width.toInt()) {
|
||||
tileProps.add(BlockCodex[world!!.getTileFromTerrain(x + intTilewiseHitbox.startX.toInt(), y + intTilewiseHitbox.startY.toInt())])
|
||||
}
|
||||
|
||||
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 PHYS_EPSILON_DIST = 1.0 / 65536.0
|
||||
// @Transient const val PHYS_EPSILON_VELO = 1.0 / 8192.0
|
||||
@Transient const val PHYS_EPSILON_DIST = 1.0 / 4096.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_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
|
||||
}
|
||||
|
||||
|
||||
@@ -145,6 +145,9 @@ class Hitbox {
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize the hitbox centred around the "canonical" point.
|
||||
*/
|
||||
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_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.TerrarumAppConfiguration.TILE_SIZE
|
||||
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.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameworld.fmod
|
||||
@@ -42,10 +42,10 @@ class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
||||
get() = WorldCamera.y + Gdx.input.y / (terrarumIngame.screenZoom)
|
||||
/** currently pointing tile coordinate */
|
||||
val mouseTileX: Int
|
||||
get() = (mouseX / TILE_SIZE).floorInt()
|
||||
get() = (mouseX / TILE_SIZE).floorToInt()
|
||||
/** currently pointing tile coordinate */
|
||||
val mouseTileY: Int
|
||||
get() = (mouseY / TILE_SIZE).floorInt()
|
||||
get() = (mouseY / TILE_SIZE).floorToInt()
|
||||
|
||||
init {
|
||||
try {
|
||||
|
||||
@@ -17,6 +17,7 @@ import net.torvald.terrarum.savegame.ByteArray64
|
||||
import net.torvald.terrarum.utils.HashArray
|
||||
import net.torvald.terrarum.utils.ZipCodedStr
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import kotlin.math.min
|
||||
|
||||
typealias ItemID = String
|
||||
|
||||
@@ -358,6 +359,8 @@ abstract class GameItem(val originalID: ItemID) : Comparable<GameItem>, Cloneabl
|
||||
return this
|
||||
}
|
||||
|
||||
fun hasTag(s: String) = tags.contains(s)
|
||||
|
||||
|
||||
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 mousePos3 = Vector2(Terrarum.mouseX - INGAME.world.width * TILE_SIZED, Terrarum.mouseY)
|
||||
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
|
||||
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 mousePos3 = Vector2(Terrarum.mouseX - INGAME.world.width * TILE_SIZED, Terrarum.mouseY)
|
||||
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 distMax = actor.actorValue.getAsDouble(AVKey.REACH)!! * reachBonus // perform some error checking here
|
||||
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 IntArray.pickRandom(): Int = this[HQRNG().nextInt(this.size)]
|
||||
|
||||
@@ -46,12 +46,12 @@ open class ParticleBase(renderOrder: Actor.RenderOrder, val despawnUponCollision
|
||||
if (velocity.isZero ||
|
||||
// simple stuck check
|
||||
BlockCodex[(INGAME.world).getTileFromTerrain(
|
||||
hitbox.centeredX.div(TerrarumAppConfiguration.TILE_SIZE).floorInt(),
|
||||
hitbox.startY.div(TerrarumAppConfiguration.TILE_SIZE).floorInt()
|
||||
hitbox.centeredX.div(TerrarumAppConfiguration.TILE_SIZE).floorToInt(),
|
||||
hitbox.startY.div(TerrarumAppConfiguration.TILE_SIZE).floorToInt()
|
||||
)].isSolid ||
|
||||
BlockCodex[(INGAME.world).getTileFromTerrain(
|
||||
hitbox.centeredX.div(TerrarumAppConfiguration.TILE_SIZE).floorInt(),
|
||||
hitbox.endY.div(TerrarumAppConfiguration.TILE_SIZE).floorInt()
|
||||
hitbox.centeredX.div(TerrarumAppConfiguration.TILE_SIZE).floorToInt(),
|
||||
hitbox.endY.div(TerrarumAppConfiguration.TILE_SIZE).floorToInt()
|
||||
)].isSolid) {
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame.Companion.inUpdateRange
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.*
|
||||
import org.dyn4j.geometry.Vector2
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
@@ -120,10 +121,10 @@ object WorldSimulator {
|
||||
|
||||
// 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"
|
||||
/*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_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
|
||||
for (y in for_y_start..for_y_end) {
|
||||
for (x in for_x_start..for_x_end) {
|
||||
@@ -354,7 +355,7 @@ object WorldSimulator {
|
||||
if (flow > minFlow) {
|
||||
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 + 1][x] += flow
|
||||
@@ -404,7 +405,7 @@ object WorldSimulator {
|
||||
if (flow > minFlow) {
|
||||
flow *= 0.5f
|
||||
}
|
||||
flow = flow.coerceIn(0f, minOf(maxSpeed, remainingMass))
|
||||
flow = flow.coerceIn(0f, min(maxSpeed, remainingMass))
|
||||
|
||||
fluidNewMap[y][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