mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-06 08:38:30 +09:00
Compare commits
97 Commits
v0.3.2-tes
...
v0.3.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
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,40 @@
|
||||
{
|
||||
"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_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,36 @@
|
||||
{
|
||||
"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_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": "輸入法",
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
@@ -22,6 +22,8 @@ Seed
|
||||
SetAV
|
||||
SetBulletin
|
||||
SetScale
|
||||
SetSol
|
||||
SetTurb
|
||||
SetTime
|
||||
SetTimeDelta
|
||||
SpawnPhysTestBall
|
||||
|
||||
|
@@ -19,5 +19,5 @@
|
||||
"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."
|
||||
"CONTEXT_PLACE_COORDINATE": "Coordinate"
|
||||
}
|
||||
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."
|
||||
}
|
||||
@@ -20,5 +20,5 @@
|
||||
"GAME_CRAFTABLE_ITEMS": "제작 가능한 아이템",
|
||||
"MENU_LABEL_RENAME": "이름 바꾸기",
|
||||
"GAME_ACTION_TELEPORT": "텔레포트하기",
|
||||
"CONTEXT_THIS_IS_A_WORLD_CURRENTLY_PLAYING": "현재 플레이 중인 월드입니다."
|
||||
"CONTEXT_PLACE_COORDINATE": "좌표"
|
||||
}
|
||||
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": "현재 플레이 중인 월드입니다."
|
||||
}
|
||||
@@ -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/
|
||||
|
||||
@@ -27,6 +27,7 @@ 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/
|
||||
|
||||
@@ -27,6 +27,7 @@ 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/
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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])
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -14,22 +14,36 @@ 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.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.awt.FlowLayout
|
||||
import java.awt.GridLayout
|
||||
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 +67,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 +82,29 @@ 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)
|
||||
|
||||
|
||||
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,9 +126,37 @@ class Application : Game() {
|
||||
oneScreen.dispose()
|
||||
}
|
||||
|
||||
val outTexWidth = 256
|
||||
val outTexWidth = 1
|
||||
val outTexHeight = 256
|
||||
|
||||
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 {
|
||||
val elevation1 = -Math.toDegrees(elevation)
|
||||
val elevation2 = -Math.toDegrees(elevation) / 28.5
|
||||
val scale = (1f - (1f - 1f / 1.8.pow(elevation1)) * 0.97f).toFloat()
|
||||
val scale2 = (1.0 - (elevation2.pow(E) / E.pow(elevation2))*0.8).toFloat()
|
||||
CIEXYZ(
|
||||
this.X.scaleFun() * scale * scale2,
|
||||
this.Y.scaleFun() * scale * scale2,
|
||||
this.Z.scaleFun() * scale * scale2,
|
||||
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)
|
||||
@@ -120,20 +171,46 @@ class Application : Game() {
|
||||
return v.toFloat()
|
||||
}
|
||||
|
||||
val ys = ArrayList<Float>()
|
||||
val ys2 = ArrayList<Float>()
|
||||
|
||||
val halfHeight = oneScreen.height * 0.5
|
||||
|
||||
for (x in 0 until oneScreen.width) {
|
||||
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)
|
||||
var yf = (y * 2.0 / oneScreen.height) % 1.0
|
||||
if (elevation < 0) yf *= 1.0 - pow(-elevation / HALF_PI, 0.333)
|
||||
val gamma = if (y < halfHeight) HALF_PI else 3 * HALF_PI
|
||||
val theta = yf.mapCircle() * HALF_PI
|
||||
|
||||
|
||||
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
|
||||
|
||||
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 +219,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 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))
|
||||
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 turbidityPanel = JPanel()
|
||||
val albedoPanel = JPanel()
|
||||
val elevationPanel = JPanel()
|
||||
val scalefactorPanel = JPanel()
|
||||
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)
|
||||
}
|
||||
|
||||
turbidityControl.preferredSize = Dimension(45, 18)
|
||||
albedoControl.preferredSize = Dimension(45, 18)
|
||||
elevationControl.preferredSize = Dimension(45, 18)
|
||||
scalefactorControl.preferredSize = Dimension(45, 18)
|
||||
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)
|
||||
}
|
||||
|
||||
turbidityPanel.add(JLabel("Turbidity"))
|
||||
turbidityPanel.add(turbidityControl)
|
||||
val cameraPanel = JPanel()
|
||||
val headingPanel = JPanel().also {
|
||||
it.add(JLabel("Heading"))
|
||||
it.add(cameraHeading)
|
||||
cameraPanel.add(it)
|
||||
}
|
||||
|
||||
albedoPanel.add(JLabel("Albedo"))
|
||||
albedoPanel.add(albedoControl)
|
||||
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)
|
||||
}
|
||||
|
||||
elevationPanel.add(JLabel("Elevation"))
|
||||
elevationPanel.add(elevationControl)
|
||||
val mainPanel = JPanel()
|
||||
|
||||
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 +370,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 inputbuf = ByteArray(8)
|
||||
val ret = DoubleArray(entrysize) {
|
||||
val inputbuf = ByteArray(8)
|
||||
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;
|
||||
@@ -240,6 +239,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;
|
||||
@@ -392,6 +392,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 +440,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 +472,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 +482,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 +555,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());
|
||||
}
|
||||
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();
|
||||
screenshotRequested = false;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
shaderPassthruRGBA.bind();
|
||||
shaderPassthruRGBA.setUniformMatrix("u_projTrans", camera.combined);
|
||||
shaderPassthruRGBA.setUniformi("u_texture", 0);
|
||||
postProcessorOutFBO.getColorBufferTexture().bind(0);
|
||||
fullscreenQuad.render(shaderPassthruRGBA, GL20.GL_TRIANGLES);
|
||||
|
||||
// process resize request
|
||||
if (resizeRequested) {
|
||||
@@ -674,6 +607,24 @@ public class App implements ApplicationListener {
|
||||
|
||||
}
|
||||
|
||||
private static void processScreenshotRequest(FrameBuffer fb) {
|
||||
if (screenshotRequested) {
|
||||
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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
public static Texture getCurrentDitherTex() {
|
||||
int hash = 31 + GLOBAL_RENDER_TIMER + 0x165667B1 + GLOBAL_RENDER_TIMER * 0xC2B2AE3D;
|
||||
hash = Integer.rotateLeft(hash, 17) * 0x27D4EB2F;
|
||||
@@ -792,7 +743,7 @@ 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 ||
|
||||
@@ -804,6 +755,11 @@ public class App implements ApplicationListener {
|
||||
scr.getHeight(),
|
||||
false
|
||||
);
|
||||
postProcessorOutFBO2 = new FloatFrameBuffer(
|
||||
scr.getWidth() * 2,
|
||||
scr.getHeight() * 2,
|
||||
false
|
||||
);
|
||||
|
||||
|
||||
if (IS_DEVELOPMENT_BUILD) {
|
||||
@@ -856,6 +812,7 @@ public class App implements ApplicationListener {
|
||||
shaderColLUT.dispose();
|
||||
shaderReflect.dispose();
|
||||
shaderGhastlyWhite.dispose();
|
||||
hq2x.dispose();
|
||||
|
||||
CommonResourcePool.INSTANCE.dispose();
|
||||
fullscreenQuad.dispose();
|
||||
@@ -954,6 +911,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 +1076,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!!
|
||||
}
|
||||
|
||||
fun renamePlayer(name: String) {
|
||||
files.forEach { skimmer ->
|
||||
skimmer.rebuild()
|
||||
skimmer.getFile(SAVEGAMEINFO)!!.let { file ->
|
||||
val json = JsonFetcher.readFromJsonString(ByteArray64Reader(file.bytes, Common.CHARSET))
|
||||
|
||||
json["actorValue"]["hashMap"]["name"]["value"].set(name) // getChild() does NOT work as [] does
|
||||
|
||||
val jsonBytes = json.prettyPrint(JsonWriter.OutputType.json, 0).encodeToByteArray().toByteArray64()
|
||||
val newEntry = DiskEntry(SAVEGAMEINFO, ROOT, skimmer.requestFile(SAVEGAMEINFO)!!.creationDate, App.getTIME_T(), EntryFile(jsonBytes))
|
||||
|
||||
skimmer.appendEntry(newEntry)
|
||||
|
||||
skimmer.setDiskName(name, Common.CHARSET)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun renameWorld(name: String) {
|
||||
files.forEach { skimmer ->
|
||||
skimmer.setDiskName(name, Common.CHARSET)
|
||||
}
|
||||
}
|
||||
|
||||
fun getThumbnail(width: Int, height: Int, shrinkage: Double) = this.loadable().getThumbnail(width, height, shrinkage)
|
||||
}
|
||||
|
||||
class SavegameCollectionPair(player: SavegameCollection?, world: SavegameCollection?) {
|
||||
fun DiskSkimmer.getTgaGz(vid: EntryID, width: Int, height: Int, shrinkage: Double): TextureRegion? {
|
||||
return this.requestFile(vid).let { file ->
|
||||
if (file != null) {
|
||||
val zippedTga = (file.contents as EntryFile).bytes
|
||||
val gzin = GZIPInputStream(ByteArray64InputStream(zippedTga))
|
||||
val tgaFileContents = gzin.readAllBytes(); gzin.close()
|
||||
val pixmap = Pixmap(tgaFileContents, 0, tgaFileContents.size)
|
||||
TextureRegion(Texture(pixmap)).also {
|
||||
App.disposables.add(it.texture)
|
||||
// do cropping and resizing
|
||||
it.setRegion(
|
||||
((pixmap.width - width*2) / shrinkage).roundToInt(),
|
||||
((pixmap.height - height*2) / shrinkage).roundToInt(),
|
||||
(width * shrinkage).roundToInt(),
|
||||
(height * shrinkage).roundToInt()
|
||||
)
|
||||
}
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
fun DiskSkimmer.getTgaGzPixmap(vid: EntryID, width: Int, height: Int, shrinkage: Double): Pixmap? {
|
||||
return this.requestFile(vid).let { file ->
|
||||
if (file != null) {
|
||||
val zippedTga = (file.contents as EntryFile).bytes
|
||||
val gzin = GZIPInputStream(ByteArray64InputStream(zippedTga))
|
||||
val tgaFileContents = gzin.readAllBytes(); gzin.close()
|
||||
val pixmap = Pixmap(tgaFileContents, 0, tgaFileContents.size)
|
||||
return pixmap
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
fun DiskSkimmer.getThumbnail(width: Int, height: Int, shrinkage: Double) =
|
||||
when (this.getSaveKind()) {
|
||||
1 -> this.getTgaGz(PLAYER_SCREENSHOT, width, height, shrinkage)
|
||||
2 -> this.getTgaGz(WORLD_SCREENSHOT, width, height, shrinkage)
|
||||
else -> throw IllegalArgumentException("Unknown save kind: ${this.getSaveKind()}")
|
||||
}
|
||||
fun DiskSkimmer.getThumbnailPixmap(width: Int, height: Int, shrinkage: Double) =
|
||||
when (this.getSaveKind()) {
|
||||
1 -> this.getTgaGzPixmap(PLAYER_SCREENSHOT, width, height, shrinkage)
|
||||
2 -> this.getTgaGzPixmap(WORLD_SCREENSHOT, width, height, shrinkage)
|
||||
else -> throw IllegalArgumentException("Unknown save kind: ${this.getSaveKind()}")
|
||||
}
|
||||
|
||||
private var manualPlayer: DiskSkimmer? = null
|
||||
private var manualWorld: DiskSkimmer? = null
|
||||
private var autoPlayer: DiskSkimmer? = null
|
||||
private var autoWorld: DiskSkimmer? = null
|
||||
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,8 +273,11 @@ 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) {}
|
||||
}
|
||||
@@ -63,7 +63,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 +71,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"
|
||||
@@ -168,11 +168,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])
|
||||
@@ -196,35 +196,35 @@ object TerrarumPostProcessor : Disposable {
|
||||
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()*/
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
99
src/net/torvald/terrarum/clut/GenerateSkyboxTextureAtlas.kt
Normal file
99
src/net/torvald/terrarum/clut/GenerateSkyboxTextureAtlas.kt
Normal file
@@ -0,0 +1,99 @@
|
||||
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
|
||||
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 (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 - 3
|
||||
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, HALF_PI, 0).toFloat(),
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, HALF_PI, 1).toFloat(),
|
||||
ArHosekSkyModel.arhosek_tristim_skymodel_radiance(state, theta, 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)
|
||||
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/mods/basegame/weathers/main_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
|
||||
240
src/net/torvald/terrarum/clut/Skybox.kt
Normal file
240
src/net/torvald/terrarum/clut/Skybox.kt
Normal file
@@ -0,0 +1,240 @@
|
||||
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.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 = 64
|
||||
|
||||
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)
|
||||
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): TextureRegion {
|
||||
val elev = elevationDeg.coerceIn(-elevMax, elevMax).roundToInt().plus(elevMax).roundToInt()
|
||||
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()
|
||||
//printdbg(this, "elev $elevationDeg->$elev; turb $turbidity->$turb; alb $albedo->$alb")
|
||||
return texRegions.get(alb * elevCnt + elev, turb)
|
||||
}
|
||||
|
||||
fun getUV(elevationDeg: Double, turbidity: Double, albedo: Double): Pair<Texture, FloatArray> {
|
||||
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()
|
||||
val region = texStripRegions.get(alb, turb)
|
||||
|
||||
val elev = elevationDeg.coerceIn(-elevMax, elevMax).plus(elevMax).div(elevations.last.toDouble()).div(albedoCnt).times((elevCnt - 1.0) / elevCnt)
|
||||
|
||||
val u = region.u + (0.5f / tex.width) + elev.toFloat() // because of the nature of bilinear interpolation, half pixels from the edges must be discarded
|
||||
|
||||
return tex to floatArrayOf(
|
||||
u,
|
||||
region.v,
|
||||
u,
|
||||
region.v2
|
||||
)
|
||||
}
|
||||
|
||||
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 {
|
||||
val deg1 = (-elevationDeg / elevMax).pow(0.93).times(-elevMax)
|
||||
val elevation1 = -deg1
|
||||
val elevation2 = -deg1 / 28.5
|
||||
val scale = (1f - (1f - 1f / 1.8.pow(elevation1)) * 0.97f).toFloat()
|
||||
val scale2 = (1.0 - (elevation2.pow(E) / E.pow(elevation2))*0.8).toFloat()
|
||||
CIEXYZ(
|
||||
this.X.scaleFun() * scale * scale2,
|
||||
this.Y.scaleFun() * scale * scale2,
|
||||
this.Z.scaleFun() * scale * scale2,
|
||||
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..45) // 1, 1.2, 1.4, 1.6, ..., 10.0
|
||||
val turbDivisor = 5.0
|
||||
val turbiditiesD = turbidities.map { 1.0 + it / turbDivisor }
|
||||
val albedos = arrayOf(0.1, 0.3, 0.5, 0.7, 0.9)
|
||||
val elevCnt = elevations.count()
|
||||
val turbCnt = turbidities.count()
|
||||
val albedoCnt = albedos.size
|
||||
val albedoLow = 0.1
|
||||
val albedoHight = 0.8 // for theoretical "winter wonderland"?
|
||||
val gamma = HALF_PI
|
||||
|
||||
internal fun Double.mapCircle() = sin(HALF_PI * this)
|
||||
|
||||
internal fun initiate() {
|
||||
printdbg(this, "Initialising skybox model")
|
||||
|
||||
gradTexBinLowAlbedo = getTexturmaps(albedoLow)
|
||||
gradTexBinHighAlbedo = getTexturmaps(albedoHight)
|
||||
|
||||
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
|
||||
*/
|
||||
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 - 3
|
||||
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()
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -24,6 +24,7 @@ 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 +443,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 +475,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) {
|
||||
@@ -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)
|
||||
@@ -746,23 +747,23 @@ open class ActorWithBody : Actor {
|
||||
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(),
|
||||
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
|
||||
)
|
||||
|
||||
// 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()
|
||||
hitbox.endY.plus(A_PIXEL).div(TILE_SIZE).floorToInt()
|
||||
else
|
||||
hitbox.startY.minus(A_PIXEL).div(TILE_SIZE).floorInt()
|
||||
hitbox.startY.minus(A_PIXEL).div(TILE_SIZE).floorToInt()
|
||||
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,7 +777,7 @@ 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).floorToInt().coerceIn(2, 16) // adaptive
|
||||
|
||||
|
||||
|
||||
@@ -906,15 +907,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
|
||||
@@ -1136,10 +1137,10 @@ open class ActorWithBody : Actor {
|
||||
val y2 = hitbox.endY - A_PIXEL
|
||||
// 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
|
||||
}
|
||||
@@ -1203,10 +1204,10 @@ open class ActorWithBody : Actor {
|
||||
}
|
||||
else throw IllegalArgumentException()
|
||||
|
||||
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, option == COLLIDING_BOTTOM).first == 2
|
||||
}
|
||||
@@ -1258,27 +1259,27 @@ open class ActorWithBody : Actor {
|
||||
y2 = hitbox.endY - A_PIXEL
|
||||
}
|
||||
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()
|
||||
val pxStart = x1.plus(0.5f).floorToInt()
|
||||
val pxEnd = x2.plus(0.5f).floorToInt()
|
||||
val pyStart = y1.plus(0.5f).floorToInt()
|
||||
val pyEnd = y2.plus(0.5f).floorToInt()
|
||||
|
||||
return isCollidingInternalStairs(pxStart, pyStart, pxEnd, pyEnd, gravitation.y >= 0.0 && option == COLLIDING_BOTTOM || gravitation.y < 0.0 && option == COLLIDING_TOP)
|
||||
}
|
||||
@@ -1890,10 +1891,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,7 +1915,7 @@ 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 = hitbox.endY.plus(1.0).div(TILE_SIZE).floorToInt()
|
||||
|
||||
for (x in hIntTilewiseHitbox.startX.toInt()..hIntTilewiseHitbox.endX.toInt()) {
|
||||
tiles.add(world!!.getTileFromTerrain(x, y))
|
||||
@@ -1930,7 +1931,7 @@ 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()
|
||||
|
||||
for (x in hIntTilewiseHitbox.startX.toInt()..hIntTilewiseHitbox.endX.toInt()) {
|
||||
tileProps.add(BlockCodex[world!!.getTileFromTerrain(x, y)])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -388,7 +389,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 +410,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
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package net.torvald.terrarum.gameworld
|
||||
|
||||
import net.torvald.terrarum.modulebasegame.worldgenerator.TWO_PI
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
|
||||
|
||||
/**
|
||||
* Please also see:
|
||||
@@ -115,11 +119,38 @@ class WorldTime(initTime: Long = 0L) {
|
||||
}
|
||||
|
||||
inline val moonPhase: Double
|
||||
get() = (TIME_T.plus(1700000L) % LUNAR_CYCLE).toDouble() / LUNAR_CYCLE
|
||||
get() = (TIME_T.plus(700000L) % LUNAR_CYCLE).toDouble() / LUNAR_CYCLE
|
||||
|
||||
fun getSolarElevationAt(ordinalDay: Int, second: Int): Double {
|
||||
val TIME_T = DAY_LENGTH * ordinalDay + second
|
||||
|
||||
val x = (TIME_T % YEAR_SECONDS).toDouble() / DAY_LENGTH + 15 // decimal days. One full day = 1.0
|
||||
// 51.56 and 23.44 will make yearly min/max elevation to be 75deg
|
||||
val d = -23.44 * cos(TWO_PI * x / YEAR_DAYS)
|
||||
return -51.56 * cos(TWO_PI * x) + d
|
||||
}
|
||||
|
||||
val solarElevationDeg: Double
|
||||
get() {
|
||||
val x = (TIME_T % YEAR_SECONDS).toDouble() / DAY_LENGTH + 15 // decimal days. One full day = 1.0
|
||||
// 51.56 and 23.44 will make yearly min/max elevation to be 75deg
|
||||
val d = -23.44 * cos(TWO_PI * x / YEAR_DAYS)
|
||||
val p = -51.56 * cos(TWO_PI * x)
|
||||
return d + p
|
||||
}
|
||||
val solarElevationRad: Double
|
||||
get() = Math.toRadians(solarElevationDeg)
|
||||
|
||||
val axialTiltDeg: Double
|
||||
get() {
|
||||
val x = (TIME_T % YEAR_SECONDS).toDouble() / DAY_LENGTH + 15 // decimal days. One full day = 1.0
|
||||
return -23.44 * cos(TWO_PI * x / YEAR_DAYS)
|
||||
}
|
||||
|
||||
@Transient private var realSecAcc: Double = 0.0
|
||||
@Transient private val REAL_SEC_TO_GAME_SECS = 1.0 / GAME_MIN_TO_REAL_SEC // how slow is real-life clock (second-wise) relative to the ingame one
|
||||
|
||||
// NOTE: ingame calendars (the fixture with GUI) should use symbols AND fullnames; the watch already uses shot daynames
|
||||
val DAY_NAMES = arrayOf(//daynames are taken from Nynorsk (å -> o)
|
||||
"Mondag", "Tysdag", "Midtveke" //middle-week
|
||||
, "Torsdag", "Fredag", "Laurdag", "Sundag", "Verddag" //From Norsk word 'verd'
|
||||
@@ -138,19 +169,21 @@ class WorldTime(initTime: Long = 0L) {
|
||||
|
||||
companion object {
|
||||
/** Each day is displayed as 24 hours, but in real-life clock it's 22 mins long */
|
||||
val DAY_LENGTH = 86400 //must be the multiple of 3600
|
||||
const val DAY_LENGTH = 86400 //must be the multiple of 3600
|
||||
|
||||
val HOUR_SEC: Int = 3600
|
||||
val MINUTE_SEC: Int = 60
|
||||
val HOUR_MIN: Int = 60
|
||||
val GAME_MIN_TO_REAL_SEC: Double = 720.0 / 11.0
|
||||
val HOURS_PER_DAY = DAY_LENGTH / HOUR_SEC
|
||||
const val HOUR_SEC: Int = 3600
|
||||
const val MINUTE_SEC: Int = 60
|
||||
const val HOUR_MIN: Int = 60
|
||||
const val GAME_MIN_TO_REAL_SEC: Double = 720.0 / 11.0
|
||||
const val HOURS_PER_DAY = DAY_LENGTH / HOUR_SEC
|
||||
|
||||
val YEAR_DAYS: Int = 120
|
||||
const val YEAR_DAYS: Int = 120
|
||||
|
||||
val MONTH_LENGTH = 30 // ingame calendar specific
|
||||
const val MONTH_LENGTH = 30 // ingame calendar specific
|
||||
|
||||
val EPOCH_YEAR = 125
|
||||
const val EPOCH_YEAR = 125
|
||||
|
||||
val YEAR_SECONDS = DAY_LENGTH * YEAR_DAYS
|
||||
|
||||
/**
|
||||
* Parse a time in the format of "8h30" (hour and minute) or "39882" (second) and return a time of day, in seconds
|
||||
@@ -169,6 +202,7 @@ class WorldTime(initTime: Long = 0L) {
|
||||
|
||||
|
||||
val LUNAR_CYCLE: Int = 29 * DAY_LENGTH + 12 * HOUR_SEC + 44 * MINUTE_SEC + 3 // 29 days, 12 hours, 44 minutes, and 3 seconds in-game calendar
|
||||
const val DIURNAL_MOTION_LENGTH = 86636f
|
||||
}
|
||||
|
||||
fun update(delta: Float) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import com.badlogic.gdx.graphics.Color
|
||||
import com.badlogic.gdx.graphics.g2d.Batch
|
||||
import com.badlogic.gdx.graphics.g2d.BitmapFont
|
||||
import com.badlogic.gdx.graphics.g2d.GlyphLayout
|
||||
import net.torvald.terrarum.round
|
||||
import net.torvald.terrarum.roundToFloat
|
||||
import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack
|
||||
|
||||
/**
|
||||
@@ -41,8 +41,8 @@ object TinyAlphNum : BitmapFont() {
|
||||
colMain = batch.color.cpy()
|
||||
colShadow = colMain.cpy().mul(0.5f, 0.5f, 0.5f, 1f)
|
||||
|
||||
val x = x.round()
|
||||
val y = y.round()
|
||||
val x = x.roundToFloat()
|
||||
val y = y.roundToFloat()
|
||||
|
||||
var charsPrinted = 0
|
||||
text.forEachIndexed { index, c ->
|
||||
@@ -56,13 +56,13 @@ object TinyAlphNum : BitmapFont() {
|
||||
}
|
||||
else if (c in 0.toChar()..255.toChar()) {
|
||||
batch.color = colShadow
|
||||
batch.draw(fontSheet.get(c.toInt() % 16, c.toInt() / 16), x + charsPrinted * W + 1, y)
|
||||
batch.draw(fontSheet.get(c.toInt() % 16, c.toInt() / 16), x + charsPrinted * W, y + 1)
|
||||
batch.draw(fontSheet.get(c.toInt() % 16, c.toInt() / 16), x + charsPrinted * W + 1, y + 1)
|
||||
batch.draw(fontSheet.get(c.code % 16, c.code / 16), x + charsPrinted * W + 1, y)
|
||||
batch.draw(fontSheet.get(c.code % 16, c.code / 16), x + charsPrinted * W, y + 1)
|
||||
batch.draw(fontSheet.get(c.code % 16, c.code / 16), x + charsPrinted * W + 1, y + 1)
|
||||
|
||||
|
||||
batch.color = colMain
|
||||
batch.draw(fontSheet.get(c.toInt() % 16, c.toInt() / 16), x + charsPrinted * W, y)
|
||||
batch.draw(fontSheet.get(c.code % 16, c.code / 16), x + charsPrinted * W, y)
|
||||
|
||||
charsPrinted += 1
|
||||
}
|
||||
@@ -80,8 +80,8 @@ object TinyAlphNum : BitmapFont() {
|
||||
|
||||
|
||||
|
||||
private fun isColourCodeHigh(c: Char) = c.toInt() in 0b110110_1111000000..0b110110_1111111111
|
||||
private fun isColourCodeLow(c: Char) = c.toInt() in 0b110111_0000000000..0b110111_1111111111
|
||||
private fun isColourCodeHigh(c: Char) = c.code in 0b110110_1111000000..0b110110_1111111111
|
||||
private fun isColourCodeLow(c: Char) = c.code in 0b110111_0000000000..0b110111_1111111111
|
||||
|
||||
private fun getColour(charHigh: Char, charLow: Char): Color { // input: 0x10ARGB, out: RGBA8888
|
||||
val codePoint = Character.toCodePoint(charHigh, charLow)
|
||||
|
||||
@@ -55,14 +55,14 @@ class ChunkLoadingLoadScreen(screenToBeLoaded: IngameInstance, private val world
|
||||
|
||||
App.batch.inUse { val it = it as FlippingSpriteBatch
|
||||
it.color = Color.WHITE
|
||||
val previewX = (drawWidth - previewWidth).div(2f).round()
|
||||
val previewY = (App.scr.height - previewHeight.times(1.5f)).div(2f).round()
|
||||
val previewX = (drawWidth - previewWidth).div(2f).roundToFloat()
|
||||
val previewY = (App.scr.height - previewHeight.times(1.5f)).div(2f).roundToFloat()
|
||||
Toolkit.drawBoxBorder(it, previewX.toInt() - 1, previewY.toInt() - 1, previewWidth + 2, previewHeight + 2)
|
||||
it.drawFlipped(previewTexture, previewX, previewY)
|
||||
val text = messages.getHeadElem() ?: ""
|
||||
App.fontGame.draw(it,
|
||||
text,
|
||||
(drawWidth - App.fontGame.getWidth(text)).div(2f).round(),
|
||||
(drawWidth - App.fontGame.getWidth(text)).div(2f).roundToFloat(),
|
||||
previewY + previewHeight + 98 - App.fontGame.lineHeight
|
||||
)
|
||||
}
|
||||
|
||||
@@ -680,7 +680,7 @@ object IngameRenderer : Disposable {
|
||||
* Camera will be moved so that (newX, newY) would be sit on the top-left edge.
|
||||
*/
|
||||
private fun setCameraPosition(newX: Float, newY: Float) {
|
||||
camera.position.set((-newX + App.scr.halfw).round(), (-newY + App.scr.halfh).round(), 0f)
|
||||
camera.position.set((-newX + App.scr.halfw).roundToFloat(), (-newY + App.scr.halfh).roundToFloat(), 0f)
|
||||
camera.update()
|
||||
batch.projectionMatrix = camera.combined
|
||||
}
|
||||
@@ -862,27 +862,27 @@ object IngameRenderer : Disposable {
|
||||
}
|
||||
|
||||
override fun dispose() {
|
||||
try { blurWriteQuad.dispose() } catch (e: UninitializedPropertyAccessException) {}
|
||||
try { blurWriteQuad2.dispose() } catch (e: UninitializedPropertyAccessException) {}
|
||||
//try { blurWriteQuad4.dispose() } catch (e: UninitializedPropertyAccessException) {}
|
||||
if (::blurWriteQuad.isInitialized) blurWriteQuad.tryDispose()
|
||||
if (::blurWriteQuad2.isInitialized) blurWriteQuad2.tryDispose()
|
||||
//if (::blurWriteQuad4.isInitialized) blurWriteQuad4.tryDispose()
|
||||
|
||||
try { fboRGB.dispose() } catch (e: UninitializedPropertyAccessException) {}
|
||||
try { fboA.dispose() } catch (e: UninitializedPropertyAccessException) {}
|
||||
try { fboRGB_lightMixed.dispose() } catch (e: UninitializedPropertyAccessException) {}
|
||||
try { fboA_lightMixed.dispose() } catch (e: UninitializedPropertyAccessException) {}
|
||||
try { fboMixedOut.dispose() } catch (e: UninitializedPropertyAccessException) {}
|
||||
try { lightmapFbo.dispose() } catch (e: UninitializedPropertyAccessException) {}
|
||||
if (::fboRGB.isInitialized) fboRGB.tryDispose()
|
||||
if (::fboA.isInitialized) fboA.tryDispose()
|
||||
if (::fboRGB_lightMixed.isInitialized) fboRGB_lightMixed.tryDispose()
|
||||
if (::fboA_lightMixed.isInitialized) fboA_lightMixed.tryDispose()
|
||||
if (::fboMixedOut.isInitialized) fboMixedOut.tryDispose()
|
||||
if (::lightmapFbo.isInitialized) lightmapFbo.tryDispose()
|
||||
|
||||
try { blurtex0.dispose() } catch (e: GdxRuntimeException) {}
|
||||
blurtex0.tryDispose()
|
||||
|
||||
try { fboBlurHalf.dispose() } catch (e: UninitializedPropertyAccessException) {}
|
||||
//try { fboBlurQuarter.dispose() } catch (e: UninitializedPropertyAccessException) {}
|
||||
if (::fboBlurHalf.isInitialized) fboBlurHalf.tryDispose()
|
||||
//if (::fboBlurQuarter.isInitialized) fboBlurQuarter.tryDispose()
|
||||
|
||||
LightmapRenderer.dispose()
|
||||
BlocksDrawer.dispose()
|
||||
WeatherMixer.dispose()
|
||||
|
||||
try { batch.dispose() } catch (e: UninitializedPropertyAccessException) {}
|
||||
if (::batch.isInitialized) batch.tryDispose()
|
||||
|
||||
|
||||
shaderBlur.dispose()
|
||||
@@ -896,10 +896,7 @@ object IngameRenderer : Disposable {
|
||||
shaderForActors.dispose()
|
||||
shaderDemultiply.dispose()
|
||||
|
||||
try { fboRGBexport.dispose() }
|
||||
catch (e: GdxRuntimeException) {}
|
||||
catch (e: UninitializedPropertyAccessException) {}
|
||||
catch (e: Throwable) { e.printStackTrace(System.out) }
|
||||
if (::fboRGBexport.isInitialized) fboRGBexport.tryDispose()
|
||||
}
|
||||
|
||||
private fun worldCamToRenderPos(): Pair<Float, Float> {
|
||||
|
||||
@@ -56,7 +56,10 @@ import net.torvald.terrarum.worlddrawer.WorldCamera
|
||||
import net.torvald.unicode.EMDASH
|
||||
import net.torvald.util.CircularArray
|
||||
import org.khelekore.prtree.PRTree
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.logging.Level
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
@@ -93,7 +96,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
companion object {
|
||||
/** Sets camera position so that (0,0) would be top-left of the screen, (width, height) be bottom-right. */
|
||||
fun setCameraPosition(batch: SpriteBatch, camera: Camera, newX: Float, newY: Float) {
|
||||
camera.position.set((-newX + App.scr.halfw).round(), (-newY + App.scr.halfh).round(), 0f)
|
||||
camera.position.set((-newX + App.scr.halfw).roundToFloat(), (-newY + App.scr.halfh).roundToFloat(), 0f)
|
||||
camera.update()
|
||||
batch.projectionMatrix = camera.combined
|
||||
}
|
||||
@@ -109,20 +112,20 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
val ACTOR_UPDATE_RANGE = 4096
|
||||
|
||||
fun distToActorSqr(world: GameWorld, a: ActorWithBody, p: ActorWithBody) =
|
||||
minOf(// take min of normal position and wrapped (x < 0) position
|
||||
(a.hitbox.centeredX - p.hitbox.centeredX).sqr() +
|
||||
min(// take min of normal position and wrapped (x < 0) position
|
||||
min((a.hitbox.centeredX - p.hitbox.centeredX).sqr() +
|
||||
(a.hitbox.centeredY - p.hitbox.centeredY).sqr(),
|
||||
((a.hitbox.centeredX + world.width * TILE_SIZE) - p.hitbox.centeredX).sqr() +
|
||||
(a.hitbox.centeredY - p.hitbox.centeredY).sqr(),
|
||||
(a.hitbox.centeredY - p.hitbox.centeredY).sqr()),
|
||||
((a.hitbox.centeredX - world.width * TILE_SIZE) - p.hitbox.centeredX).sqr() +
|
||||
(a.hitbox.centeredY - p.hitbox.centeredY).sqr()
|
||||
)
|
||||
fun distToCameraSqr(world: GameWorld, a: ActorWithBody) =
|
||||
minOf(
|
||||
(a.hitbox.centeredX - WorldCamera.xCentre).sqr() +
|
||||
min(
|
||||
min((a.hitbox.centeredX - WorldCamera.xCentre).sqr() +
|
||||
(a.hitbox.centeredY - WorldCamera.yCentre).sqr(),
|
||||
((a.hitbox.centeredX + world.width * TILE_SIZE) - WorldCamera.xCentre).sqr() +
|
||||
(a.hitbox.centeredY - WorldCamera.yCentre).sqr(),
|
||||
(a.hitbox.centeredY - WorldCamera.yCentre).sqr()),
|
||||
((a.hitbox.centeredX - world.width * TILE_SIZE) - WorldCamera.xCentre).sqr() +
|
||||
(a.hitbox.centeredY - WorldCamera.yCentre).sqr()
|
||||
)
|
||||
@@ -399,15 +402,11 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
worldDisk = VDUtil.createNewDisk(
|
||||
1L shl 60,
|
||||
savegameNickname,
|
||||
worldName,
|
||||
Common.CHARSET
|
||||
)
|
||||
|
||||
playerDisk = VDUtil.createNewDisk(
|
||||
1L shl 60,
|
||||
actorGamer.actorValue.getAsString(AVKey.NAME) ?: "",
|
||||
Common.CHARSET
|
||||
)
|
||||
playerDisk = VDUtil.readDiskArchive(App.savegamePlayers[actorGamer.uuid]!!.loadable().diskFile, Level.INFO)
|
||||
|
||||
// go to spawn position
|
||||
printdbg(this, "World Spawn position: (${world.spawnX}, ${world.spawnY})")
|
||||
@@ -434,6 +433,9 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
makeSavegameBackupCopy(getWorldSaveFiledesc(worldSavefileName)) // don't put it on the postInit() or render(); must be called using callback
|
||||
uiAutosaveNotifier.setAsClose()
|
||||
|
||||
App.savegameWorlds[world.worldIndex] = SavegameCollection.collectFromBaseFilename(File(worldsDir), worldSavefileName)
|
||||
App.savegameWorldsName[world.worldIndex] = worldName
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -475,7 +477,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
|
||||
historicalFigureIDBucket = ArrayList<Int>()
|
||||
|
||||
savegameNickname = worldParams.savegameName
|
||||
worldName = worldParams.savegameName
|
||||
|
||||
|
||||
world.worldCreator = UUID.fromString(player.uuid.toString())
|
||||
@@ -488,6 +490,8 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
forceAddActor(player)
|
||||
|
||||
WeatherMixer.internalReset()
|
||||
|
||||
UILoadGovernor.worldUUID = world.worldIndex
|
||||
}
|
||||
|
||||
KeyToggler.forceSet(Input.Keys.Q, false)
|
||||
@@ -1032,10 +1036,10 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
} }
|
||||
|
||||
private fun fillUpWiresBuffer() {
|
||||
val for_y_start = (WorldCamera.y.toFloat() / TILE_SIZE).floorInt() - LIGHTMAP_OVERRENDER
|
||||
val for_y_start = (WorldCamera.y.toFloat() / TILE_SIZE).floorToInt() - LIGHTMAP_OVERRENDER
|
||||
val for_y_end = for_y_start + BlocksDrawer.tilesInVertical + 2*LIGHTMAP_OVERRENDER
|
||||
|
||||
val for_x_start = (WorldCamera.x.toFloat() / TILE_SIZE).floorInt() - LIGHTMAP_OVERRENDER
|
||||
val for_x_start = (WorldCamera.x.toFloat() / TILE_SIZE).floorToInt() - LIGHTMAP_OVERRENDER
|
||||
val for_x_end = for_x_start + BlocksDrawer.tilesInHorizontal + 2*LIGHTMAP_OVERRENDER
|
||||
|
||||
var wiringCounter = 0
|
||||
@@ -1418,7 +1422,7 @@ open class TerrarumIngame(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
// }
|
||||
// else, punch a block
|
||||
else if (canAttackOrDig) {
|
||||
val punchBlockSize = punchSize.div(TILE_SIZED).floorInt()
|
||||
val punchBlockSize = punchSize.div(TILE_SIZED).floorToInt()
|
||||
if (punchBlockSize > 0) {
|
||||
PickaxeCore.startPrimaryUse(actor, delta, null, Terrarum.mouseTileX, Terrarum.mouseTileY, 1.0 / punchBlockSize, punchBlockSize, punchBlockSize)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import net.torvald.terrarum.gameworld.GameWorld
|
||||
import net.torvald.terrarum.gameworld.WorldTime
|
||||
import net.torvald.terrarum.gameworld.fmod
|
||||
import net.torvald.terrarum.langpack.Lang
|
||||
import net.torvald.terrarum.clut.Skybox
|
||||
import net.torvald.terrarum.modulebasegame.ui.UILoadGovernor
|
||||
import net.torvald.terrarum.modulebasegame.ui.UIRemoCon
|
||||
import net.torvald.terrarum.modulebasegame.ui.UITitleRemoConYaml
|
||||
@@ -74,7 +75,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
val ww = TILE_SIZEF * demoWorld.width
|
||||
val x = px % ww
|
||||
|
||||
val indexThis = ((x / ww * cameraNodes.size).floorInt())
|
||||
val indexThis = ((x / ww * cameraNodes.size).floorToInt())
|
||||
val xwstart: Double = indexThis.toDouble() / cameraNodes.size * ww
|
||||
val xwend: Double = ((indexThis + 1).toDouble() / cameraNodes.size) * ww
|
||||
val xw: Double = xwend - xwstart
|
||||
@@ -175,13 +176,13 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
|
||||
|
||||
// set time to summer
|
||||
// set initial time to summer
|
||||
demoWorld.worldTime.addTime(WorldTime.DAY_LENGTH * 32)
|
||||
|
||||
// construct camera nodes
|
||||
val nodeCount = demoWorld.width / cameraNodeWidth
|
||||
cameraNodes = kotlin.FloatArray(nodeCount) {
|
||||
val tileXPos = (demoWorld.width.toFloat() * it / nodeCount).floorInt()
|
||||
val tileXPos = (demoWorld.width.toFloat() * it / nodeCount).floorToInt()
|
||||
var travelDownCounter = 0
|
||||
while (travelDownCounter < demoWorld.height &&
|
||||
!BlockCodex[demoWorld.getTileFromTerrain(tileXPos, travelDownCounter)].isSolid
|
||||
@@ -193,13 +194,14 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
}
|
||||
// apply gaussian blur to the camera nodes
|
||||
for (i in cameraNodes.indices) {
|
||||
val offM2 = cameraNodes[(i-2) fmod cameraNodes.size] * 1f
|
||||
val offM1 = cameraNodes[(i-1) fmod cameraNodes.size] * 4f
|
||||
val off0 = cameraNodes[i] * 6f
|
||||
val off1 = cameraNodes[(i+1) fmod cameraNodes.size] * 4f
|
||||
val off2 = cameraNodes[(i+2) fmod cameraNodes.size] * 1f
|
||||
// val offM2 = cameraNodes[(i-2) fmod cameraNodes.size] * 1f
|
||||
val offM1 = cameraNodes[(i-1) fmod cameraNodes.size] * 1f
|
||||
val off0 = cameraNodes[i] * 2f
|
||||
val off1 = cameraNodes[(i+1) fmod cameraNodes.size] * 1f
|
||||
// val off2 = cameraNodes[(i+2) fmod cameraNodes.size] * 1f
|
||||
|
||||
cameraNodes[i] = (offM2 + offM1 + off0 + off1 + off2) / 16f
|
||||
// cameraNodes[i] = (offM2 + offM1 + off0 + off1 + off2) / 16f
|
||||
cameraNodes[i] = (offM1 + off0 + off1) / 4f
|
||||
}
|
||||
|
||||
|
||||
@@ -239,6 +241,8 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
uiContainer.add(uiRemoCon)
|
||||
|
||||
CommandDict // invoke
|
||||
Skybox.loadlut() // invoke
|
||||
// Skybox.initiate() // invoke the lengthy calculation
|
||||
// TODO add console here
|
||||
|
||||
|
||||
@@ -283,9 +287,9 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
||||
private val updateScreen = { delta: Float ->
|
||||
// TODO: desynched weather and time-of-day change
|
||||
|
||||
val forcedTime = 39693
|
||||
// demoWorld.globalLight = WeatherMixer.globalLightNow
|
||||
demoWorld.globalLight = WeatherMixer.getGlobalLightOfTime(demoWorld, forcedTime)
|
||||
val forcedTime = 32880 // 9h08m
|
||||
demoWorld.globalLight = WeatherMixer.globalLightNow
|
||||
// demoWorld.globalLight = WeatherMixer.getGlobalLightOfTimeOfNoon()
|
||||
demoWorld.updateWorldTime(delta)
|
||||
// WeatherMixer.update(delta, cameraPlayer, demoWorld)
|
||||
WeatherMixer.forceTimeAt = forcedTime
|
||||
|
||||
@@ -70,14 +70,14 @@ class WorldgenLoadScreen(screenToBeLoaded: IngameInstance, private val worldwidt
|
||||
|
||||
App.batch.inUse { val it = it as FlippingSpriteBatch
|
||||
it.color = Color.WHITE
|
||||
val previewX = (drawWidth - previewWidth).div(2f).round()
|
||||
val previewY = (App.scr.height - previewHeight.times(1.5f)).div(2f).round()
|
||||
val previewX = (drawWidth - previewWidth).div(2f).roundToFloat()
|
||||
val previewY = (App.scr.height - previewHeight.times(1.5f)).div(2f).roundToFloat()
|
||||
Toolkit.drawBoxBorder(it, previewX.toInt()-1, previewY.toInt()-1, previewWidth+2, previewHeight+2)
|
||||
it.drawFlipped(previewTexture, previewX, previewY)
|
||||
val text = messages.getHeadElem() ?: ""
|
||||
App.fontGame.draw(it,
|
||||
text,
|
||||
(drawWidth - App.fontGame.getWidth(text)).div(2f).round(),
|
||||
(drawWidth - App.fontGame.getWidth(text)).div(2f).roundToFloat(),
|
||||
previewY + previewHeight + 98 - App.fontGame.lineHeight
|
||||
)
|
||||
}
|
||||
|
||||
48
src/net/torvald/terrarum/modulebasegame/console/SetSol.kt
Normal file
48
src/net/torvald/terrarum/modulebasegame/console/SetSol.kt
Normal file
@@ -0,0 +1,48 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.reflection.extortField
|
||||
import net.torvald.terrarum.INGAME
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.weather.WeatherMixer
|
||||
import net.torvald.terrarum.worlddrawer.LightmapRenderer
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-07-25.
|
||||
*/
|
||||
internal object SetSol : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 2) {
|
||||
if (args[1].trim().lowercase() == "none") {
|
||||
WeatherMixer.forceSolarElev = null
|
||||
}
|
||||
else {
|
||||
try {
|
||||
val solarAngle = args[1].toDouble().coerceIn(-75.0..75.0)
|
||||
WeatherMixer.forceSolarElev = solarAngle
|
||||
LightmapRenderer.recalculate(
|
||||
INGAME.extortField<ArrayList<ActorWithBody>>("visibleActorsRenderBehind")!! +
|
||||
INGAME.extortField<ArrayList<ActorWithBody>>("visibleActorsRenderMiddle")!! +
|
||||
INGAME.extortField<ArrayList<ActorWithBody>>("visibleActorsRenderMidTop")!! +
|
||||
INGAME.extortField<ArrayList<ActorWithBody>>("visibleActorsRenderFront")!! +
|
||||
INGAME.extortField<ArrayList<ActorWithBody>>("visibleActorsRenderOverlay")!!
|
||||
)
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
Echo("Wrong number input.")
|
||||
}
|
||||
catch (e1: IllegalArgumentException) {
|
||||
Echo("Range: -75.0-75.0")
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("usage: setsol <-75.0..75.0 or 'none'>")
|
||||
}
|
||||
}
|
||||
37
src/net/torvald/terrarum/modulebasegame/console/SetTurb.kt
Normal file
37
src/net/torvald/terrarum/modulebasegame/console/SetTurb.kt
Normal file
@@ -0,0 +1,37 @@
|
||||
package net.torvald.terrarum.modulebasegame.console
|
||||
|
||||
import net.torvald.terrarum.console.ConsoleCommand
|
||||
import net.torvald.terrarum.console.Echo
|
||||
import net.torvald.terrarum.weather.WeatherMixer
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 2023-07-25.
|
||||
*/
|
||||
object SetTurb : ConsoleCommand {
|
||||
override fun execute(args: Array<String>) {
|
||||
if (args.size == 2) {
|
||||
if (args[1].trim().lowercase() == "none") {
|
||||
WeatherMixer.forceTurbidity = null
|
||||
}
|
||||
else {
|
||||
try {
|
||||
val turbidity = args[1].toDouble().coerceIn(1.0..10.0)
|
||||
WeatherMixer.forceTurbidity = turbidity
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
Echo("Wrong number input.")
|
||||
}
|
||||
catch (e1: IllegalArgumentException) {
|
||||
Echo("Range: 1.0-10.0")
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
printUsage()
|
||||
}
|
||||
}
|
||||
|
||||
override fun printUsage() {
|
||||
Echo("usage: setturb <1.0..10.0 or 'none'>")
|
||||
}
|
||||
}
|
||||
@@ -292,8 +292,8 @@ open class ActorHumanoid : ActorWithBody, Controllable, Pocketed, Factionable, L
|
||||
val occupyingTileHasPlatform = bodyTiles.filterNotNull().any { it.isPlatform }
|
||||
val feetTileHasPlatform = feetTiles.filterNotNull().any { it.isPlatform }
|
||||
val feetTileIsAllPlatform = feetTiles.filterNotNull().all { it.isPlatform }
|
||||
if (isDownDown && feetTileIsAllPlatform && (controllerV?.y ?: 0.0) >= 0.0 ||
|
||||
occupyingTileHasPlatform && !feetTileHasPlatform) { // FIXME this does not account for reverse gravity
|
||||
if (isDownDown && feetTileIsAllPlatform && (controllerV?.y ?: 0.0) >= 0.0) {// ||
|
||||
// occupyingTileHasPlatform && !feetTileHasPlatform) { // FIXME commenting this out enables platform-ladder but falldown gets slowed down if the body passes thru the platform but I think this behav might be beneficial for player?
|
||||
downDownVirtually = true
|
||||
}
|
||||
if (downDownVirtually && !occupyingTileHasPlatform && !feetTileIsAllPlatform) {
|
||||
@@ -545,7 +545,7 @@ open class ActorHumanoid : ActorWithBody, Controllable, Pocketed, Factionable, L
|
||||
|
||||
if (hasPlatformOnTheFeet) {
|
||||
// equation copied verbatim from the ActorWthBody.forEachFeetTile
|
||||
val y = hitbox.endY.plus(1.0).div(TerrarumAppConfiguration.TILE_SIZE).floorInt()
|
||||
val y = hitbox.endY.plus(1.0).div(TerrarumAppConfiguration.TILE_SIZE).floorToInt()
|
||||
var wxStart = hIntTilewiseHitbox.startX.toInt()
|
||||
var wxEnd = wxStart
|
||||
// scan to the left
|
||||
|
||||
@@ -69,8 +69,8 @@ internal class FixtureTapestry : FixtureBase {
|
||||
Pixmap(ModMgr.getGdxFilesFromEveryMod("tapestries/common/canvas.tga").last().second)
|
||||
} as Pixmap
|
||||
|
||||
tilewiseHitboxWidth = pixmap.width.div(TILE_SIZEF).ceilInt()
|
||||
tilewiseHitboxHeight = pixmap.height.div(TILE_SIZEF).ceilInt()
|
||||
tilewiseHitboxWidth = pixmap.width.div(TILE_SIZEF).ceilToInt()
|
||||
tilewiseHitboxHeight = pixmap.height.div(TILE_SIZEF).ceilToInt()
|
||||
|
||||
// blend canvas texture
|
||||
for (y in 0 until pixmap.height) { for (x in 0 until pixmap.width) {
|
||||
|
||||
@@ -77,11 +77,11 @@ class FixtureWorldPortal : Electric {
|
||||
// load existing
|
||||
val jobAfterSave: () -> Unit
|
||||
if (it.worldDiskToLoad != null) {
|
||||
UILoadGovernor.worldDisk = it.worldDiskToLoad
|
||||
UILoadGovernor.playerDisk = App.savegamePlayers[player.uuid]!!.files[0]
|
||||
jobAfterSave = {
|
||||
UILoadGovernor.playerDisk!!.rebuild()
|
||||
LoadSavegame(UILoadGovernor.playerDisk!!, UILoadGovernor.worldDisk!!)
|
||||
LoadSavegame(
|
||||
App.savegamePlayers[player.uuid]!!.files[0],
|
||||
it.worldDiskToLoad
|
||||
)
|
||||
}
|
||||
}
|
||||
// create new
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package net.torvald.terrarum.modulebasegame.gameactors.physicssolver
|
||||
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.abs
|
||||
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
||||
import net.torvald.terrarum.gameactors.ActorWithBody
|
||||
import net.torvald.terrarum.sqr
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@@ -202,9 +204,6 @@ object CollisionSolver {
|
||||
return (t_ax.sqr() + t_ay.sqr()) < actor_dist_t_sqr
|
||||
}
|
||||
|
||||
fun Double.abs() = if (this < 0) -this else this
|
||||
fun Double.sqr() = this * this
|
||||
|
||||
data class CollisionMarkings(
|
||||
val pos: Double,
|
||||
val kind: Int,
|
||||
|
||||
@@ -5,6 +5,7 @@ import net.torvald.random.HQRNG
|
||||
import net.torvald.terrarum.gameitems.GameItem
|
||||
import net.torvald.terrarum.gameitems.ItemID
|
||||
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
|
||||
import kotlin.math.max
|
||||
import kotlin.math.pow
|
||||
|
||||
/**
|
||||
@@ -21,7 +22,7 @@ object WeaponMeleeCore {
|
||||
private fun getAttackMomentum(weapon: WeaponMeleeBase, actor: ActorHumanoid) =
|
||||
weapon.mass * weapon.material.density * weapon.velocityMod * actor.scale.pow(SQRT2) // TODO multiply racial strength from RaceCodex
|
||||
fun getAttackPower(weapon: WeaponMeleeBase, actor: ActorHumanoid, actee: ActorHumanoid) =
|
||||
getAttackMomentum(weapon, actor) * randomise() * maxOf(1.0, (actee.hitbox.endY - actor.hitbox.startY) / actee.hitbox.height)
|
||||
getAttackMomentum(weapon, actor) * randomise() * max(1.0, (actee.hitbox.endY - actor.hitbox.startY) / actee.hitbox.height)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package net.torvald.terrarum.modulebasegame.magiccontroller
|
||||
|
||||
import net.torvald.terrarum.gameactors.AVKey
|
||||
import net.torvald.terrarum.gameactors.Actor
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* "Data Type" describing magical force
|
||||
@@ -33,13 +34,13 @@ class TheMagicLanguage(vm: TheMagicMachine) {
|
||||
if (power >= 0) {
|
||||
// pour out positive power without inversion; result is positive power
|
||||
if (value >= 0) {
|
||||
val value = minOf(power, value)
|
||||
val value = min(power, value)
|
||||
other.pourIn(value)
|
||||
power -= value
|
||||
}
|
||||
// pour out positive power with inversion; result is negative power
|
||||
else {
|
||||
val value = minOf(-power, value)
|
||||
val value = min(-power, value)
|
||||
other.pourIn(value)
|
||||
power += value
|
||||
}
|
||||
@@ -47,12 +48,12 @@ class TheMagicLanguage(vm: TheMagicMachine) {
|
||||
else {
|
||||
// pour out negative power without inversion; result is negative power
|
||||
if (value < 0) {
|
||||
val value = minOf(power, value)
|
||||
val value = min(power, value)
|
||||
other.pourIn(-value)
|
||||
}
|
||||
// pour out negative power with inversion; result is positive power
|
||||
else {
|
||||
val value = minOf(-power, value)
|
||||
val value = min(-power, value)
|
||||
other.pourIn(-value)
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user