-Subproject commit 45b691209c95e5a758536a32564c329683550dca
+Subproject commit 97963be1d8fbc53dce1b116f1d62340dee83383c
--- /dev/null
+# Goxel 0.10.6
+# One line per voxel
+# X Y Z RRGGBB
+0 -1 9 a5a5a5
+0 -1 10 a0a0a0
+0 0 0 503612
+0 0 1 503612
+0 0 2 584120
+0 0 3 43351e
+0 0 4 503612
+0 0 5 503612
+0 0 6 4a3312
+0 0 7 5c421a
+0 3 7 a0a0a0
+0 4 7 9e9e9e
+0 0 8 5a380e
+0 2 8 9e9e9e
+0 3 8 a1a1a1
+0 4 8 a1a1a1
+0 0 9 a1a1a1
+1 0 9 a0a0a0
+0 1 9 9e9e9e
+0 2 9 9e9e9e
+0 3 9 a1a1a1
+0 4 9 9e9e9e
+0 0 10 989898
+1 0 10 a0a0a0
+0 1 10 a0a0a0
+0 2 10 9e9e9e
+0 3 10 9e9e9e
+0 4 10 9e9e9e
+0 0 11 5c421a
+0 2 11 a0a0a0
+0 3 11 9e9e9e
+0 4 11 a1a1a1
+0 3 12 9e9e9e
+0 4 12 9e9e9e
+-1 0 9 a0a0a0
+-1 0 10 a0a0a0
--- /dev/null
+# Goxel 0.10.6
+# One line per voxel
+# X Y Z RRGGBB
+0 -4 7 a0a0a0
+0 -4 8 a0a0a0
+0 -3 8 999999
+0 -3 9 a0a0a0
+0 -2 9 a0a0a0
+0 -1 9 8b8b8b
+0 -2 10 a0a0a0
+0 -1 10 a9a9a9
+0 0 0 503612
+0 0 1 503612
+0 0 2 584120
+0 0 3 43351e
+0 0 4 503612
+0 0 5 503612
+0 0 6 4a3312
+0 0 7 5c421a
+0 4 7 999999
+0 0 8 5a380e
+0 3 8 999999
+0 4 8 a0a0a0
+0 0 9 a0a0a0
+0 1 9 a9a9a9
+0 2 9 a0a0a0
+0 3 9 a0a0a0
+0 0 10 a9a9a9
+0 1 10 8b8b8b
+0 2 10 a0a0a0
+0 0 11 a0a0a0
--- /dev/null
+# Goxel 0.10.6
+# One line per voxel
+# X Y Z RRGGBB
+0 0 0 920088
+1 0 0 920088
+2 0 0 920088
+3 0 0 920088
+4 0 0 920088
+5 0 0 920088
+6 0 0 920088
+7 0 0 920088
+8 0 0 920088
+0 1 0 920088
+1 1 0 c400bc
+2 1 0 c400bc
+3 1 0 c400bc
+4 1 0 c400bc
+5 1 0 c400bc
+6 1 0 c400bc
+7 1 0 c400bc
+8 1 0 920088
+0 2 0 920088
+1 2 0 c400bc
+2 2 0 c400bc
+3 2 0 cdd300
+4 2 0 cdd300
+5 2 0 cdd300
+6 2 0 c400bc
+7 2 0 c400bc
+8 2 0 920088
+0 3 0 920088
+1 3 0 c400bc
+2 3 0 cdd300
+3 3 0 c400bc
+4 3 0 c400bc
+5 3 0 c400bc
+6 3 0 cdd300
+7 3 0 c400bc
+8 3 0 920088
+0 4 0 920088
+1 4 0 c400bc
+2 4 0 c400bc
+3 4 0 c400bc
+4 4 0 cdd300
+5 4 0 cdd300
+6 4 0 c400bc
+7 4 0 c400bc
+8 4 0 920088
+0 5 0 920088
+1 5 0 c400bc
+2 5 0 c400bc
+3 5 0 c400bc
+4 5 0 c400bc
+5 5 0 c400bc
+6 5 0 c400bc
+7 5 0 c400bc
+8 5 0 920088
+0 6 0 920088
+1 6 0 c400bc
+2 6 0 c400bc
+3 6 0 c400bc
+4 6 0 cdd300
+5 6 0 c400bc
+6 6 0 c400bc
+7 6 0 c400bc
+8 6 0 920088
+0 7 0 920088
+1 7 0 c400bc
+2 7 0 c400bc
+3 7 0 c400bc
+4 7 0 c400bc
+5 7 0 c400bc
+6 7 0 c400bc
+7 7 0 c400bc
+8 7 0 920088
+0 8 0 920088
+1 8 0 920088
+2 8 0 920088
+3 8 0 920088
+4 8 0 920088
+5 8 0 920088
+6 8 0 920088
+7 8 0 920088
+8 8 0 920088
+0 0 1 920088
+1 0 1 c400bc
+2 0 1 c400bc
+3 0 1 c400bc
+4 0 1 c400bc
+5 0 1 c400bc
+6 0 1 c400bc
+7 0 1 c400bc
+8 0 1 920088
+0 1 1 c400bc
+1 1 1 ffffff
+2 1 1 ffffff
+3 1 1 ffffff
+4 1 1 ffffff
+5 1 1 ffffff
+6 1 1 ffffff
+7 1 1 ffffff
+8 1 1 c400bc
+0 2 1 c400bc
+1 2 1 ffffff
+2 2 1 ffffff
+3 2 1 ffffff
+4 2 1 ffffff
+5 2 1 ffffff
+6 2 1 ffffff
+7 2 1 ffffff
+8 2 1 c400bc
+0 3 1 c400bc
+1 3 1 ffffff
+2 3 1 ffffff
+3 3 1 ffffff
+4 3 1 ffffff
+5 3 1 ffffff
+6 3 1 ffffff
+7 3 1 ffffff
+8 3 1 c400bc
+0 4 1 c400bc
+1 4 1 ffffff
+2 4 1 ffffff
+3 4 1 ffffff
+4 4 1 ffffff
+5 4 1 ffffff
+6 4 1 ffffff
+7 4 1 ffffff
+8 4 1 c400bc
+0 5 1 c400bc
+1 5 1 ffffff
+2 5 1 ffffff
+3 5 1 ffffff
+4 5 1 ffffff
+5 5 1 ffffff
+6 5 1 ffffff
+7 5 1 ffffff
+8 5 1 c400bc
+0 6 1 c400bc
+1 6 1 ffffff
+2 6 1 ffffff
+3 6 1 ffffff
+4 6 1 ffffff
+5 6 1 ffffff
+6 6 1 ffffff
+7 6 1 ffffff
+8 6 1 c400bc
+0 7 1 c400bc
+1 7 1 ffffff
+2 7 1 ffffff
+3 7 1 ffffff
+4 7 1 ffffff
+5 7 1 ffffff
+6 7 1 ffffff
+7 7 1 ffffff
+8 7 1 c400bc
+0 8 1 920088
+1 8 1 c400bc
+2 8 1 c400bc
+3 8 1 c400bc
+4 8 1 c400bc
+5 8 1 c400bc
+6 8 1 c400bc
+7 8 1 c400bc
+8 8 1 920088
+0 0 2 920088
+1 0 2 c400bc
+2 0 2 c400bc
+3 0 2 c400bc
+4 0 2 cdd300
+5 0 2 c400bc
+6 0 2 c400bc
+7 0 2 c400bc
+8 0 2 920088
+0 1 2 c400bc
+1 1 2 ffffff
+2 1 2 ffffff
+3 1 2 ffffff
+4 1 2 ffffff
+5 1 2 ffffff
+6 1 2 ffffff
+7 1 2 ffffff
+8 1 2 c400bc
+0 2 2 c400bc
+1 2 2 ffffff
+2 2 2 ffffff
+3 2 2 ffffff
+4 2 2 ffffff
+5 2 2 ffffff
+6 2 2 ffffff
+7 2 2 ffffff
+8 2 2 c400bc
+0 3 2 c400bc
+1 3 2 ffffff
+2 3 2 ffffff
+3 3 2 ffffff
+4 3 2 ffffff
+5 3 2 ffffff
+6 3 2 ffffff
+7 3 2 ffffff
+8 3 2 c400bc
+0 4 2 cdd300
+1 4 2 ffffff
+2 4 2 ffffff
+3 4 2 ffffff
+4 4 2 ffffff
+5 4 2 ffffff
+6 4 2 ffffff
+7 4 2 ffffff
+8 4 2 cdd300
+0 5 2 c400bc
+1 5 2 ffffff
+2 5 2 ffffff
+3 5 2 ffffff
+4 5 2 ffffff
+5 5 2 ffffff
+6 5 2 ffffff
+7 5 2 ffffff
+8 5 2 c400bc
+0 6 2 c400bc
+1 6 2 ffffff
+2 6 2 ffffff
+3 6 2 ffffff
+4 6 2 ffffff
+5 6 2 ffffff
+6 6 2 ffffff
+7 6 2 ffffff
+8 6 2 c400bc
+0 7 2 c400bc
+1 7 2 ffffff
+2 7 2 ffffff
+3 7 2 ffffff
+4 7 2 ffffff
+5 7 2 ffffff
+6 7 2 ffffff
+7 7 2 ffffff
+8 7 2 c400bc
+0 8 2 920088
+1 8 2 c400bc
+2 8 2 c400bc
+3 8 2 c400bc
+4 8 2 cdd300
+5 8 2 c400bc
+6 8 2 c400bc
+7 8 2 c400bc
+8 8 2 920088
+0 0 3 920088
+1 0 3 c400bc
+2 0 3 c400bc
+3 0 3 c400bc
+4 0 3 c400bc
+5 0 3 c400bc
+6 0 3 c400bc
+7 0 3 c400bc
+8 0 3 920088
+0 1 3 c400bc
+1 1 3 ffffff
+2 1 3 c400bc
+3 1 3 c400bc
+4 1 3 ffffff
+5 1 3 ffffff
+6 1 3 ffffff
+7 1 3 ffffff
+8 1 3 c400bc
+0 2 3 c400bc
+1 2 3 c400bc
+2 2 3 c400bc
+3 2 3 ffffff
+4 2 3 ffffff
+5 2 3 ffffff
+6 2 3 ffffff
+7 2 3 ffffff
+8 2 3 c400bc
+0 3 3 c400bc
+1 3 3 ffffff
+2 3 3 ffffff
+3 3 3 ffffff
+4 3 3 ffffff
+5 3 3 ffffff
+6 3 3 ffffff
+7 3 3 ffffff
+8 3 3 c400bc
+0 4 3 c400bc
+1 4 3 ffffff
+2 4 3 ffffff
+3 4 3 ffffff
+4 4 3 ffffff
+5 4 3 ffffff
+6 4 3 ffffff
+7 4 3 ffffff
+8 4 3 c400bc
+0 5 3 c400bc
+1 5 3 ffffff
+2 5 3 ffffff
+3 5 3 ffffff
+4 5 3 ffffff
+5 5 3 ffffff
+6 5 3 ffffff
+7 5 3 ffffff
+8 5 3 c400bc
+0 6 3 c400bc
+1 6 3 ffffff
+2 6 3 ffffff
+3 6 3 ffffff
+4 6 3 ffffff
+5 6 3 ffffff
+6 6 3 ffffff
+7 6 3 ffffff
+8 6 3 c400bc
+0 7 3 c400bc
+1 7 3 ffffff
+2 7 3 ffffff
+3 7 3 ffffff
+4 7 3 ffffff
+5 7 3 ffffff
+6 7 3 ffffff
+7 7 3 ffffff
+8 7 3 c400bc
+0 8 3 920088
+1 8 3 c400bc
+2 8 3 c400bc
+3 8 3 c400bc
+4 8 3 c400bc
+5 8 3 c400bc
+6 8 3 c400bc
+7 8 3 c400bc
+8 8 3 920088
+0 0 4 920088
+1 0 4 c400bc
+2 0 4 c400bc
+3 0 4 c400bc
+4 0 4 cdd300
+5 0 4 cdd300
+6 0 4 c400bc
+7 0 4 c400bc
+8 0 4 920088
+0 1 4 c400bc
+1 1 4 c400bc
+2 1 4 c400bc
+3 1 4 ffffff
+4 1 4 ffffff
+5 1 4 ffffff
+6 1 4 ffffff
+7 1 4 ffffff
+8 1 4 c400bc
+0 2 4 c400bc
+1 2 4 c400bc
+2 2 4 ffffff
+3 2 4 ffffff
+4 2 4 ffffff
+5 2 4 ffffff
+6 2 4 ffffff
+7 2 4 ffffff
+8 2 4 c400bc
+0 3 4 cdd300
+1 3 4 ffffff
+2 3 4 ffffff
+3 3 4 ffffff
+4 3 4 ffffff
+5 3 4 ffffff
+6 3 4 ffffff
+7 3 4 ffffff
+8 3 4 c400bc
+0 4 4 cdd300
+1 4 4 ffffff
+2 4 4 ffffff
+3 4 4 ffffff
+4 4 4 ffffff
+5 4 4 ffffff
+6 4 4 ffffff
+7 4 4 ffffff
+8 4 4 cdd300
+0 5 4 c400bc
+1 5 4 ffffff
+2 5 4 ffffff
+3 5 4 ffffff
+4 5 4 ffffff
+5 5 4 ffffff
+6 5 4 ffffff
+7 5 4 ffffff
+8 5 4 cdd300
+0 6 4 c400bc
+1 6 4 ffffff
+2 6 4 ffffff
+3 6 4 ffffff
+4 6 4 ffffff
+5 6 4 ffffff
+6 6 4 ffffff
+7 6 4 ffffff
+8 6 4 c400bc
+0 7 4 c400bc
+1 7 4 ffffff
+2 7 4 ffffff
+3 7 4 ffffff
+4 7 4 ffffff
+5 7 4 ffffff
+6 7 4 ffffff
+7 7 4 ffffff
+8 7 4 c400bc
+0 8 4 920088
+1 8 4 c400bc
+2 8 4 c400bc
+3 8 4 cdd300
+4 8 4 cdd300
+5 8 4 c400bc
+6 8 4 c400bc
+7 8 4 c400bc
+8 8 4 920088
+0 0 5 920088
+1 0 5 c400bc
+2 0 5 cdd300
+3 0 5 c400bc
+4 0 5 c400bc
+5 0 5 c400bc
+6 0 5 cdd300
+7 0 5 c400bc
+8 0 5 920088
+0 1 5 c400bc
+1 1 5 c400bc
+2 1 5 ffffff
+3 1 5 ffffff
+4 1 5 ffffff
+5 1 5 ffffff
+6 1 5 ffffff
+7 1 5 ffffff
+8 1 5 c400bc
+0 2 5 cdd300
+1 2 5 ffffff
+2 2 5 ffffff
+3 2 5 ffffff
+4 2 5 ffffff
+5 2 5 ffffff
+6 2 5 ffffff
+7 2 5 ffffff
+8 2 5 cdd300
+0 3 5 c400bc
+1 3 5 ffffff
+2 3 5 ffffff
+3 3 5 ffffff
+4 3 5 ffffff
+5 3 5 ffffff
+6 3 5 ffffff
+7 3 5 ffffff
+8 3 5 c400bc
+0 4 5 c400bc
+1 4 5 ffffff
+2 4 5 ffffff
+3 4 5 ffffff
+4 4 5 ffffff
+5 4 5 ffffff
+6 4 5 ffffff
+7 4 5 ffffff
+8 4 5 c400bc
+0 5 5 c400bc
+1 5 5 ffffff
+2 5 5 ffffff
+3 5 5 ffffff
+4 5 5 ffffff
+5 5 5 ffffff
+6 5 5 ffffff
+7 5 5 ffffff
+8 5 5 c400bc
+0 6 5 cdd300
+1 6 5 ffffff
+2 6 5 ffffff
+3 6 5 ffffff
+4 6 5 ffffff
+5 6 5 ffffff
+6 6 5 ffffff
+7 6 5 ffffff
+8 6 5 cdd300
+0 7 5 c400bc
+1 7 5 ffffff
+2 7 5 ffffff
+3 7 5 ffffff
+4 7 5 ffffff
+5 7 5 ffffff
+6 7 5 ffffff
+7 7 5 ffffff
+8 7 5 c400bc
+0 8 5 920088
+1 8 5 c400bc
+2 8 5 cdd300
+3 8 5 c400bc
+4 8 5 c400bc
+5 8 5 c400bc
+6 8 5 cdd300
+7 8 5 c400bc
+8 8 5 920088
+0 0 6 920088
+1 0 6 c400bc
+2 0 6 c400bc
+3 0 6 cdd300
+4 0 6 cdd300
+5 0 6 cdd300
+6 0 6 c400bc
+7 0 6 c400bc
+8 0 6 920088
+0 1 6 c400bc
+1 1 6 c400bc
+2 1 6 c400bc
+3 1 6 c400bc
+4 1 6 ffffff
+5 1 6 ffffff
+6 1 6 c400bc
+7 1 6 c400bc
+8 1 6 c400bc
+0 2 6 c400bc
+1 2 6 c400bc
+2 2 6 ffffff
+3 2 6 ffffff
+4 2 6 ffffff
+5 2 6 ffffff
+6 2 6 ffffff
+7 2 6 ffffff
+8 2 6 c400bc
+0 3 6 cdd300
+1 3 6 ffffff
+2 3 6 ffffff
+3 3 6 ffffff
+4 3 6 ffffff
+5 3 6 ffffff
+6 3 6 ffffff
+7 3 6 ffffff
+8 3 6 cdd300
+0 4 6 cdd300
+1 4 6 ffffff
+2 4 6 ffffff
+3 4 6 ffffff
+4 4 6 ffffff
+5 4 6 ffffff
+6 4 6 ffffff
+7 4 6 ffffff
+8 4 6 cdd300
+0 5 6 cdd300
+1 5 6 ffffff
+2 5 6 ffffff
+3 5 6 ffffff
+4 5 6 ffffff
+5 5 6 ffffff
+6 5 6 ffffff
+7 5 6 ffffff
+8 5 6 cdd300
+0 6 6 c400bc
+1 6 6 ffffff
+2 6 6 ffffff
+3 6 6 ffffff
+4 6 6 ffffff
+5 6 6 ffffff
+6 6 6 ffffff
+7 6 6 ffffff
+8 6 6 c400bc
+0 7 6 c400bc
+1 7 6 ffffff
+2 7 6 ffffff
+3 7 6 ffffff
+4 7 6 ffffff
+5 7 6 ffffff
+6 7 6 ffffff
+7 7 6 ffffff
+8 7 6 c400bc
+0 8 6 920088
+1 8 6 c400bc
+2 8 6 c400bc
+3 8 6 cdd300
+4 8 6 cdd300
+5 8 6 cdd300
+6 8 6 c400bc
+7 8 6 c400bc
+8 8 6 920088
+0 0 7 920088
+1 0 7 c400bc
+2 0 7 c400bc
+3 0 7 c400bc
+4 0 7 c400bc
+5 0 7 c400bc
+6 0 7 c400bc
+7 0 7 c400bc
+8 0 7 920088
+0 1 7 c400bc
+1 1 7 ffffff
+2 1 7 c400bc
+3 1 7 ffffff
+4 1 7 ffffff
+5 1 7 ffffff
+6 1 7 ffffff
+7 1 7 c400bc
+8 1 7 c400bc
+0 2 7 c400bc
+1 2 7 c400bc
+2 2 7 c400bc
+3 2 7 c400bc
+4 2 7 ffffff
+5 2 7 c400bc
+6 2 7 c400bc
+7 2 7 c400bc
+8 2 7 c400bc
+0 3 7 c400bc
+1 3 7 c400bc
+2 3 7 ffffff
+3 3 7 ffffff
+4 3 7 c400bc
+5 3 7 c400bc
+6 3 7 c400bc
+7 3 7 ffffff
+8 3 7 c400bc
+0 4 7 c400bc
+1 4 7 ffffff
+2 4 7 ffffff
+3 4 7 ffffff
+4 4 7 ffffff
+5 4 7 ffffff
+6 4 7 ffffff
+7 4 7 ffffff
+8 4 7 c400bc
+0 5 7 c400bc
+1 5 7 ffffff
+2 5 7 ffffff
+3 5 7 ffffff
+4 5 7 ffffff
+5 5 7 ffffff
+6 5 7 ffffff
+7 5 7 ffffff
+8 5 7 c400bc
+0 6 7 c400bc
+1 6 7 ffffff
+2 6 7 ffffff
+3 6 7 ffffff
+4 6 7 ffffff
+5 6 7 ffffff
+6 6 7 ffffff
+7 6 7 ffffff
+8 6 7 c400bc
+0 7 7 c400bc
+1 7 7 ffffff
+2 7 7 ffffff
+3 7 7 ffffff
+4 7 7 ffffff
+5 7 7 ffffff
+6 7 7 ffffff
+7 7 7 ffffff
+8 7 7 c400bc
+0 8 7 920088
+1 8 7 c400bc
+2 8 7 c400bc
+3 8 7 c400bc
+4 8 7 c400bc
+5 8 7 c400bc
+6 8 7 c400bc
+7 8 7 c400bc
+8 8 7 920088
+0 0 8 920088
+1 0 8 920088
+2 0 8 920088
+3 0 8 920088
+4 0 8 920088
+5 0 8 920088
+6 0 8 920088
+7 0 8 920088
+8 0 8 920088
+0 1 8 920088
+1 1 8 c400bc
+2 1 8 c400bc
+3 1 8 c400bc
+4 1 8 c400bc
+5 1 8 c400bc
+6 1 8 c400bc
+7 1 8 c400bc
+8 1 8 920088
+0 2 8 920088
+1 2 8 c400bc
+2 2 8 c400bc
+3 2 8 c400bc
+4 2 8 cdd300
+5 2 8 c400bc
+6 2 8 c400bc
+7 2 8 c400bc
+8 2 8 920088
+0 3 8 920088
+1 3 8 c400bc
+2 3 8 c400bc
+3 3 8 c400bc
+4 3 8 c400bc
+5 3 8 c400bc
+6 3 8 c400bc
+7 3 8 c400bc
+8 3 8 920088
+0 4 8 920088
+1 4 8 c400bc
+2 4 8 c400bc
+3 4 8 c400bc
+4 4 8 cdd300
+5 4 8 cdd300
+6 4 8 c400bc
+7 4 8 c400bc
+8 4 8 920088
+0 5 8 920088
+1 5 8 c400bc
+2 5 8 cdd300
+3 5 8 c400bc
+4 5 8 c400bc
+5 5 8 c400bc
+6 5 8 cdd300
+7 5 8 c400bc
+8 5 8 920088
+0 6 8 920088
+1 6 8 c400bc
+2 6 8 c400bc
+3 6 8 cdd300
+4 6 8 cdd300
+5 6 8 cdd300
+6 6 8 c400bc
+7 6 8 c400bc
+8 6 8 920088
+0 7 8 920088
+1 7 8 c400bc
+2 7 8 c400bc
+3 7 8 c400bc
+4 7 8 c400bc
+5 7 8 c400bc
+6 7 8 c400bc
+7 7 8 c400bc
+8 7 8 920088
+0 8 8 920088
+1 8 8 920088
+2 8 8 920088
+3 8 8 920088
+4 8 8 920088
+5 8 8 920088
+6 8 8 920088
+7 8 8 920088
+8 8 8 920088
-name player scale 1 1.8 1
- name nametag pos 0 1.1 0
- name neck pos 0 0.75 0 scale 0.45 0.25 0.45
- name head pos 0 +0.5 0 cube head
- name eyes pos 0 0 +0.5
- name body scale 0.48 0.75 0.225
- name upper pos 0 1.0 0 scale 1 0.5 1
- name chest pos 0 -0.5 0 cube chest
- name shoulders scale 0.5 1 1
- name left pos -1.5 0 0
- name arm pos 0 -0.5 0 cube arm
- name right pos +1.5 0 0
- name arm pos 0 -0.5 0 cube arm
- name lower pos 0 0.5 0 scale 1 0.5 1
- name hips scale 0.5 1 1
- name left pos -0.5 0 0
- name leg pos 0 -0.5 0 cube leg
- name right pos +0.5 0 0
- name leg pos 0 -0.5 0 cube leg
+name nametag pos 0 2 0
+name neck pos 0 1.35 0
+ name head pos 0 0.225 0 scale 0.45 0.45 0.45 cube head
+ name eyes pos 0 0 +0.5
+name chest pos 0 1.0125 0 scale 0.48 0.675 0.225 cube chest
+name arm_left pos -0.36 1.35 0 scale -1 1 1 clockwise
+ pos 0 -0.3375 0 scale 0.24 0.675 0.225 cube arm
+ name hand pos 0 -0.585 0 scale 0.0625 0.0625 0.0625 rot 90 0 0
+name arm_right pos +0.36 1.35 0
+ pos 0 -0.3375 0 scale 0.24 0.675 0.225 cube arm
+ name hand pos 0 -0.585 0 scale 0.0625 0.0625 0.0625 rot 90 0 0
+name leg_left pos -0.12 0.675 0 scale -1 1 1 clockwise
+ pos 0 -0.3375 0 scale 0.24 0.675 0.225 cube leg
+name leg_right pos +0.12 0.675 0
+ pos 0 -0.3375 0 scale 0.24 0.675 0.225 cube leg
in vec3 fragmentPosition;
-in vec3 fragmentNormal;
in vec3 fragmentTextureCoordinates;
in float fragmentLight;
layout(location = 1) in vec3 vertexNormal;
out vec3 fragmentPosition;
-out vec3 fragmentNormal;
out vec3 fragmentTextureCoordinates;
out float fragmentLight;
gl_Position = VP * worldSpace;
fragmentPosition = worldSpace.xyz;
- fragmentNormal = vertexNormal;
fragmentTextureCoordinates = vertexPosition;
- float diffuseLight = 0.3 * daylight * clamp(dot(normalize(fragmentNormal), normalize(lightDir)), 0.0, 1.0);
- fragmentLight = ambientLight + diffuseLight;
+ mat3 normalMatrix = transpose(inverse(mat3(model)));
+ vec3 normal = normalize(normalMatrix * vertexNormal);
+ fragmentLight = ambientLight + 0.3 * daylight * clamp(dot(normal, normalize(lightDir)), 0.0, 1.0);
}
--- /dev/null
+in vec3 fragmentPosition;
+in vec3 fragmentColor;
+
+out vec4 outColor;
+
+uniform vec3 fogColor;
+uniform vec3 cameraPos;
+
+void main()
+{
+ outColor = vec4(fragmentColor, 1.0);
+ outColor.rgb = mix(outColor.rgb, fogColor, clamp(length(fragmentPosition - cameraPos) / VIEW_DISTANCE, 0.0, 1.0));
+
+ if (outColor.a == 0.0)
+ discard;
+}
--- /dev/null
+layout(location = 0) in vec3 vertexPosition;
+layout(location = 1) in vec3 vertexNormal;
+layout(location = 2) in vec3 vertexColor;
+
+out vec3 fragmentPosition;
+out vec3 fragmentColor;
+
+uniform mat4 model;
+uniform mat4 VP;
+uniform float daylight;
+uniform float ambientLight;
+uniform vec3 lightDir;
+
+void main()
+{
+ vec4 worldSpace = model * vec4(vertexPosition, 1.0);
+ gl_Position = VP * worldSpace;
+
+ fragmentPosition = worldSpace.xyz;
+ fragmentColor = vertexColor;
+
+ mat3 normalMatrix = transpose(inverse(mat3(model)));
+ vec3 normal = normalize(normalMatrix * vertexNormal);
+ fragmentColor *= ambientLight + 0.3 * daylight * clamp(dot(normal, normalize(lightDir)), 0.0, 1.0);
+}
in vec3 fragmentPosition;
-in vec3 fragmentNormal;
in vec2 fragmentTextureCoordinates;
in float fragmentTextureIndex;
in vec3 fragmentColor;
layout(location = 4) in vec3 vertexColor;
out vec3 fragmentPosition;
-out vec3 fragmentNormal;
out vec2 fragmentTextureCoordinates;
out float fragmentTextureIndex;
out vec3 fragmentColor;
gl_Position = VP * worldSpace;
fragmentPosition = worldSpace.xyz;
- fragmentNormal = vertexNormal;
fragmentTextureCoordinates = vertexTextureCoordinates;
fragmentTextureIndex = vertexTextureIndex;
fragmentColor = vertexColor;
- float diffuseLight = 0.3 * daylight * clamp(dot(normalize(fragmentNormal), normalize(lightDir)), 0.0, 1.0);
- float light = ambientLight + diffuseLight;
-
- fragmentColor *= light;
+ fragmentColor *= ambientLight + 0.3 * daylight * clamp(dot(normalize(vertexNormal), normalize(lightDir)), 0.0, 1.0);
}
day.c
environment.c
interrupt.c
+ item.c
node.c
perlin.c
physics.c
client/client_auth.c
client/client_config.c
client/client_entity.c
+ client/client_inventory.c
+ client/client_item.c
client/client_node.c
client/client_player.c
client/client_terrain.c
client/mesh.c
client/model.c
client/raycast.c
+ client/screenshot.c
client/shader.c
client/sky.c
client/terrain_gfx.c
#include <math.h>
#include "client/camera.h"
-#include "client/client.h"
struct Camera camera;
mat4x4_look_at(camera.view, camera.eye, center, camera.up);
}
+void camera_init()
+{
+ camera_set_position((v3f32) {0.0f, 0.0f, 0.0f});
+ camera_set_angle(0.0f, 0.0f);
+}
+
void camera_set_position(v3f32 pos)
{
camera.eye[0] = pos.x;
#ifndef _CAMERA_H_
#define _CAMERA_H_
-#include <GL/glew.h>
-#include <GLFW/glfw3.h>
#include <linmath.h/linmath.h>
#include "types.h"
} movement_dirs;
} camera;
+void camera_init();
void camera_set_position(v3f32 pos);
void camera_set_angle(f32 yaw, f32 pitch);
-void camera_on_resize(int width, int height);
#endif // _CAMERA_H_
#include <unistd.h>
#include "client/client.h"
#include "client/client_auth.h"
+#include "client/client_inventory.h"
#include "client/client_player.h"
#include "client/client_terrain.h"
#include "client/debug_menu.h"
client->on_recv_type[DRAGONNET_TYPE_ToClientEntityRemove ] = (void *) &client_entity_remove;
client->on_recv_type[DRAGONNET_TYPE_ToClientEntityUpdatePosRot ] = (void *) &client_entity_update_pos_rot;
client->on_recv_type[DRAGONNET_TYPE_ToClientEntityUpdateNametag] = (void *) &client_entity_update_nametag;
+ client->on_recv_type[DRAGONNET_TYPE_ToClientPlayerInventory ] = (void *) &client_inventory_update_player;
flag_ini(&finish);
flag_ini(&gfx_init);
if (!entity->data.nametag)
entity->nametag->visible = false;
} else if (entity->data.nametag) {
- entity->nametag = gui_add(NULL, (GUIElementDefinition) {
+ entity->nametag = gui_add(NULL, (GUIElementDef) {
.pos = {-1.0f, -1.0f},
.z_index = 0.1f,
.offset = {0, 0},
model_node_transform(entity->model->root);
}
-void client_entity_add(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityAdd *pkt)
+void client_entity_add(__attribute__((unused)) void *peer, ToClientEntityAdd *pkt)
{
if (pkt->type >= COUNT_ENTITY)
return;
refcount_drp(&entity->rc);
}
-void client_entity_remove(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityRemove *pkt)
+void client_entity_remove(__attribute__((unused)) void *peer, ToClientEntityRemove *pkt)
{
map_del(&entities, &pkt->id, &cmp_entity, &entity_drop, NULL, &refcount_obj);
}
-void client_entity_update_pos_rot(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityUpdatePosRot *pkt)
+void client_entity_update_pos_rot(__attribute__((unused)) void *peer, ToClientEntityUpdatePosRot *pkt)
{
ClientEntity *entity = client_entity_grab(pkt->id);
refcount_drp(&entity->rc);
}
-void client_entity_update_nametag(__attribute__((unused)) DragonnetPeer *peer, ToClientEntityUpdateNametag *pkt)
+void client_entity_update_nametag(__attribute__((unused)) void *peer, ToClientEntityUpdateNametag *pkt)
{
ClientEntity *entity = client_entity_grab(pkt->id);
#ifndef _CLIENT_ENTITY_H_
#define _CLIENT_ENTITY_H_
-#include <dragonnet/peer.h>
#include <dragonstd/refcount.h>
#include <pthread.h>
#include "client/gui.h"
#include "client/model.h"
#include "entity.h"
+#include "item.h"
#include "types.h"
typedef struct {
void client_entity_transform(ClientEntity *entity);
-void client_entity_add(DragonnetPeer *peer, ToClientEntityAdd *pkt);
-void client_entity_remove(DragonnetPeer *peer, ToClientEntityRemove *pkt);
-void client_entity_update_pos_rot(DragonnetPeer *peer, ToClientEntityUpdatePosRot *pkt);
-void client_entity_update_nametag(DragonnetPeer *peer, ToClientEntityUpdateNametag *pkt);
+void client_entity_add(void *peer, ToClientEntityAdd *pkt);
+void client_entity_remove(void *peer, ToClientEntityRemove *pkt);
+void client_entity_update_pos_rot(void *peer, ToClientEntityUpdatePosRot *pkt);
+void client_entity_update_nametag(void *peer, ToClientEntityUpdateNametag *pkt);
#endif // _CLIENT_ENTITY_H_
--- /dev/null
+#include <asprintf/asprintf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "client/client_config.h"
+#include "client/client_inventory.h"
+#include "client/client_item.h"
+#include "client/gl_debug.h"
+#include "client/frustum.h"
+#include "client/light.h"
+#include "client/shader.h"
+
+static GLuint _3d_shader_prog;
+static GLint _3d_loc_VP;
+static ModelShader _3d_model_shader;
+static LightShader _3d_light_shader;
+
+bool client_inventory_init()
+{
+ char *_3d_shader_defs;
+ asprintf(&_3d_shader_defs, "#define VIEW_DISTANCE %lf\n", client_config.view_distance);
+
+ if (!shader_program_create(RESSOURCE_PATH "shaders/3d/item", &_3d_shader_prog, _3d_shader_defs)) {
+ fprintf(stderr, "[error] failed to create 3D item shader program\n");
+ return false;
+ }
+
+ free(_3d_shader_defs);
+
+ _3d_loc_VP = glGetUniformLocation(_3d_shader_prog, "VP");
+
+ _3d_model_shader.prog = _3d_shader_prog;
+ _3d_model_shader.loc_transform = glGetUniformLocation(_3d_shader_prog, "model"); GL_DEBUG
+
+ _3d_light_shader.prog = _3d_shader_prog;
+ light_shader_locate(&_3d_light_shader);
+
+ return true;
+}
+
+void client_inventory_deinit()
+{
+ glDeleteProgram(_3d_shader_prog); GL_DEBUG
+}
+
+void client_inventory_update()
+{
+ glProgramUniformMatrix4fv(_3d_shader_prog, _3d_loc_VP, 1, GL_FALSE, frustum[0]); GL_DEBUG
+ light_shader_update(&_3d_light_shader);
+}
+
+static void wield_init(ModelNode *hand)
+{
+ if (hand)
+ model_node_add_mesh(hand, &(ModelMesh) {
+ .mesh = NULL,
+ .textures = NULL,
+ .num_textures = 0,
+ .shader = &_3d_model_shader,
+ });
+}
+
+static void wield_update(ModelNode *hand, ModelNode *arm, ItemType item)
+{
+ Mesh *mesh = client_item_mesh(item);
+
+ if (hand)
+ ((ModelMesh *) hand->meshes.ptr)[0].mesh = mesh;
+
+ if (arm) {
+ arm->rot.x = mesh ? -M_PI / 8.0 : 0.0;
+ model_node_transform(arm);
+ }
+}
+
+void client_inventory_init_player(ClientEntity *entity)
+{
+ ClientPlayerData *data = entity->extra;
+
+ item_stack_initialize(&data->inventory.left);
+ item_stack_initialize(&data->inventory.right);
+
+ wield_init(data->bones.hand_left);
+ wield_init(data->bones.hand_right);
+}
+
+void client_inventory_deinit_player(ClientEntity *entity)
+{
+ ClientPlayerData *data = entity->extra;
+
+ item_stack_destroy(&data->inventory.left);
+ item_stack_destroy(&data->inventory.right);
+}
+
+void client_inventory_update_player(__attribute__((unused)) void *peer, ToClientPlayerInventory *pkt)
+{
+ ClientEntity *entity = client_player_entity(pkt->id);
+ if (!entity)
+ return;
+
+ ClientPlayerData *data = entity->extra;
+
+ item_stack_deserialize(&data->inventory.left, &pkt->left);
+ item_stack_deserialize(&data->inventory.right, &pkt->right);
+
+ wield_update(data->bones.hand_left, data->bones.arm_left, data->inventory.left.type);
+ wield_update(data->bones.hand_right, data->bones.arm_right, data->inventory.right.type);
+
+ refcount_drp(&entity->rc);
+}
--- /dev/null
+#ifndef _CLIENT_INVENTORY_H_
+#define _CLIENT_INVENTORY_H_
+
+#include <stdbool.h>
+#include "client/client_player.h"
+#include "client/model.h"
+
+bool client_inventory_init();
+void client_inventory_deinit();
+void client_inventory_update();
+
+void client_inventory_init_player(ClientEntity *entity);
+void client_inventory_deinit_player(ClientEntity *entity);
+void client_inventory_update_player(void *peer, ToClientPlayerInventory *pkt);
+
+#endif // _CLIENT_INVENTORY_H_
--- /dev/null
+#include "client/client_item.h"
+
+ClientItemDef client_item_defs[COUNT_ITEM] = {
+ // unknown
+ {
+ .mesh_path = RESSOURCE_PATH "meshes/unknown.txt",
+ .mesh = {0},
+ },
+ // none
+ {
+ .mesh_path = NULL,
+ .mesh = {0},
+ },
+ // pickaxe
+ {
+ .mesh_path = RESSOURCE_PATH "meshes/pickaxe.txt",
+ .mesh = {0},
+ },
+ // axe
+ {
+ .mesh_path = RESSOURCE_PATH "meshes/axe.txt",
+ .mesh = {0},
+ },
+};
+
+void client_item_init()
+{
+ for (ItemType i = 0; i < COUNT_ITEM; i++)
+ if (client_item_defs[i].mesh_path)
+ mesh_load(&client_item_defs[i].mesh, client_item_defs[i].mesh_path);
+}
+
+void client_item_deinit()
+{
+ for (ItemType i = 0; i < COUNT_ITEM; i++)
+ if (client_item_defs[i].mesh_path)
+ mesh_destroy(&client_item_defs[i].mesh);
+}
+
+Mesh *client_item_mesh(ItemType type)
+{
+ return client_item_defs[type].mesh_path ? &client_item_defs[type].mesh : NULL;
+}
--- /dev/null
+#ifndef _CLIENT_ITEM_H_
+#define _CLIENT_ITEM_H_
+
+#include "client/mesh.h"
+#include "item.h"
+
+typedef struct {
+ const char *mesh_path;
+ Mesh mesh;
+} ClientItemDef;
+
+extern ClientItemDef client_item_defs[];
+
+void client_item_init();
+void client_item_deinit();
+Mesh *client_item_mesh(ItemType type);
+
+#endif // _CLIENT_ITEM_H_
args->vertex.color = ((ColorData *) args->node->data)->color;
}
-ClientNodeDefinition client_node_definitions[NODE_UNLOADED] = {
+ClientNodeDef client_node_defs[NODE_UNLOADED] = {
// unknown
{
.tiles = TILES_SIMPLE(RESSOURCE_PATH "textures/unknown.png"),
.render = NULL,
.pointable = true,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Unknown",
},
// air
{
.render = NULL,
.pointable = false,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Air",
},
// grass
{
.render = &render_grass,
.pointable = true,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Grass",
},
// dirt
{
.render = NULL,
.pointable = true,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Dirt",
},
// stone
{
.render = &render_stone,
.pointable = true,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Stone",
},
// snow
{
.render = NULL,
.pointable = true,
.selection_color = {0.1f, 0.5f, 1.0f},
+ .name = "Snow",
},
// oak wood
{
.render = &render_color,
.pointable = true,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Oak Wood",
},
// oak leaves
{
.render = &render_color,
.pointable = true,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Oak Leaves",
},
// pine wood
{
.render = &render_color,
.pointable = true,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Pine Wood",
},
// pine leaves
{
.render = &render_color,
.pointable = true,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Pine Leaves",
},
// palm wood
{
.render = &render_color,
.pointable = true,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Palm Wood",
},
// palm leaves
{
.render = &render_color,
.pointable = true,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Palm Leaves",
},
// sand
{
.render = NULL,
.pointable = true,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Sand",
},
// water
{
.render = NULL,
.pointable = false,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Water",
},
// lava
{
.render = NULL,
.pointable = false,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Lava",
},
// vulcano_stone
{
.render = NULL,
.pointable = true,
.selection_color = {1.0f, 1.0f, 1.0f},
+ .name = "Vulcano Stone",
},
};
void client_node_init()
{
- for (NodeType node = NODE_UNKNOWN; node < NODE_UNLOADED; node++) {
- ClientNodeDefinition *def = &client_node_definitions[node];
+ for (NodeType node = 0; node < NODE_UNLOADED; node++) {
+ ClientNodeDef *def = &client_node_defs[node];
if (def->visibility != VISIBILITY_NONE) {
Texture *textures[6];
void (*render)(NodeArgsRender *args);
bool pointable;
v3f32 selection_color;
-} ClientNodeDefinition;
+ char *name;
+} ClientNodeDef;
-extern ClientNodeDefinition client_node_definitions[];
+extern ClientNodeDef client_node_defs[];
void client_node_init();
#endif // _CLIENT_NODE_H_
#include <stdlib.h>
#include "client/camera.h"
#include "client/client.h"
+#include "client/client_inventory.h"
#include "client/client_player.h"
#include "client/client_terrain.h"
#include "client/cube.h"
#include "environment.h"
#include "physics.h"
-typedef struct {
- ModelNode *nametag;
- ModelNode *neck;
- ModelNode *eyes;
- ModelNode *shoulder_left;
- ModelNode *shoulder_right;
- ModelNode *hip_left;
- ModelNode *hip_right;
-} PlayerModelBones;
-
struct ClientPlayer client_player;
static ClientEntity *player_entity;
{
vec4 dst, src = {0.0f, 0.0f, 0.0f, 1.0f};
- PlayerModelBones *bones = player_entity->extra;
+ ClientPlayerData *data = player_entity->extra;
- if (bones->eyes)
- mat4x4_mul_vec4(dst, bones->eyes->abs, src);
+ if (data->bones.eyes)
+ mat4x4_mul_vec4(dst, data->bones.eyes->abs, src);
else
vec4_dup(dst, src);
entity->model = model_clone(player_model);
entity->model->extra = refcount_grb(&entity->rc);
- PlayerModelBones *bones = entity->extra = malloc(sizeof *bones);
- *bones = (PlayerModelBones) {NULL};
- model_get_bones(entity->model, (ModelBoneMapping[]) {
- {"player.nametag", &bones->nametag },
- {"player.neck", &bones->neck },
- {"player.neck.head.eyes", &bones->eyes },
- {"player.body.upper.shoulders.left", &bones->shoulder_left },
- {"player.body.upper.shoulders.right", &bones->shoulder_right},
- {"player.body.lower.hips.left", &bones->hip_left },
- {"player.body.lower.hips.right", &bones->hip_right },
- }, 7);
-
- entity->nametag_offset = bones->nametag ? &bones->nametag->abs : NULL;
+ ClientPlayerData *data = entity->extra = malloc(sizeof *data);
+ data->bones = (struct ClientPlayerBones) {NULL};
+
+ model_get_bones(entity->model, (ModelBoneMapping[9]) {
+ {"nametag", &data->bones.nametag },
+ {"neck", &data->bones.neck },
+ {"neck.head.eyes", &data->bones.eyes },
+ {"arm_left", &data->bones.arm_left },
+ {"arm_right", &data->bones.arm_right },
+ {"arm_left.hand", &data->bones.hand_left },
+ {"arm_right.hand", &data->bones.hand_right},
+ {"leg_left", &data->bones.leg_left },
+ {"leg_right", &data->bones.leg_right },
+ }, 9);
+
+ entity->nametag_offset = data->bones.nametag ? &data->bones.nametag->abs : NULL;
entity->box_collision = (aabb3f32) {{-0.45f, 0.0f, -0.45f}, {0.45f, 1.8f, 0.45f}};
+ client_inventory_init_player(entity);
+
model_scene_add(entity->model);
client_entity_transform(entity);
}
static void on_free(ClientEntity *entity)
{
+ client_inventory_init_player(entity);
free(entity->extra);
}
static void on_transform(ClientEntity *entity)
{
- PlayerModelBones *bones = entity->extra;
+ ClientPlayerData *data = entity->extra;
entity->model->root->rot.x = entity->model->root->rot.z = 0.0f;
- if (bones->neck) {
- bones->neck->rot.x = entity->data.rot.x;
- model_node_transform(bones->neck);
+ if (data->bones.neck) {
+ data->bones.neck->rot.x = entity->data.rot.x;
+ model_node_transform(data->bones.neck);
}
}
static void __attribute__((unused)) on_model_step(Model *model, __attribute__((unused)) f64 dtime)
{
- PlayerModelBones *bones = ((ClientEntity *) model->extra)->extra;
- (void) bones;
+ ClientPlayerData *data = ((ClientEntity *) model->extra)->extra;
+ (void) data; // ToDo: animations
}
static void on_model_delete(Model *model)
model_delete(player_model);
}
-ClientEntity *client_player_entity()
+ClientEntity *client_player_entity(u64 id)
+{
+ ClientEntity *entity = client_entity_grab(id);
+
+ if (entity->type == &client_entity_types[ENTITY_LOCALPLAYER]
+ || entity->type == &client_entity_types[ENTITY_PLAYER])
+ return entity;
+
+ refcount_drp(&entity->rc);
+ return NULL;
+}
+
+ClientEntity *client_player_entity_local()
{
ClientEntity *entity = NULL;
// jump if possible
void client_player_jump()
{
- ClientEntity *entity = client_player_entity();
+ ClientEntity *entity = client_player_entity_local();
if (!entity)
return;
// to be called every frame
void client_player_tick(f64 dtime)
{
- ClientEntity *entity = client_player_entity();
+ ClientEntity *entity = client_player_entity_local();
if (!entity)
return;
pthread_rwlock_t lock_movement;
} client_player;
+typedef struct {
+ struct {
+ ItemStack left;
+ ItemStack right;
+ } inventory;
+ struct ClientPlayerBones {
+ ModelNode *nametag;
+ ModelNode *neck;
+ ModelNode *eyes;
+ ModelNode *arm_left;
+ ModelNode *arm_right;
+ ModelNode *hand_left;
+ ModelNode *hand_right;
+ ModelNode *leg_left;
+ ModelNode *leg_right;
+ } bones;
+} ClientPlayerData;
+
void client_player_init(); // called on startup
void client_player_deinit(); // called on shutdown
void client_player_gfx_init();
void client_player_gfx_deinit();
-ClientEntity *client_player_entity(); // grab and return client entity
+ClientEntity *client_player_entity(u64 id); // grab and return client entity by id
+ClientEntity *client_player_entity_local(); // grab and return local client entity
void client_player_jump(); // jump if possible
static size_t old_num_requests = 0;
v3f64 player_pos;
- ClientEntity *entity = client_player_entity();
+ ClientEntity *entity = client_player_entity_local();
if (entity) {
pthread_rwlock_rdlock(&entity->lock_pos_rot);
#include <stdlib.h>
#include <pthread.h>
#include "client/client_config.h"
+#include "client/client_node.h"
#include "client/client_player.h"
#include "client/client_terrain.h"
#include "client/debug_menu.h"
#include "client/game.h"
#include "client/gl_debug.h"
#include "client/gui.h"
+#include "client/interact.h"
#include "client/window.h"
#include "day.h"
#include "environment.h"
static pthread_mutex_t changed_elements_mtx = PTHREAD_MUTEX_INITIALIZER;
static bool debug_menu_enabled = true;
-static DebugMenuEntry last_always_visible = ENTRY_POS;
+static DebugMenuEntry last_always_visible = ENTRY_POINTED;
static char *get_entry_text(DebugMenuEntry entry)
{
int minutes = 0;
v3f64 pos = {0.0f, 0.0f, 0.0f};
v3f32 rot = {0.0f, 0.0f, 0.0f};
+ char *pnt_name = NULL;
+
+ // shortcut
+ static struct InteractPointed *pnt = &interact_pointed;
switch (entry) {
case ENTRY_POS:
case ENTRY_PITCH:
case ENTRY_HUMIDITY:
case ENTRY_TEMPERATURE: {
- ClientEntity *entity = client_player_entity();
+ ClientEntity *entity = client_player_entity_local();
if (!entity)
return strdup("");
break;
}
+ case ENTRY_POINTED:
+ if (!pnt->exists)
+ return strdup("");
+
+ pnt_name = client_node_defs[pnt->node].name;
+ break;
+
case ENTRY_FLIGHT:
case ENTRY_COLLISION:
pthread_rwlock_rdlock(&client_player.lock_movement);
case ENTRY_VERSION: asprintf(&str, "Dragonblocks Alpha %s", VERSION ); break;
case ENTRY_FPS: asprintf(&str, "%d FPS", game_fps ); break;
case ENTRY_POS: asprintf(&str, "(%.1f %.1f %.1f)", pos.x, pos.y, pos.z ); break;
+ case ENTRY_POINTED: asprintf(&str, "%s (%d, %d, %d)", pnt_name, pnt->pos.x, pnt->pos.y, pnt->pos.z ); break;
case ENTRY_YAW: asprintf(&str, "yaw = %.1f", 360.0 - rot.y / M_PI * 180.0 ); break;
case ENTRY_PITCH: asprintf(&str, "pitch = %.1f", -rot.x / M_PI * 180.0 ); break;
case ENTRY_TIME: asprintf(&str, "%02d:%02d", hours, minutes ); break;
s32 offset = -16;
for (DebugMenuEntry i = 0; i < COUNT_ENTRY; i++) {
- gui_elements[i] = gui_add(NULL, (GUIElementDefinition) {
+ gui_elements[i] = gui_add(NULL, (GUIElementDef) {
.pos = {0.0f, 0.0f},
.z_index = 0.1f,
.offset = {2, offset += 18},
ENTRY_VERSION,
ENTRY_FPS,
ENTRY_POS,
+ ENTRY_POINTED,
ENTRY_YAW,
ENTRY_PITCH,
ENTRY_TIME,
-#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <GL/glew.h>
#include <GL/gl.h>
#include <GLFW/glfw3.h>
-#include <stb/stb_image_write.h>
#include <stdio.h>
#include <unistd.h>
#include "client/camera.h"
#include "client/client.h"
#include "client/client_entity.h"
+#include "client/client_inventory.h"
+#include "client/client_item.h"
#include "client/client_node.h"
#include "client/client_player.h"
#include "client/client_terrain.h"
int game_fps = 0;
-static void crosshair_init()
-{
- gui_add(NULL, (GUIElementDefinition) {
- .pos = {0.5f, 0.5f},
- .z_index = 0.0f,
- .offset = {0, 0},
- .margin = {0, 0},
- .align = {0.5f, 0.5f},
- .scale = {1.0f, 1.0f},
- .scale_type = SCALE_IMAGE,
- .affect_parent_scale = false,
- .text = NULL,
- .image = texture_load(RESSOURCE_PATH "textures/crosshair.png", false),
- .text_color = {0.0f, 0.0f, 0.0f, 0.0f},
- .bg_color = {0.0f, 0.0f, 0.0f, 0.0f},
- });
-}
-
-static void render(f64 dtime)
+void game_render(f64 dtime)
{
glEnable(GL_DEPTH_TEST); GL_DEBUG
glEnable(GL_BLEND); GL_DEBUG
frustum_update();
terrain_gfx_update();
client_entity_gfx_update();
+ client_inventory_update();
sky_render();
model_scene_render(dtime);
debug_menu_changed(ENTRY_SUN_ANGLE);
debug_menu_update();
- render(dtime);
+ game_render(dtime);
glfwSwapBuffers(window.handle);
glfwPollEvents();
client_player_gfx_init();
- if (!interact_init())
+ camera_init();
+
+ if (!gui_init())
return false;
- client_node_init();
- client_terrain_start();
+ if (!interact_init())
+ return false;
- camera_set_position((v3f32) {0.0f, 0.0f, 0.0f});
- camera_set_angle(0.0f, 0.0f);
+ client_item_init();
- if (!gui_init())
+ if (!client_inventory_init())
return false;
+ client_node_init();
+ client_terrain_start();
+
debug_menu_init();
- crosshair_init();
input_init();
flag_set(gfx_init);
+
game_loop();
client_terrain_stop();
client_entity_gfx_deinit();
client_player_gfx_deinit();
interact_deinit();
+ client_item_deinit();
+ client_inventory_deinit();
return true;
}
-char *game_take_screenshot()
-{
- // renderbuffer for depth & stencil buffer
- GLuint rbo;
- glGenRenderbuffers(1, &rbo); GL_DEBUG
- glBindRenderbuffer(GL_RENDERBUFFER, rbo); GL_DEBUG
- glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH24_STENCIL8, window.width, window.height); GL_DEBUG
-
- // 2 textures, one with AA, one without
-
- GLuint txos[2];
- glGenTextures(2, txos); GL_DEBUG
-
- glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, txos[0]); GL_DEBUG
- glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB, window.width, window.height, GL_TRUE); GL_DEBUG
-
- glBindTexture(GL_TEXTURE_2D, txos[1]); GL_DEBUG
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window.width, window.height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); GL_DEBUG
-
- // 2 framebuffers, one with AA, one without
-
- GLuint fbos[2];
- glGenFramebuffers(2, fbos); GL_DEBUG
-
- glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); GL_DEBUG
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, txos[0], 0); GL_DEBUG
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); GL_DEBUG
-
- glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); GL_DEBUG
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, txos[1], 0); GL_DEBUG
-
- // render scene
- glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); GL_DEBUG
- render(0.0);
- glBindFramebuffer(GL_FRAMEBUFFER, 0); GL_DEBUG
-
- // blit AA-buffer into no-AA buffer
- glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); GL_DEBUG
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); GL_DEBUG
- glBlitFramebuffer(0, 0, window.width, window.height, 0, 0, window.width, window.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); GL_DEBUG
-
- // read data
- GLubyte data[window.width * window.height * 3];
- glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); GL_DEBUG
- glPixelStorei(GL_PACK_ALIGNMENT, 1); GL_DEBUG
- glReadPixels(0, 0, window.width, window.height, GL_RGB, GL_UNSIGNED_BYTE, data); GL_DEBUG
-
- // create filename
- char filename[BUFSIZ];
- time_t timep = time(0);
- strftime(filename, BUFSIZ, "screenshot-%Y-%m-%d-%H:%M:%S.png", localtime(&timep));
-
- // save screenshot
- stbi_flip_vertically_on_write(true);
- stbi_write_png(filename, window.width, window.height, 3, data, window.width * 3);
-
- // delete buffers
- glDeleteRenderbuffers(1, &rbo); GL_DEBUG
- glDeleteTextures(2, txos); GL_DEBUG
- glDeleteFramebuffers(2, fbos); GL_DEBUG
-
- return strdup(filename);
-}
#define _GAME_H_
#include <dragonstd/flag.h>
+#include "types.h"
extern int game_fps;
bool game(Flag *gfx_init);
-char *game_take_screenshot();
+void game_render(f64 dtime);
#endif // _GAME_H_
glEnable(GL_CULL_FACE); GL_DEBUG
}
-GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def)
+GUIElement *gui_add(GUIElement *parent, GUIElementDef def)
{
if (parent == NULL)
parent = &root_element;
Texture *image;
v4f32 text_color;
v4f32 bg_color;
-} GUIElementDefinition;
+} GUIElementDef;
typedef struct GUIElement {
- GUIElementDefinition def;
+ GUIElementDef def;
bool visible;
v2f32 pos;
v2f32 scale;
void gui_deinit();
void gui_update_projection();
void gui_render();
-GUIElement *gui_add(GUIElement *parent, GUIElementDefinition def);
+GUIElement *gui_add(GUIElement *parent, GUIElementDef def);
void gui_text(GUIElement *element, const char *text);
void gui_transform(GUIElement *element);
#include "client/client.h"
#include "client/client_player.h"
#include "client/debug_menu.h"
-#include "client/game.h"
#include "client/gui.h"
#include "client/input.h"
+#include "client/screenshot.h"
#include "client/window.h"
#include "day.h"
void input_init()
{
- pause_menu = gui_add(NULL, (GUIElementDefinition) {
+ pause_menu = gui_add(NULL, (GUIElementDef) {
.pos = {0.0f, 0.0f},
.z_index = 0.5f,
.offset = {0, 0},
.bg_color = {0.0f, 0.0f, 0.0f, 0.4f},
});
- status_message = gui_add(NULL, (GUIElementDefinition) {
+ status_message = gui_add(NULL, (GUIElementDef) {
.pos = {0.5f, 0.25f},
.z_index = 0.1f,
.offset = {0, 0},
debug_menu_toggle();
if (key_listener(&listener_screenshot)) {
- char *screenshot_filename = game_take_screenshot();
+ char *screenshot_filename = screenshot();
SET_STATUS_MESSAGE("Screenshot saved to %s", screenshot_filename)
free(screenshot_filename);
}
cursor_last_x = current_x;
cursor_last_y = current_y;
- ClientEntity *entity = client_player_entity();
+ ClientEntity *entity = client_player_entity_local();
if (!entity)
return;
#include "client/camera.h"
#include "client/client_node.h"
#include "client/cube.h"
+#include "client/debug_menu.h"
#include "client/frustum.h"
#include "client/gl_debug.h"
+#include "client/gui.h"
#include "client/interact.h"
#include "client/mesh.h"
#include "client/raycast.h"
#include "client/shader.h"
-static bool pointed;
-static v3s32 node_pos;
+struct InteractPointed interact_pointed;
+
static GLuint shader_prog;
static GLint loc_MVP;
static GLint loc_color;
selection_mesh.data = vertices;
mesh_upload(&selection_mesh);
+ gui_add(NULL, (GUIElementDef) {
+ .pos = {0.5f, 0.5f},
+ .z_index = 0.0f,
+ .offset = {0, 0},
+ .margin = {0, 0},
+ .align = {0.5f, 0.5f},
+ .scale = {1.0f, 1.0f},
+ .scale_type = SCALE_IMAGE,
+ .affect_parent_scale = false,
+ .text = NULL,
+ .image = texture_load(RESSOURCE_PATH "textures/crosshair.png", false),
+ .text_color = {0.0f, 0.0f, 0.0f, 0.0f},
+ .bg_color = {0.0f, 0.0f, 0.0f, 0.0f},
+ });
+
return true;
}
void interact_tick()
{
- v3s32 old_node_pos = node_pos;
-
- NodeType node;
- if ((pointed = raycast(
- (v3f64) {camera.eye [0], camera.eye [1], camera.eye [2]},
- (v3f64) {camera.front[0], camera.front[1], camera.front[2]},
- 5, &node_pos, &node)) && !v3s32_equals(node_pos, old_node_pos)) {
- mat4x4_translate(model, node_pos.x, node_pos.y, node_pos.z);
- v3f32 *color = &client_node_definitions[node].selection_color;
+ bool old_exists = interact_pointed.exists;
+ v3s32 old_pointed = interact_pointed.pos;
+ if ((interact_pointed.exists = raycast(
+ (v3f64) {camera.eye [0], camera.eye [1], camera.eye [2]},
+ (v3f64) {camera.front[0], camera.front[1], camera.front[2]},
+ 5, &interact_pointed.pos, &interact_pointed.node))
+ && !v3s32_equals(interact_pointed.pos, old_pointed)) {
+ mat4x4_translate(model,
+ interact_pointed.pos.x, interact_pointed.pos.y, interact_pointed.pos.z);
+ v3f32 *color = &client_node_defs[interact_pointed.node].selection_color;
glProgramUniform3f(shader_prog, loc_color, color->x, color->y, color->z); GL_DEBUG
+ debug_menu_changed(ENTRY_POINTED);
}
+
+ if (old_exists && !interact_pointed.exists)
+ debug_menu_changed(ENTRY_POINTED);
}
void interact_render()
{
- if (!pointed)
+ if (!interact_pointed.exists)
return;
mat4x4 mvp;
#ifndef _INTERACT_H_
#define _INTERACT_H_
+extern struct InteractPointed {
+ bool exists;
+ v3s32 pos;
+ NodeType node;
+} interact_pointed;
+
bool interact_init();
void interact_deinit();
void interact_tick();
+#include <dragonstd/tree.h>
#include <stddef.h>
+#include <stdio.h>
#include <stdlib.h>
+#include "client/cube.h"
#include "client/gl_debug.h"
#include "client/mesh.h"
+typedef struct {
+ v3s32 pos;
+ v3f32 color;
+} LoadedVoxel;
+
+typedef struct {
+ Tree voxels;
+ Array vertices;
+} LoadedRenderArgs;
+
+static v3s32 face_dir[6] = {
+ {+0, +0, -1},
+ {+0, +0, +1},
+ {-1, +0, +0},
+ {+1, +0, +0},
+ {+0, -1, +0},
+ {+0, +1, +0},
+};
+
+typedef struct {
+ v3f32 pos;
+ v3f32 normal;
+ v3f32 color;
+} __attribute__((packed)) LoadedVertex;
+static VertexLayout loaded_layout = {
+ .attributes = (VertexAttribute[]) {
+ {GL_FLOAT, 3, sizeof(v3f32)}, // position
+ {GL_FLOAT, 3, sizeof(v3f32)}, // normal
+ {GL_FLOAT, 3, sizeof(v3f32)}, // color
+ },
+ .count = 3,
+ .size = sizeof(LoadedVertex),
+};
+
+static int cmp_loaded_voxel(const LoadedVoxel *voxel, const v3s32 *pos)
+{
+ return v3s32_cmp(&voxel->pos, pos);
+}
+
+static void render_loaded_voxel(LoadedVoxel *voxel, LoadedRenderArgs *args)
+{
+ v3f32 pos = v3s32_to_f32(voxel->pos);
+ for (int f = 0; f < 6; f++) {
+ v3s32 neigh_pos = v3s32_add(voxel->pos, face_dir[f]);
+ if (tree_get(&args->voxels, &neigh_pos, &cmp_loaded_voxel, NULL))
+ continue;
+
+ for (int v = 0; v < 6; v++)
+ array_apd(&args->vertices, &(LoadedVertex) {
+ v3f32_add(cube_vertices[f][v].position, pos),
+ cube_vertices[f][v].normal,
+ voxel->color,
+ });
+ }
+}
+
+void mesh_load(Mesh *mesh, const char *path)
+{
+ mesh->layout = &loaded_layout;
+ mesh->vao = mesh->vbo = 0;
+ mesh->data = NULL;
+ mesh->count = 0;
+ mesh->free_data = true;
+
+ LoadedRenderArgs args;
+ tree_ini(&args.voxels);
+ array_ini(&args.vertices, sizeof(LoadedVertex), 500);
+
+ FILE *file = fopen(path, "r");
+ if (!file) {
+ fprintf(stderr, "[warning] failed to open mesh %s\n", path);
+ return;
+ }
+
+ char *line = NULL;
+ size_t siz = 0;
+ ssize_t length;
+ int count = 0;
+
+ while ((length = getline(&line, &siz, file)) > 0) {
+ count++;
+
+ if (*line == '#')
+ continue;
+
+ LoadedVoxel *voxel = malloc(sizeof *voxel);
+
+ v3s32 color;
+ if (sscanf(line, "%d %d %d %2x%2x%2x",
+ &voxel->pos.x, &voxel->pos.z, &voxel->pos.y,
+ &color.x, &color.y, &color.z) != 6) {
+ fprintf(stderr, "[warning] syntax error in mesh %s in line %d: %s\n",
+ path, count, line);
+ free(voxel);
+ continue;
+ }
+
+ voxel->color = (v3f32) {
+ (f32) color.x / 0xFF,
+ (f32) color.y / 0xFF,
+ (f32) color.z / 0xFF,
+ };
+
+ if (!tree_add(&args.voxels, &voxel->pos, voxel, &cmp_loaded_voxel, NULL)) {
+ fprintf(stderr, "[warning] more than one voxel at position (%d, %d, %d) in mesh %s in line %d\n",
+ voxel->pos.x, voxel->pos.y, voxel->pos.z, path, count);
+ free(voxel);
+ }
+ }
+
+ if (line)
+ free(line);
+
+ fclose(file);
+
+ tree_trv(&args.voxels, &render_loaded_voxel, &args, NULL, 0);
+ tree_clr(&args.voxels, &free, NULL, NULL, 0);
+
+ mesh->data = args.vertices.ptr;
+ mesh->count = args.vertices.siz;
+}
+
// upload data to GPU (only done once)
void mesh_upload(Mesh *mesh)
{
bool free_data;
} Mesh;
+void mesh_load(Mesh *mesh, const char *path);
void mesh_upload(Mesh *mesh);
void mesh_render(Mesh *mesh);
void mesh_destroy(Mesh *mesh);
if (!node->visible)
return;
+ if (node->clockwise) {
+ glFrontFace(GL_CW); GL_DEBUG
+ }
+
for (size_t i = 0; i < node->meshes.siz; i++) {
ModelMesh *mesh = &((ModelMesh *) node->meshes.ptr)[i];
+ if (!mesh->mesh)
+ continue;
+
glUseProgram(mesh->shader->prog); GL_DEBUG
glUniformMatrix4fv(mesh->shader->loc_transform, 1, GL_FALSE, node->abs[0]); GL_DEBUG
}
list_itr(&node->children, &render_node, NULL, NULL);
+
+ if (node->clockwise) {
+ glFrontFace(GL_CCW); GL_DEBUG
+ }
}
static void free_node_meshes(ModelNode *node)
cursor += n;
else
fprintf(stderr, "[warning] invalid value for rot in model %s in line %d\n", path, count);
+
+ node->rot = v3f32_scale(node->rot, M_PI / 180.0);
} else if (strcmp(key, "scale") == 0) {
if (sscanf(cursor, "%f %f %f %n", &node->scale.x, &node->scale.y, &node->scale.z, &n) == 3)
cursor += n;
else
fprintf(stderr, "[warning] invalid value for scale in model %s in line %d\n", path, count);
+ } else if (strcmp(key, "clockwise") == 0) {
+ node->clockwise = 1;
} else if (strcmp(key, "cube") == 0) {
char texture[length + 1];
{
ModelNode *node = malloc(sizeof *node);
node->name = NULL;
- node->visible = true;
+ node->visible = 1;
+ node->clockwise = 0;
node->pos = (v3f32) {0.0f, 0.0f, 0.0f};
node->rot = (v3f32) {0.0f, 0.0f, 0.0f};
node->scale = (v3f32) {1.0f, 1.0f, 1.0f};
typedef struct ModelNode {
char *name;
- bool visible;
v3f32 pos, rot, scale;
mat4x4 abs, rel;
Array meshes;
struct ModelNode *parent;
List children;
+ unsigned int visible: 1;
+ unsigned int clockwise: 1;
} ModelNode;
typedef struct {
if (*node == NODE_UNLOADED)
return false;
- if (client_node_definitions[*node].pointable)
+ if (client_node_defs[*node].pointable)
return true;
f64 vpos[3] = {pos.x, pos.y, pos.z};
--- /dev/null
+#define STB_IMAGE_WRITE_IMPLEMENTATION
+#include <GL/glew.h>
+#include <GL/gl.h>
+#include <stb/stb_image_write.h>
+#include <string.h>
+#include <time.h>
+#include "client/game.h"
+#include "client/gl_debug.h"
+#include "client/window.h"
+
+char *screenshot()
+{
+ // renderbuffer for depth & stencil buffer
+ GLuint rbo;
+ glGenRenderbuffers(1, &rbo); GL_DEBUG
+ glBindRenderbuffer(GL_RENDERBUFFER, rbo); GL_DEBUG
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_DEPTH24_STENCIL8, window.width, window.height); GL_DEBUG
+
+ // 2 textures, one with AA, one without
+
+ GLuint txos[2];
+ glGenTextures(2, txos); GL_DEBUG
+
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, txos[0]); GL_DEBUG
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 8, GL_RGB, window.width, window.height, GL_TRUE); GL_DEBUG
+
+ glBindTexture(GL_TEXTURE_2D, txos[1]); GL_DEBUG
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, window.width, window.height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); GL_DEBUG
+
+ // 2 framebuffers, one with AA, one without
+
+ GLuint fbos[2];
+ glGenFramebuffers(2, fbos); GL_DEBUG
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); GL_DEBUG
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, txos[0], 0); GL_DEBUG
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo); GL_DEBUG
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); GL_DEBUG
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, txos[1], 0); GL_DEBUG
+
+ // render scene
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[0]); GL_DEBUG
+ game_render(0.0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0); GL_DEBUG
+
+ // blit AA-buffer into no-AA buffer
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]); GL_DEBUG
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]); GL_DEBUG
+ glBlitFramebuffer(0, 0, window.width, window.height, 0, 0, window.width, window.height, GL_COLOR_BUFFER_BIT, GL_NEAREST); GL_DEBUG
+
+ // read data
+ GLubyte data[window.width * window.height * 3];
+ glBindFramebuffer(GL_FRAMEBUFFER, fbos[1]); GL_DEBUG
+ glPixelStorei(GL_PACK_ALIGNMENT, 1); GL_DEBUG
+ glReadPixels(0, 0, window.width, window.height, GL_RGB, GL_UNSIGNED_BYTE, data); GL_DEBUG
+
+ // create filename
+ char filename[BUFSIZ];
+ time_t timep = time(0);
+ strftime(filename, BUFSIZ, "screenshot-%Y-%m-%d-%H:%M:%S.png", localtime(&timep));
+
+ // save screenshot
+ stbi_flip_vertically_on_write(true);
+ stbi_write_png(filename, window.width, window.height, 3, data, window.width * 3);
+
+ // delete buffers
+ glDeleteRenderbuffers(1, &rbo); GL_DEBUG
+ glDeleteTextures(2, txos); GL_DEBUG
+ glDeleteFramebuffers(2, fbos); GL_DEBUG
+
+ return strdup(filename);
+}
--- /dev/null
+#ifndef _SCREENSHOT_H_
+#define _SCREENSHOT_H_
+
+char *screenshot();
+
+#endif // _SCREENSHOT_H_
#include "client/gl_debug.h"
#include "client/shader.h"
-static GLuint compile_shader(GLenum type, const char *path, const char *name, GLuint program, const char *definitions)
+static GLuint compile_shader(GLenum type, const char *path, const char *name, GLuint program, const char *defs)
{
char full_path[strlen(path) + 1 + strlen(name) + 1 + 4 + 1];
sprintf(full_path, "%s/%s.glsl", path, name);
const char *code_list[3] = {
version,
- definitions,
+ defs,
code,
};
int size_list[3] = {
18,
- strlen(definitions),
+ strlen(defs),
size,
};
return id;
}
-bool shader_program_create(const char *path, GLuint *idptr, const char *definitions)
+bool shader_program_create(const char *path, GLuint *idptr, const char *defs)
{
GLuint id = glCreateProgram(); GL_DEBUG
- if (!definitions)
- definitions = "";
+ if (!defs)
+ defs = "";
GLuint vert, frag;
- if (!(vert = compile_shader(GL_VERTEX_SHADER, path, "vertex", id, definitions))) {
+ if (!(vert = compile_shader(GL_VERTEX_SHADER, path, "vertex", id, defs))) {
glDeleteProgram(id); GL_DEBUG
return false;
}
- if (!(frag = compile_shader(GL_FRAGMENT_SHADER, path, "fragment", id, definitions))) {
+ if (!(frag = compile_shader(GL_FRAGMENT_SHADER, path, "fragment", id, defs))) {
glDeleteShader(vert); GL_DEBUG
glDeleteProgram(id); GL_DEBUG
return false;
#include <GL/gl.h>
#include <stdbool.h>
-bool shader_program_create(const char *path, GLuint *idptr, const char *definitions);
+bool shader_program_create(const char *path, GLuint *idptr, const char *defs);
#endif // _SHADER_H_
static inline bool cull_face(NodeType self, NodeType nbr)
{
- switch (client_node_definitions[self].visibility) {
+ switch (client_node_defs[self].visibility) {
case VISIBILITY_CLIP:
return false;
case VISIBILITY_SOLID:
return nbr == NODE_UNLOADED
- || client_node_definitions[nbr].visibility == VISIBILITY_SOLID;
+ || client_node_defs[nbr].visibility == VISIBILITY_SOLID;
default: // impossible
break;
args.node = &data->chunk->data[offset.x][offset.y][offset.z];
- ClientNodeDefinition *def = &client_node_definitions[args.node->type];
+ ClientNodeDef *def = &client_node_defs[args.node->type];
if (def->visibility == VISIBILITY_NONE)
return;
#define _WINDOW_H_
#include <GLFW/glfw3.h>
+#include <linmath.h/linmath.h>
+#include <stdbool.h>
+#include "types.h"
extern struct Window {
int width, height;
--- /dev/null
+#include <stdlib.h>
+#include "item.h"
+
+void item_stack_initialize(ItemStack *stack)
+{
+ stack->type = ITEM_NONE;
+ stack->count = 1;
+ stack->data = NULL;
+
+ if (item_defs[stack->type].create)
+ item_defs[stack->type].create(stack);
+}
+
+void item_stack_destroy(ItemStack *stack)
+{
+ if (item_defs[stack->type].delete)
+ item_defs[stack->type].delete(stack);
+
+ if (stack->data) {
+ free(stack->data);
+ stack->data = NULL;
+ }
+}
+
+void item_stack_set(ItemStack *stack, ItemType type, u32 count, Blob buffer)
+{
+ item_stack_destroy(stack);
+
+ stack->type = type;
+ stack->count = count;
+ stack->data = item_defs[stack->type].data_size > 0 ?
+ malloc(item_defs[stack->type].data_size) : NULL;
+
+ if (item_defs[stack->type].create)
+ item_defs[stack->type].create(stack);
+
+ if (item_defs[stack->type].deserialize)
+ item_defs[stack->type].deserialize(&buffer, stack->data);
+}
+
+void item_stack_serialize(ItemStack *stack, SerializedItemStack *serialized)
+{
+ serialized->type = stack->type;
+ serialized->count = stack->count;
+ serialized->data = (Blob) {0, NULL};
+
+ if (item_defs[stack->type].serialize)
+ item_defs[stack->type].serialize(&serialized->data, stack->data);
+}
+
+void item_stack_deserialize(ItemStack *stack, SerializedItemStack *serialized)
+{
+ ItemType type = serialized->type;
+
+ if (type >= COUNT_ITEM)
+ type = ITEM_UNKNOWN;
+
+ item_stack_set(stack, type, serialized->count, serialized->data);
+}
+
+ItemDef item_defs[COUNT_ITEM] = {
+ // unknown
+ {
+ .stackable = false,
+ .data_size = 0,
+ .create = NULL,
+ .delete = NULL,
+ .serialize = NULL,
+ .deserialize = NULL,
+ },
+ // none
+ {
+ .stackable = false,
+ .data_size = 0,
+ .create = NULL,
+ .delete = NULL,
+ .serialize = NULL,
+ .deserialize = NULL,
+ },
+ // pickaxe
+ {
+ .stackable = false,
+ .data_size = 0,
+ .create = NULL,
+ .delete = NULL,
+ .serialize = NULL,
+ .deserialize = NULL,
+ },
+ // axe
+ {
+ .stackable = false,
+ .data_size = 0,
+ .create = NULL,
+ .delete = NULL,
+ .serialize = NULL,
+ .deserialize = NULL,
+ },
+};
--- /dev/null
+#ifndef _ITEM_H_
+#define _ITEM_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include "types.h"
+
+typedef enum {
+ ITEM_UNKNOWN,
+ ITEM_NONE,
+ ITEM_PICKAXE,
+ ITEM_AXE,
+ COUNT_ITEM,
+} ItemType;
+
+typedef struct {
+ ItemType type;
+ u32 count; // i know future me is going to thank me for making it big
+ void *data;
+} ItemStack;
+
+typedef struct {
+ bool stackable;
+ size_t data_size;
+ void (*create)(ItemStack *stack);
+ void (*delete)(ItemStack *stack);
+ void (*serialize)(Blob *buffer, void *data);
+ void (*deserialize)(Blob *buffer, void *data);
+} ItemDef;
+
+void item_stack_initialize(ItemStack *stack);
+void item_stack_destroy(ItemStack *stack);
+
+void item_stack_set(ItemStack *stack, ItemType type, u32 count, Blob buffer);
+void item_stack_serialize(ItemStack *stack, SerializedItemStack *serialized);
+void item_stack_deserialize(ItemStack *stack, SerializedItemStack *serialized);
+
+extern ItemDef item_defs[];
+
+#endif // _ITEM_H_
#include "terrain.h"
#include "types.h"
-NodeDefinition node_definitions[NODE_UNLOADED] = {
+NodeDef node_defs[NODE_UNLOADED] = {
// unknown
{
.solid = true,
#include <stddef.h>
#include "types.h"
-#define NODE_DEFINITION(type) ((type) < NODE_UNLOADED ? &node_definitions[NODE_UNKNOWN] : &node_definitions[(type)]);
-
typedef enum {
NODE_UNKNOWN, // Used for unknown nodes received from server (caused by outdated clients)
NODE_AIR,
void (*delete)(struct TerrainNode *node);
void (*serialize)(Blob *buffer, void *data);
void (*deserialize)(Blob *buffer, void *data);
-} NodeDefinition;
+} NodeDef;
-extern NodeDefinition node_definitions[];
+extern NodeDef node_defs[];
#endif
static bool is_solid(Terrain *terrain, s32 x, s32 y, s32 z)
{
NodeType node = terrain_get_node(terrain, (v3s32) {x, y, z}).type;
- return node == NODE_UNLOADED || node_definitions[node].solid;
+ return node == NODE_UNLOADED || node_defs[node].solid;
}
bool physics_ground(Terrain *terrain, bool collide, aabb3f32 box, v3f64 *pos, v3f64 *vel)
#define _GNU_SOURCE // don't worry, GNU extensions are only used when available
#include <dragonnet/addr.h>
+#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
-#include <pthread.h>
+#include <time.h>
#include "interrupt.h"
#include "server/database.h"
#include "server/server.h"
server->on_recv_type[DRAGONNET_TYPE_ToServerPosRot ] = (void *) &on_ToServerPosRot;
server->on_recv_type[DRAGONNET_TYPE_ToServerRequestChunk] = (void *) &on_ToServerRequestChunk;
+ srand(time(0));
+
interrupt_init();
if (!database_init())
return EXIT_FAILURE;
});
}
-static void send_entity_remove(ServerPlayer *player, ServerPlayer *entity)
+static void send_entity_remove(ServerPlayer *client, ServerPlayer *entity)
{
- dragonnet_peer_send_ToClientEntityRemove(player->peer, &(ToClientEntityRemove) {
+ dragonnet_peer_send_ToClientEntityRemove(client->peer, &(ToClientEntityRemove) {
.id = entity->id,
});
}
-static void send_entity_update_pos_rot(ServerPlayer *player, ServerPlayer *entity)
+static void send_entity_update_pos_rot(ServerPlayer *client, ServerPlayer *entity)
{
- if (player != entity)
- dragonnet_peer_send_ToClientEntityUpdatePosRot(player->peer, &(ToClientEntityUpdatePosRot) {
+ if (client != entity)
+ dragonnet_peer_send_ToClientEntityUpdatePosRot(client->peer, &(ToClientEntityUpdatePosRot) {
.id = entity->id,
.pos = entity->pos,
.rot = entity->rot,
});
}
-static void send_entity_add_existing(ServerPlayer *entity, ServerPlayer *player)
+static void send_entity_add_existing(ServerPlayer *entity, ServerPlayer *client)
{
- if (player != entity) {
+ if (client != entity) {
pthread_rwlock_rdlock(&entity->lock_pos);
- send_entity_add(player, entity);
+ send_entity_add(client, entity);
pthread_rwlock_unlock(&entity->lock_pos);
}
}
+static void send_player_inventory(ServerPlayer *client, ServerPlayer *player)
+{
+ ToClientPlayerInventory pkt;
+ pkt.id = player->id;
+ item_stack_serialize(&player->inventory.left, &pkt.left);
+ item_stack_serialize(&player->inventory.right, &pkt.right);
+ dragonnet_peer_send_ToClientPlayerInventory(client->peer, &pkt);
+}
+
+static void send_player_inventory_existing(ServerPlayer *player, ServerPlayer *client)
+{
+ if (client != player) {
+ pthread_rwlock_rdlock(&player->lock_inv);
+ send_player_inventory(client, player);
+ pthread_rwlock_unlock(&player->lock_inv);
+ }
+}
+
// main thread
// called on server shutdown
static void player_drop(ServerPlayer *player)
pthread_rwlock_destroy(&player->lock_pos);
+ item_stack_destroy(&player->inventory.left);
+ item_stack_destroy(&player->inventory.right);
+ pthread_rwlock_destroy(&player->lock_inv);
+
free(player);
}
database_create_player(player->name, player->pos, player->rot);
}
+ item_stack_set(&player->inventory.left, ITEM_NONE + rand() % (ITEM_AXE - ITEM_NONE + 1), 1, (Blob) {0, NULL});
+ item_stack_set(&player->inventory.right, ITEM_NONE + rand() % (ITEM_AXE - ITEM_NONE + 1), 1, (Blob) {0, NULL});
+
// since this is recv thread, we don't need lock_peer
dragonnet_peer_send_ToClientInfo(player->peer, &(ToClientInfo) {
.seed = seed,
server_player_iterate(&send_entity_add, player);
server_player_iterate(&send_entity_add_existing, player);
+
+ server_player_iterate(&send_player_inventory, player);
+ server_player_iterate(&send_player_inventory_existing, player);
}
// any thread
player->rot = (v3f32) {0.0f, 0.0f, 0.0f};
pthread_rwlock_init(&player->lock_pos, NULL);
+ item_stack_initialize(&player->inventory.left);
+ item_stack_initialize(&player->inventory.right);
+ pthread_rwlock_init(&player->lock_inv, NULL);
+
printf("[access] connected %s\n", player->name);
peer->extra = refcount_grb(&player->rc);
#include <dragonstd/refcount.h>
#include <pthread.h>
#include <stdbool.h>
+#include "item.h"
#include "types.h"
typedef struct {
v3f64 pos; // player position
v3f32 rot; // you wont guess what this is
pthread_rwlock_t lock_pos; // git commit crime
+
+ struct {
+ ItemStack left;
+ ItemStack right;
+ } inventory;
+ pthread_rwlock_t lock_inv;
} ServerPlayer;
void server_player_init();
pos.y++;
}
- if (node_definitions[node].solid)
+ if (node_defs[node].solid)
break;
server_terrain_gen_node(pos,
node = NODE_SNOW;
if (generate_args.diff == 1) for (int i = 0; i < NUM_TREES; i++) {
- TreeDef *def = &tree_definitions[i];
+ TreeDef *def = &tree_defs[i];
if (def->condition(&condition_args)
&& noise2d(condition_args.pos.x, condition_args.pos.z, 0, seed + def->offset) * 0.5 + 0.5 < def->probability
voxel_procedural_delete(proc);
}
-TreeDef tree_definitions[NUM_TREES] = {
+TreeDef tree_defs[NUM_TREES] = {
// oak
{
.spread = 64.0f,
void (*generate)(v3s32 pos, List *changed_chunks);
} TreeDef;
-extern TreeDef tree_definitions[];
+extern TreeDef tree_defs[];
#endif // _TREES_H_
},
};
- NodeDefinition *def = &node_definitions[node->type];
+ NodeDef *def = &node_defs[node->type];
if (def->serialize)
def->serialize(&node_data->data, node->data);
if (type >= NODE_UNLOADED)
type = NODE_UNKNOWN;
- NodeDefinition *def = &node_definitions[type];
+ NodeDef *def = &node_defs[type];
TerrainNode node;
node.type = type;
void terrain_node_delete(TerrainNode node)
{
- NodeDefinition *def = &node_definitions[node.type];
+ NodeDef *def = &node_defs[node.type];
if (def->delete)
def->delete(&node);
v3f32 rot
String nametag
+SerializedItemStack
+ u32 type
+ u32 count
+ Blob data
+
; server packets
pkt ToServerAuth
pkt ToClientEntityUpdateNametag
u64 id
String nametag
+
+pkt ToClientPlayerInventory
+ u64 id
+ SerializedItemStack left
+ SerializedItemStack right