Drastic code reduction, now handled by the C++ module
parent
f7a7ab404e
commit
e9e9522bd6
|
@ -0,0 +1,160 @@
|
||||||
|
|
||||||
|
class _Base:
|
||||||
|
var _noise = OsnNoise.new()
|
||||||
|
func _init():
|
||||||
|
_noise.set_seed(131183)
|
||||||
|
|
||||||
|
|
||||||
|
class Flat extends _Base:
|
||||||
|
func generate(voxels, offset):
|
||||||
|
if offset.y <= 0:
|
||||||
|
voxels.fill(1)
|
||||||
|
|
||||||
|
class Grid extends _Base:
|
||||||
|
var step = 4
|
||||||
|
|
||||||
|
func generate(voxels, offset):
|
||||||
|
|
||||||
|
for z in range(0, voxels.get_size_z()):
|
||||||
|
for x in range(0, voxels.get_size_x()):
|
||||||
|
for y in range(0, voxels.get_size_y()):
|
||||||
|
|
||||||
|
var v = 0
|
||||||
|
|
||||||
|
if (y/step)%2 == 0:
|
||||||
|
if (x/step)%2 == 0:
|
||||||
|
if (z/step)%2 == 0:
|
||||||
|
v = 1
|
||||||
|
else:
|
||||||
|
if (z/step)%2 != 0:
|
||||||
|
v = 1
|
||||||
|
else:
|
||||||
|
if (x/step)%2 == 0:
|
||||||
|
if (z/step)%2 != 0:
|
||||||
|
v = 1
|
||||||
|
else:
|
||||||
|
if (z/step)%2 == 0:
|
||||||
|
v = 1
|
||||||
|
|
||||||
|
voxels.set_voxel(v, x,y,z)
|
||||||
|
|
||||||
|
|
||||||
|
class Heightmap extends _Base:
|
||||||
|
func generate(voxels, offset):
|
||||||
|
var ox = offset.x
|
||||||
|
var oy = offset.y
|
||||||
|
var oz = offset.z
|
||||||
|
var empty = true
|
||||||
|
var ns1 = 0.01
|
||||||
|
var ns2 = 0.05
|
||||||
|
|
||||||
|
var dirt = 1
|
||||||
|
if oy < 0:
|
||||||
|
dirt = 2
|
||||||
|
|
||||||
|
var bs = voxels.get_size_x()
|
||||||
|
|
||||||
|
var noise1 = OsnFractalNoise.new()
|
||||||
|
noise1.set_source_noise(_noise)
|
||||||
|
noise1.set_period(128)
|
||||||
|
noise1.set_octaves(4)
|
||||||
|
|
||||||
|
for z in range(0, bs):
|
||||||
|
for x in range(0, bs):
|
||||||
|
|
||||||
|
var h = 16.0 * noise1.get_noise_2d(ox+x, oz+z) - oy
|
||||||
|
|
||||||
|
if h >= 0:
|
||||||
|
if h < bs:
|
||||||
|
empty = false
|
||||||
|
for y in range(0, h):
|
||||||
|
voxels.set_voxel(dirt, x,y,z)
|
||||||
|
#voxels[z][y][x] = dirt
|
||||||
|
for y in range(h, bs):
|
||||||
|
voxels.set_voxel(0, x,y,z)
|
||||||
|
#voxels[z][y][x] = air
|
||||||
|
# if oy == -BLOCK_SIZE:
|
||||||
|
# voxels[z][bs-1][x] = 0
|
||||||
|
# if oy >= 0 and randf() < 0.2:
|
||||||
|
# voxels[z][h][x] = 2
|
||||||
|
# if randf() < 0.01:
|
||||||
|
# var th = h+1+randi()%8
|
||||||
|
# if th > bs:
|
||||||
|
# th = bs
|
||||||
|
# for y in range(h, th):
|
||||||
|
# voxels[z][y][x] = 3
|
||||||
|
else:
|
||||||
|
empty = false
|
||||||
|
for y in range(0, bs):
|
||||||
|
voxels.set_voxel(dirt, x,y,z)
|
||||||
|
else:
|
||||||
|
for y in range(0, bs):
|
||||||
|
voxels.set_voxel(0, x,y,z)
|
||||||
|
|
||||||
|
return empty
|
||||||
|
|
||||||
|
|
||||||
|
class Volume extends _Base:
|
||||||
|
func generate(voxels, offset):
|
||||||
|
var ox = offset.x
|
||||||
|
var oy = offset.y
|
||||||
|
var oz = offset.z
|
||||||
|
var empty = true
|
||||||
|
var bs = voxels.get_size_x()
|
||||||
|
|
||||||
|
var noise1 = OsnFractalNoise.new()
|
||||||
|
noise1.set_source_noise(_noise)
|
||||||
|
noise1.set_period(100)
|
||||||
|
noise1.set_octaves(4)
|
||||||
|
|
||||||
|
var dirt = 1
|
||||||
|
if oy < 0:
|
||||||
|
dirt = 2
|
||||||
|
|
||||||
|
for z in range(0, bs):
|
||||||
|
for x in range(0, bs):
|
||||||
|
for y in range(0, bs):
|
||||||
|
var gy = y+oy
|
||||||
|
var h = noise1.get_noise_3d(x+ox+2, gy, z+oz)
|
||||||
|
if h < 1-gy*0.01 - 1:
|
||||||
|
voxels.set_voxel(dirt, x, y, z)
|
||||||
|
empty = false
|
||||||
|
else:
|
||||||
|
if gy < 0:
|
||||||
|
voxels.set_voxel(4, x, y, z)
|
||||||
|
else:
|
||||||
|
voxels.set_voxel(0, x, y, z)
|
||||||
|
empty = false
|
||||||
|
|
||||||
|
return empty
|
||||||
|
|
||||||
|
|
||||||
|
class Test extends _Base:
|
||||||
|
func generate(voxels, offset):
|
||||||
|
voxels.set_voxel(1, 1,1,1)
|
||||||
|
|
||||||
|
voxels.set_voxel(1, 3,1,1)
|
||||||
|
voxels.set_voxel(1, 3,1,2)
|
||||||
|
|
||||||
|
voxels.set_voxel(1, 5,1,1)
|
||||||
|
voxels.set_voxel(1, 5,1,2)
|
||||||
|
voxels.set_voxel(1, 5,2,1)
|
||||||
|
|
||||||
|
voxels.set_voxel(1, 8,1,1)
|
||||||
|
voxels.set_voxel(1, 8,2,1)
|
||||||
|
voxels.set_voxel(1, 7,1,1)
|
||||||
|
|
||||||
|
voxels.set_voxel(1, 11,1,1)
|
||||||
|
voxels.set_voxel(1, 11,2,1)
|
||||||
|
voxels.set_voxel(1, 10,1,1)
|
||||||
|
voxels.set_voxel(1, 10,1,2)
|
||||||
|
|
||||||
|
for x in range(4,7):
|
||||||
|
for z in range(4,7):
|
||||||
|
voxels.set_voxel(1, x, 2, z)
|
||||||
|
voxels.set_voxel(1, x+5, 2, z)
|
||||||
|
voxels.set_voxel(1, 5,3,5)
|
||||||
|
voxels.set_voxel(1, 5,1,5)
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
|
||||||
|
extends MeshInstance
|
||||||
|
|
||||||
|
var step = 16
|
||||||
|
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
|
||||||
|
var st = SurfaceTool.new()
|
||||||
|
|
||||||
|
st.begin(Mesh.PRIMITIVE_LINES)
|
||||||
|
|
||||||
|
st.add_color(Color(0,0,0))
|
||||||
|
|
||||||
|
var r = 4
|
||||||
|
var rv = 4 * step
|
||||||
|
|
||||||
|
for i in range(-r, r):
|
||||||
|
for j in range(-r, r):
|
||||||
|
|
||||||
|
var x = i * step
|
||||||
|
var y = j * step
|
||||||
|
|
||||||
|
st.add_vertex(Vector3(x, -rv, y))
|
||||||
|
st.add_vertex(Vector3(x, rv, y))
|
||||||
|
|
||||||
|
st.add_vertex(Vector3(x, y, -rv))
|
||||||
|
st.add_vertex(Vector3(x, y, rv))
|
||||||
|
|
||||||
|
st.add_vertex(Vector3(-rv, x, y))
|
||||||
|
st.add_vertex(Vector3(rv, x, y))
|
||||||
|
|
||||||
|
var mesh = st.commit()
|
||||||
|
set_mesh(mesh)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#func _add_wireframe_cube(st, pos):
|
||||||
|
#
|
||||||
|
# st.add_vertex(pos)
|
||||||
|
# st.add_vertex(pos + Vector3(step, 0, 0))
|
||||||
|
#
|
||||||
|
# st.add_vertex(pos + Vector3(step, 0, 0))
|
||||||
|
# st.add_vertex(pos + Vector3(step, 0, step))
|
||||||
|
#
|
||||||
|
# st.add_vertex(pos + Vector3(step, 0, step))
|
||||||
|
# st.add_vertex(pos + Vector3(0, 0, step))
|
||||||
|
#
|
||||||
|
# st.add_vertex(pos + Vector3(0, 0, step))
|
||||||
|
# st.add_vertex(pos)
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# st.add_vertex(pos + Vector3(0, step, 0))
|
||||||
|
# st.add_vertex(pos + Vector3(step, step, 0))
|
||||||
|
#
|
||||||
|
# st.add_vertex(pos + Vector3(step, step, 0))
|
||||||
|
# st.add_vertex(pos + Vector3(step, step, step))
|
||||||
|
#
|
||||||
|
# st.add_vertex(pos + Vector3(step, step, step))
|
||||||
|
# st.add_vertex(pos + Vector3(0, step, step))
|
||||||
|
#
|
||||||
|
# st.add_vertex(pos + Vector3(0, step, step))
|
||||||
|
# st.add_vertex(pos + Vector3(0, step, 0))
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# st.add_vertex(pos)
|
||||||
|
# st.add_vertex(pos + Vector3(0, step, 0))
|
||||||
|
#
|
||||||
|
# st.add_vertex(pos + Vector3(step, 0, 0))
|
||||||
|
# st.add_vertex(pos + Vector3(step, step, 0))
|
||||||
|
#
|
||||||
|
# st.add_vertex(pos + Vector3(step, 0, step))
|
||||||
|
# st.add_vertex(pos + Vector3(step, step, step))
|
||||||
|
#
|
||||||
|
# st.add_vertex(pos + Vector3(0, 0, step))
|
||||||
|
# st.add_vertex(pos + Vector3(0, step, step))
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
# member variables here, example:
|
||||||
|
# var a=2
|
||||||
|
# var b="textvar"
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _on_Node_pressed():
|
||||||
|
get_tree().change_scene("res://new_scene.tscn")
|
|
@ -0,0 +1,22 @@
|
||||||
|
[gd_scene load_steps=2 format=1]
|
||||||
|
|
||||||
|
[ext_resource path="res://launcher.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="Node" type="Button"]
|
||||||
|
|
||||||
|
focus/ignore_mouse = false
|
||||||
|
focus/stop_mouse = true
|
||||||
|
size_flags/horizontal = 2
|
||||||
|
size_flags/vertical = 2
|
||||||
|
margin/left = 66.0
|
||||||
|
margin/top = 116.0
|
||||||
|
margin/right = 394.0
|
||||||
|
margin/bottom = 156.0
|
||||||
|
toggle_mode = false
|
||||||
|
text = "Start"
|
||||||
|
flat = false
|
||||||
|
script/script = ExtResource( 1 )
|
||||||
|
|
||||||
|
[connection signal="pressed" from="." to="." method="_on_Node_pressed"]
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
[gd_scene load_steps=7 format=1]
|
[gd_scene load_steps=8 format=1]
|
||||||
|
|
||||||
[ext_resource path="res://debug_camera.gd" type="Script" id=1]
|
[ext_resource path="res://debug_camera.gd" type="Script" id=1]
|
||||||
[ext_resource path="res://voxel_map.gd" type="Script" id=2]
|
[ext_resource path="res://voxel_map.gd" type="Script" id=2]
|
||||||
[ext_resource path="res://terrain.png" type="Texture" id=3]
|
[ext_resource path="res://terrain.png" type="Texture" id=3]
|
||||||
|
[ext_resource path="res://grid.gd" type="Script" id=4]
|
||||||
|
|
||||||
[sub_resource type="FixedMaterial" id=1]
|
[sub_resource type="FixedMaterial" id=1]
|
||||||
|
|
||||||
|
@ -214,7 +215,7 @@ phase_2/color = Color( 0, 0, 0, 1 )
|
||||||
phase_3/pos = 1.0
|
phase_3/pos = 1.0
|
||||||
phase_3/color = Color( 0, 0, 0, 1 )
|
phase_3/color = Color( 0, 0, 0, 1 )
|
||||||
|
|
||||||
[node name="VoxelMap" type="Node" parent="."]
|
[node name="VoxelTerrain" type="VoxelTerrain" parent="."]
|
||||||
|
|
||||||
script/script = ExtResource( 2 )
|
script/script = ExtResource( 2 )
|
||||||
solid_material = SubResource( 1 )
|
solid_material = SubResource( 1 )
|
||||||
|
@ -249,4 +250,25 @@ shadow/max_distance = 32.0
|
||||||
shadow/split_weight = 0.5
|
shadow/split_weight = 0.5
|
||||||
shadow/zoffset_scale = 2.0
|
shadow/zoffset_scale = 2.0
|
||||||
|
|
||||||
|
[node name="Grid" type="MeshInstance" parent="."]
|
||||||
|
|
||||||
|
_import_transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )
|
||||||
|
layers = 1
|
||||||
|
geometry/visible = true
|
||||||
|
geometry/material_override = null
|
||||||
|
geometry/cast_shadow = 1
|
||||||
|
geometry/receive_shadows = true
|
||||||
|
geometry/range_begin = 0.0
|
||||||
|
geometry/range_end = 0.0
|
||||||
|
geometry/extra_cull_margin = 0.0
|
||||||
|
geometry/billboard = false
|
||||||
|
geometry/billboard_y = false
|
||||||
|
geometry/depth_scale = false
|
||||||
|
geometry/visible_in_all_rooms = false
|
||||||
|
geometry/use_baked_light = false
|
||||||
|
geometry/baked_light_tex_id = 0
|
||||||
|
mesh/mesh = null
|
||||||
|
mesh/skeleton = NodePath("..")
|
||||||
|
script/script = ExtResource( 4 )
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,426 +1,36 @@
|
||||||
|
|
||||||
# Infinite terrain of voxels.
|
extends VoxelTerrain
|
||||||
# Voxels are divided in blocks in all directions (like octants in Gridmap).
|
|
||||||
# It is a lot faster than Gridmap because geometry is merged in one mesh per block.
|
|
||||||
# Voxels are usually cubes, but they can of any shape (see voxel_type.gd).
|
|
||||||
# One thread is used to generate and bake geometry.
|
|
||||||
|
|
||||||
# TODO Immerge blocks that are too far away (they currently flood the memory at some point)
|
|
||||||
# TODO Voxel edition
|
|
||||||
# TODO Physics
|
|
||||||
# TODO Generate structures (trees, caves, old buildings... everything that is not made of a single voxel)
|
|
||||||
# TODO Move data crunching to a C++ module for faster generation and mesh baking
|
|
||||||
# TODO Ambient occlusion with vertex colors
|
|
||||||
# TODO Import .obj to voxel types
|
|
||||||
# TODO Move to a 2D Chunk-based generation system? More convenient for terrains (but keep Blocks for graphics)
|
|
||||||
|
|
||||||
extends Node
|
|
||||||
|
|
||||||
const BLOCK_SIZE = 16
|
|
||||||
const SORT_TIME = 1
|
|
||||||
#const TILE_SIZE = 16
|
|
||||||
|
|
||||||
export(Material) var solid_material = null
|
export(Material) var solid_material = null
|
||||||
export(Material) var transparent_material = null
|
export(Material) var transparent_material = null
|
||||||
var view_radius = 4
|
|
||||||
var min_y = -4
|
|
||||||
var max_y = 4
|
|
||||||
|
|
||||||
var _blocks = {}
|
|
||||||
var _generating_blocks = {}
|
|
||||||
#var _chunks = {}
|
|
||||||
|
|
||||||
var _pending_blocks = []
|
|
||||||
var _thread = Thread.new()
|
|
||||||
var _time_before_sort = SORT_TIME
|
|
||||||
var _camera = null
|
|
||||||
var _voxel_types = []
|
|
||||||
var _priority_positions = []
|
|
||||||
var _outer_positions = []
|
|
||||||
var _precalc_neighboring = []
|
|
||||||
|
|
||||||
var _noise = OsnNoise.new()
|
|
||||||
var _mesh_builder = VoxelMeshBuilder.new()
|
|
||||||
var _library = VoxelLibrary.new()
|
var _library = VoxelLibrary.new()
|
||||||
|
var _generator = null
|
||||||
|
|
||||||
class Block:
|
|
||||||
var voxel_map = null
|
|
||||||
var voxels = VoxelBuffer.new()
|
|
||||||
var pos = Vector3(0,0,0)
|
|
||||||
var mesh = null
|
|
||||||
var node = null
|
|
||||||
var gen_time = 0
|
|
||||||
var has_generated = false
|
|
||||||
var has_structures = false
|
|
||||||
var need_update = false
|
|
||||||
|
|
||||||
func _init():
|
|
||||||
voxels.create(BLOCK_SIZE+2,BLOCK_SIZE+2,BLOCK_SIZE+2)
|
|
||||||
|
|
||||||
func is_generated():
|
|
||||||
return has_generated and has_structures
|
|
||||||
|
|
||||||
func is_surrounded():
|
|
||||||
var blocks = voxel_map._blocks
|
|
||||||
var ngb = voxel_map._precalc_neighboring
|
|
||||||
for v in ngb:
|
|
||||||
if not blocks.has(pos + v):
|
|
||||||
return false
|
|
||||||
return false
|
|
||||||
|
|
||||||
func get_ground_y(x,z):
|
|
||||||
var types = voxel_map._voxel_types
|
|
||||||
for y in range(BLOCK_SIZE-1, 0, -1):
|
|
||||||
if not types[voxels[z][y][x]].is_transparent:
|
|
||||||
return y
|
|
||||||
return 0
|
|
||||||
|
|
||||||
func local_to_map(vpos):
|
|
||||||
return vpos + pos * BLOCK_SIZE
|
|
||||||
|
|
||||||
|
|
||||||
class BlockRequest:
|
|
||||||
const TYPE_GENERATE = 0
|
|
||||||
const TYPE_UPDATE = 0
|
|
||||||
|
|
||||||
var type = 0
|
|
||||||
var block_pos = Vector3(0,0,0)
|
|
||||||
|
|
||||||
func _init(pos, type=TYPE_GENERATE):
|
|
||||||
self.block_pos = pos
|
|
||||||
self.type = type
|
|
||||||
|
|
||||||
|
|
||||||
#class Chunk:
|
|
||||||
# var heightmap = []
|
|
||||||
#
|
|
||||||
# func _init():
|
|
||||||
# heightmap.resize(BLOCK_SIZE+2)
|
|
||||||
# for y in range(0, heightmap.size()):
|
|
||||||
# var line = []
|
|
||||||
# line.resize(BLOCK_SIZE+2)
|
|
||||||
# heightmap[y] = line
|
|
||||||
# for x in range(0, line.size()):
|
|
||||||
# line[x] = 0
|
|
||||||
|
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
_noise.set_seed(131183)
|
var gen = preload("generator.gd")
|
||||||
|
_generator = gen.Heightmap.new()
|
||||||
|
|
||||||
_library.set_atlas_size(4)
|
_library.set_atlas_size(4)
|
||||||
|
|
||||||
_camera = get_parent().get_node("Camera")
|
|
||||||
|
|
||||||
_load_voxel_types()
|
|
||||||
_precalculate_priority_positions()
|
|
||||||
_precalculate_neighboring()
|
|
||||||
_update_pending_blocks()
|
|
||||||
|
|
||||||
set_process(true)
|
|
||||||
|
|
||||||
|
|
||||||
func _precalculate_neighboring():
|
|
||||||
for z in range(-1, 2):
|
|
||||||
for y in range(-1, 2):
|
|
||||||
for x in range(-1, 2):
|
|
||||||
if x != 0 and y != 0 and z != 0:
|
|
||||||
_precalc_neighboring.append(Vector3(x,y,z))
|
|
||||||
|
|
||||||
|
|
||||||
func _load_voxel_types():
|
|
||||||
_library.create_voxel(0, "air").set_transparent()
|
_library.create_voxel(0, "air").set_transparent()
|
||||||
_library.create_voxel(1, "grass_dirt").set_cube_geometry().set_cube_uv_tbs_sides(Vector2(0,0), Vector2(0,1), Vector2(1,0))
|
_library.create_voxel(1, "grass_dirt").set_cube_geometry().set_cube_uv_tbs_sides(Vector2(0,0), Vector2(0,1), Vector2(1,0))
|
||||||
_library.create_voxel(2, "dirt").set_cube_geometry().set_cube_uv_all_sides(Vector2(1,0))
|
_library.create_voxel(2, "dirt").set_cube_geometry().set_cube_uv_all_sides(Vector2(1,0))
|
||||||
_library.create_voxel(3, "log").set_cube_geometry().set_cube_uv_tbs_sides(Vector2(3,0), Vector2(3,0), Vector2(2,0))
|
_library.create_voxel(3, "log").set_cube_geometry().set_cube_uv_tbs_sides(Vector2(3,0), Vector2(3,0), Vector2(2,0))
|
||||||
_library.create_voxel(4, "water").set_transparent().set_cube_geometry(15.0/16.0).set_cube_uv_all_sides(Vector2(2,1)).set_material_id(1)
|
_library.create_voxel(4, "water").set_transparent().set_cube_geometry(15.0/16.0).set_cube_uv_all_sides(Vector2(2,1)).set_material_id(1)
|
||||||
|
|
||||||
_mesh_builder.set_library(_library)
|
var mesher = get_mesher()
|
||||||
_mesh_builder.set_material(solid_material, 0)
|
mesher.set_library(_library)
|
||||||
_mesh_builder.set_material(transparent_material, 1)
|
mesher.set_material(solid_material, 0)
|
||||||
|
mesher.set_material(transparent_material, 1)
|
||||||
|
|
||||||
func _precalculate_priority_positions():
|
force_load_blocks(Vector3(0,0,0), Vector3(8,3,8))
|
||||||
_priority_positions.clear()
|
|
||||||
for z in range(-view_radius, view_radius):
|
|
||||||
for x in range(-view_radius, view_radius):
|
|
||||||
for y in range(min_y, max_y):
|
|
||||||
_priority_positions.append(Vector3(x,y,z))
|
|
||||||
_priority_positions.sort_custom(self, "_compare_priority_positions")
|
|
||||||
|
|
||||||
|
|
||||||
func _compare_priority_positions(a, b):
|
|
||||||
return a.length_squared() > b.length_squared()
|
|
||||||
|
|
||||||
|
|
||||||
func set_voxel(pos, id):
|
|
||||||
# This function only works if the block exists and is surrounded
|
|
||||||
|
|
||||||
var bpos = Vector3(floor(pos.x/BLOCK_SIZE), floor(pos.y/BLOCK_SIZE), floor(pos.z/BLOCK_SIZE))
|
|
||||||
var block = _blocks[bpos]
|
|
||||||
var rx = pos.x%BLOCK_SIZE
|
|
||||||
var ry = pos.y%BLOCK_SIZE
|
|
||||||
var rz = pos.z%BLOCK_SIZE
|
|
||||||
block.voxels[rz+1][ry+1][rx+1] = id
|
|
||||||
block.need_update = true
|
|
||||||
|
|
||||||
# TODO The following is not needed if the meshing process could just take copies with neighboring,
|
|
||||||
# So we don't need to keep boundaries information for all the lifetime of blocks
|
|
||||||
|
|
||||||
if rx == 0:
|
|
||||||
var nblock = _blocks[bpos-Vector3(1,0,0)]
|
|
||||||
nblock.voxels[BLOCK_SIZE+1][ry+1][rx+1] = id
|
|
||||||
nblock.need_update = true
|
|
||||||
elif rx == BLOCK_SIZE-1:
|
|
||||||
var nblock = _blocks[bpos+Vector3(1,0,0)]
|
|
||||||
nblock.voxels[0][ry+1][rx+1] = id
|
|
||||||
nblock.need_update = true
|
|
||||||
|
|
||||||
if ry == 0:
|
|
||||||
var nblock = _blocks[bpos-Vector3(0,1,0)]
|
|
||||||
nblock.voxels[rx+1][BLOCK_SIZE+1][rx+1] = id
|
|
||||||
nblock.need_update = true
|
|
||||||
elif ry == BLOCK_SIZE-1:
|
|
||||||
var nblock = _blocks[bpos+Vector3(0,1,0)]
|
|
||||||
nblock.voxels[rx+1][0][rx+1] = id
|
|
||||||
nblock.need_update = true
|
|
||||||
|
|
||||||
if rz == 0:
|
|
||||||
var nblock = _blocks[bpos-Vector3(0,0,1)]
|
|
||||||
nblock.voxels[rz+1][ry+1][BLOCK_SIZE+1] = id
|
|
||||||
nblock.need_update = true
|
|
||||||
elif rz == BLOCK_SIZE-1:
|
|
||||||
var nblock = _blocks[bpos+Vector3(0,0,1)]
|
|
||||||
nblock.voxels[rx+1][ry+1][0] = id
|
|
||||||
nblock.need_update = true
|
|
||||||
|
|
||||||
|
|
||||||
func _update_pending_blocks():
|
|
||||||
# Using pre-sorted relative vectors is faster than sorting the list directly
|
|
||||||
var camera_block_pos = _camera.get_translation() / BLOCK_SIZE
|
|
||||||
camera_block_pos.x = floor(camera_block_pos.x)
|
|
||||||
camera_block_pos.y = 0#floor(camera_block_pos.y)
|
|
||||||
camera_block_pos.z = floor(camera_block_pos.z)
|
|
||||||
_pending_blocks.clear()
|
|
||||||
for rpos in _priority_positions:
|
|
||||||
var pos = rpos + camera_block_pos
|
|
||||||
if pos.y >= min_y and pos.y < max_y and not _generating_blocks.has(pos):
|
|
||||||
if not _blocks.has(pos):
|
|
||||||
_pending_blocks.append(pos)
|
|
||||||
# else:
|
|
||||||
# var block = _blocks[pos]
|
|
||||||
# if block.need_update:
|
|
||||||
# # TODO update mesh
|
|
||||||
# elif not block.has_structures and block.is_surrounded():
|
|
||||||
# # TODO generate structures
|
|
||||||
|
|
||||||
|
|
||||||
func _process(delta):
|
|
||||||
|
|
||||||
# TODO Immerge blocks that are too far away
|
|
||||||
|
|
||||||
if _time_before_sort > 0:
|
|
||||||
_time_before_sort -= delta
|
|
||||||
if _time_before_sort <= 0:
|
|
||||||
_time_before_sort = SORT_TIME
|
|
||||||
_update_pending_blocks()
|
|
||||||
|
|
||||||
if _pending_blocks.size() != 0:
|
|
||||||
if not _thread.is_active():
|
|
||||||
|
|
||||||
# Closer blocks are loaded first
|
|
||||||
var pos = _pending_blocks[_pending_blocks.size()-1]
|
|
||||||
_pending_blocks.pop_back()
|
|
||||||
_generating_blocks[pos] = true
|
|
||||||
var arg = BlockRequest.new(pos, BlockRequest.TYPE_GENERATE)
|
|
||||||
#_thread.start(self, "generate_block_thread", arg)
|
|
||||||
#print("generate " + str(pos))
|
|
||||||
spawn_block(generate_block(arg.block_pos))
|
|
||||||
|
|
||||||
# Visible blocks are loaded first
|
|
||||||
# var hbs = Vector3(0.5, 0.5, 0.5) * BLOCK_SIZE
|
|
||||||
# for i in range(_pending_blocks.size()-1, 0, -1):
|
|
||||||
# var pos = _pending_blocks[i]
|
|
||||||
# var wpos = pos*BLOCK_SIZE + hbs
|
|
||||||
# if not _camera.is_position_behind(wpos):
|
|
||||||
# _pending_blocks[i] = _pending_blocks[_pending_blocks.size()-1]
|
|
||||||
# _pending_blocks.pop_back()
|
|
||||||
# _thread.start(self, "generate_block_thread", pos)
|
|
||||||
# break
|
|
||||||
|
|
||||||
|
|
||||||
func generate_block_thread(request):
|
|
||||||
if request.type == BlockRequest.TYPE_GENERATE:
|
|
||||||
var block = generate_block(request.block_pos)
|
|
||||||
# Call the main thread to wait
|
|
||||||
call_deferred("thread_finished")
|
|
||||||
#_generating_blocks.erase(block.pos) # Enable only without thread!
|
|
||||||
return block
|
|
||||||
else:
|
|
||||||
print("Unknown request type " + str(request.type))
|
|
||||||
|
|
||||||
|
|
||||||
func thread_finished():
|
|
||||||
var block = _thread.wait_to_finish()
|
|
||||||
_generating_blocks.erase(block.pos)
|
|
||||||
spawn_block(block)
|
|
||||||
|
|
||||||
|
|
||||||
func generate_block(pos):
|
|
||||||
var time_before = OS.get_ticks_msec()
|
|
||||||
|
|
||||||
var block = Block.new()
|
|
||||||
block.pos = pos
|
|
||||||
|
|
||||||
#time_before = OS.get_ticks_msec()
|
|
||||||
var empty = generate_3d(block.voxels, pos * BLOCK_SIZE)
|
|
||||||
#print("Generate: " + str(OS.get_ticks_msec() - time_before) + "ms")
|
|
||||||
|
|
||||||
var mesh = null
|
|
||||||
if empty:
|
|
||||||
block.voxels = null
|
|
||||||
else:
|
|
||||||
#time_before = OS.get_ticks_msec()
|
|
||||||
mesh = _mesh_builder.build(block.voxels)
|
|
||||||
#print("Bake: " + str(OS.get_ticks_msec() - time_before) + "ms")
|
|
||||||
|
|
||||||
block.voxel_map = self
|
|
||||||
block.mesh = mesh
|
|
||||||
block.gen_time = OS.get_ticks_msec() - time_before
|
|
||||||
|
|
||||||
return block
|
|
||||||
|
|
||||||
|
|
||||||
func spawn_block(block):
|
|
||||||
if block.mesh != null:
|
|
||||||
var mesh_instance = preload("res://block.tscn").instance()
|
|
||||||
mesh_instance.set_translation(block.pos * BLOCK_SIZE)
|
|
||||||
mesh_instance.spawn()
|
|
||||||
mesh_instance.set_mesh(block.mesh)
|
|
||||||
mesh_instance.voxel_map = self
|
|
||||||
add_child(mesh_instance)
|
|
||||||
block.node = mesh_instance
|
|
||||||
_blocks[block.pos] = block
|
|
||||||
#print("Gen time: " + str(block.gen_time) + " (empty=" + str(block.mesh == null) + ")")
|
|
||||||
|
|
||||||
|
|
||||||
func generate_test(cubes, offset):
|
|
||||||
cubes.set_voxel(1, 1,1,1)
|
|
||||||
|
|
||||||
cubes.set_voxel(1, 3,1,1)
|
|
||||||
cubes.set_voxel(1, 3,1,2)
|
|
||||||
|
|
||||||
cubes.set_voxel(1, 5,1,1)
|
|
||||||
cubes.set_voxel(1, 5,1,2)
|
|
||||||
cubes.set_voxel(1, 5,2,1)
|
|
||||||
|
|
||||||
cubes.set_voxel(1, 8,1,1)
|
|
||||||
cubes.set_voxel(1, 8,2,1)
|
|
||||||
cubes.set_voxel(1, 7,1,1)
|
|
||||||
|
|
||||||
cubes.set_voxel(1, 11,1,1)
|
|
||||||
cubes.set_voxel(1, 11,2,1)
|
|
||||||
cubes.set_voxel(1, 10,1,1)
|
|
||||||
cubes.set_voxel(1, 10,1,2)
|
|
||||||
|
|
||||||
for x in range(4,7):
|
|
||||||
for z in range(4,7):
|
|
||||||
cubes.set_voxel(1, x, 2, z)
|
|
||||||
cubes.set_voxel(1, x+5, 2, z)
|
|
||||||
cubes.set_voxel(1, 5,3,5)
|
|
||||||
cubes.set_voxel(1, 5,1,5)
|
|
||||||
|
|
||||||
return false
|
|
||||||
|
|
||||||
|
|
||||||
func generate_3d(cubes, offset):
|
|
||||||
var ox = offset.x
|
|
||||||
var oy = offset.y
|
|
||||||
var oz = offset.z
|
|
||||||
var empty = true
|
|
||||||
var bs = cubes.get_size_x()
|
|
||||||
|
|
||||||
var noise1 = OsnFractalNoise.new()
|
|
||||||
noise1.set_source_noise(_noise)
|
|
||||||
noise1.set_period(100)
|
|
||||||
noise1.set_octaves(4)
|
|
||||||
|
|
||||||
var dirt = 1
|
|
||||||
if oy < 0:
|
|
||||||
dirt = 2
|
|
||||||
|
|
||||||
for z in range(0, bs):
|
|
||||||
for x in range(0, bs):
|
|
||||||
for y in range(0, bs):
|
|
||||||
var gy = y+oy
|
|
||||||
var h = noise1.get_noise_3d(x+ox+2, gy, z+oz)
|
|
||||||
if h < 1-gy*0.01 - 1:
|
|
||||||
cubes.set_voxel(dirt, x, y, z)
|
|
||||||
empty = false
|
|
||||||
else:
|
|
||||||
if gy < 0:
|
|
||||||
cubes.set_voxel(4, x, y, z)
|
|
||||||
else:
|
|
||||||
cubes.set_voxel(0, x, y, z)
|
|
||||||
empty = false
|
|
||||||
|
|
||||||
return empty
|
|
||||||
|
|
||||||
|
|
||||||
func generate_heightmap(cubes, offset):
|
|
||||||
var ox = offset.x
|
|
||||||
var oy = offset.y
|
|
||||||
var oz = offset.z
|
|
||||||
var empty = true
|
|
||||||
var ns1 = 0.01
|
|
||||||
var ns2 = 0.05
|
|
||||||
|
|
||||||
var dirt = 1
|
|
||||||
if oy < 0:
|
|
||||||
dirt = 2
|
|
||||||
|
|
||||||
var bs = cubes.get_size_x()
|
|
||||||
|
|
||||||
var noise1 = OsnFractalNoise.new()
|
|
||||||
noise1.set_source_noise(_noise)
|
|
||||||
noise1.set_period(128)
|
|
||||||
noise1.set_octaves(4)
|
|
||||||
|
|
||||||
for z in range(0, bs):
|
|
||||||
for x in range(0, bs):
|
|
||||||
|
|
||||||
var h = 16.0 * noise1.get_noise_2d(ox+x, oz+z) - oy
|
|
||||||
|
|
||||||
if h >= 0:
|
|
||||||
if h < bs:
|
|
||||||
empty = false
|
|
||||||
for y in range(0, h):
|
|
||||||
cubes.set_voxel(dirt, x,y,z)
|
|
||||||
#cubes[z][y][x] = dirt
|
|
||||||
for y in range(h, bs):
|
|
||||||
cubes.set_voxel(0, x,y,z)
|
|
||||||
#cubes[z][y][x] = air
|
|
||||||
# if oy == -BLOCK_SIZE:
|
|
||||||
# cubes[z][bs-1][x] = 0
|
|
||||||
# if oy >= 0 and randf() < 0.2:
|
|
||||||
# cubes[z][h][x] = 2
|
|
||||||
# if randf() < 0.01:
|
|
||||||
# var th = h+1+randi()%8
|
|
||||||
# if th > bs:
|
|
||||||
# th = bs
|
|
||||||
# for y in range(h, th):
|
|
||||||
# cubes[z][y][x] = 3
|
|
||||||
else:
|
|
||||||
empty = false
|
|
||||||
for y in range(0, bs):
|
|
||||||
cubes.set_voxel(dirt, x,y,z)
|
|
||||||
else:
|
|
||||||
for y in range(0, bs):
|
|
||||||
cubes.set_voxel(0, x,y,z)
|
|
||||||
|
|
||||||
return empty
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# TODO option to execute this method in a thread
|
||||||
|
func _generate_block(voxels, block_pos):
|
||||||
|
#print("Generating block " + str(block_pos))
|
||||||
|
var offset = block_to_voxel(block_pos)
|
||||||
|
_generator.generate(voxels, offset)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue