WIP: Streamline Interiors System #16
|
@ -43,62 +43,34 @@ class Chunk:
|
||||||
|
|
||||||
var _interior_map: InteriorMap = null
|
var _interior_map: InteriorMap = null
|
||||||
|
|
||||||
var _meshes_by_floor_tile: Array[Mesh] = []
|
var _renderables_by_mesh := {}
|
||||||
|
|
||||||
var _renderable_by_floor_tile: Array[Renderable] = []
|
|
||||||
|
|
||||||
func _init(interior_map: InteriorMap, coordinates: Vector2i) -> void:
|
func _init(interior_map: InteriorMap, coordinates: Vector2i) -> void:
|
||||||
_interior_map = interior_map
|
_interior_map = interior_map
|
||||||
_coordinates = coordinates
|
_coordinates = coordinates
|
||||||
|
|
||||||
var floor_tile_count := FloorTile.size()
|
|
||||||
|
|
||||||
_renderable_by_floor_tile.resize(floor_tile_count)
|
|
||||||
_meshes_by_floor_tile.resize(floor_tile_count)
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## Invalidates the mesh block, re-baking its contents from the current mesh data set.
|
## Invalidates the mesh block, re-baking its contents from the current mesh data set.
|
||||||
##
|
##
|
||||||
func invalidate() -> void:
|
func invalidate() -> void:
|
||||||
_renderable_by_floor_tile.fill(null)
|
_renderables_by_mesh.clear()
|
||||||
|
|
||||||
var interior_floor := _interior_map.interior_floor
|
var floor_map := _interior_map._floor_map
|
||||||
|
var map_size := _interior_map.size
|
||||||
|
var offset := _coordinates * _CHUNK_SIZE
|
||||||
|
var positions_by_mesh := {}
|
||||||
|
var map_area := Rect2i(Vector2.ZERO, map_size)
|
||||||
|
|
||||||
if interior_floor == null:
|
for y in _CHUNK_SIZE:
|
||||||
_meshes_by_floor_tile.fill(null)
|
var map_row_offset := (map_size.y * y)
|
||||||
|
|
||||||
else:
|
for x in _CHUNK_SIZE:
|
||||||
_meshes_by_floor_tile[FloorTile.CORNER_NORTH_EAST] = interior_floor.corner_north_east_mesh
|
var map_coordinates := offset + Vector2i(x, y)
|
||||||
_meshes_by_floor_tile[FloorTile.CORNER_NORTH_WEST] = interior_floor.corner_north_west_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.CORNER_SOUTH_EAST] = interior_floor.corner_south_east_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.CORNER_SOUTH_WEST] = interior_floor.corner_south_west_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.EDGE_EAST] = interior_floor.edge_east_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.EDGE_NORTH] = interior_floor.edge_north_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.EDGE_SOUTH] = interior_floor.edge_south_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.EDGE_WEST] = interior_floor.edge_west_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.ENDCAP_EAST] = interior_floor.endcap_east_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.ENDCAP_NORTH] = interior_floor.endcap_north_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.ENDCAP_SOUTH] = interior_floor.endcap_south_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.ENDCAP_WEST] = interior_floor.endcap_west_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.FILL] = interior_floor.fill_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.ISLAND] = interior_floor.island_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.PATH_HORIZONTAL] = interior_floor.path_horizontal_mesh
|
|
||||||
_meshes_by_floor_tile[FloorTile.PATH_VERTICAL] = interior_floor.path_vertical_mesh
|
|
||||||
|
|
||||||
var floor_map := _interior_map._floor_map
|
if map_area.has_point(map_coordinates):
|
||||||
var map_size := _interior_map.size
|
var interior_floor := floor_map[map_row_offset + map_coordinates.x]
|
||||||
var offset := _coordinates * _CHUNK_SIZE
|
|
||||||
var positions_by_floor_tile: Array[PackedVector2Array] = []
|
|
||||||
|
|
||||||
positions_by_floor_tile.resize(FloorTile.size())
|
if interior_floor != null:
|
||||||
|
|
||||||
# Find floor tile types.
|
|
||||||
for y in _CHUNK_SIZE:
|
|
||||||
for x in _CHUNK_SIZE:
|
|
||||||
var map_area := Rect2i(Vector2.ZERO, map_size)
|
|
||||||
var map_coordinates := offset + Vector2i(x, y)
|
|
||||||
|
|
||||||
if map_area.has_point(map_coordinates) and floor_map.get_bitv(map_coordinates):
|
|
||||||
var tile := 0
|
var tile := 0
|
||||||
|
|
||||||
for i in Orientation.values().size():
|
for i in Orientation.values().size():
|
||||||
|
@ -106,42 +78,61 @@ class Chunk:
|
||||||
roundi(cos(i * PI / 2.0)), roundi(sin(i * PI / 2.0)))
|
roundi(cos(i * PI / 2.0)), roundi(sin(i * PI / 2.0)))
|
||||||
|
|
||||||
if map_area.has_point(map_neighbor):
|
if map_area.has_point(map_neighbor):
|
||||||
tile += int(floor_map.get_bitv(map_neighbor)) * 2 ** i
|
tile += int(floor_map[(map_size.y * map_neighbor.y) + map_neighbor.x] == interior_floor) * 2 ** i
|
||||||
|
|
||||||
positions_by_floor_tile[tile].append(Vector2(x, y))
|
var mesh: Mesh = null
|
||||||
|
|
||||||
# (Re)-bake tiles into multimesh instances for the chunk.
|
match tile:
|
||||||
var scenario_rid := _interior_map.get_world_3d().scenario
|
FloorTile.ISLAND: mesh = interior_floor.island_mesh
|
||||||
|
FloorTile.ENDCAP_WEST: mesh = interior_floor.endcap_west_mesh
|
||||||
|
FloorTile.ENDCAP_NORTH: mesh = interior_floor.endcap_north_mesh
|
||||||
|
FloorTile.CORNER_NORTH_WEST: mesh = interior_floor.corner_north_west_mesh
|
||||||
|
FloorTile.ENDCAP_EAST: mesh = interior_floor.endcap_east_mesh
|
||||||
|
FloorTile.PATH_HORIZONTAL: mesh = interior_floor.path_horizontal_mesh
|
||||||
|
FloorTile.CORNER_NORTH_EAST: mesh = interior_floor.corner_north_east_mesh
|
||||||
|
FloorTile.EDGE_NORTH: mesh = interior_floor.edge_north_mesh
|
||||||
|
FloorTile.ENDCAP_SOUTH: mesh = interior_floor.endcap_south_mesh
|
||||||
|
FloorTile.CORNER_SOUTH_WEST: mesh = interior_floor.corner_south_west_mesh
|
||||||
|
FloorTile.PATH_VERTICAL: mesh = interior_floor.path_vertical_mesh
|
||||||
|
FloorTile.EDGE_WEST: mesh = interior_floor.edge_west_mesh
|
||||||
|
FloorTile.CORNER_SOUTH_EAST: mesh = interior_floor.corner_south_east_mesh
|
||||||
|
FloorTile.EDGE_SOUTH: mesh = interior_floor.edge_south_mesh
|
||||||
|
FloorTile.EDGE_EAST: mesh = interior_floor.edge_east_mesh
|
||||||
|
FloorTile.FILL: mesh = interior_floor.fill_mesh
|
||||||
|
|
||||||
for i in FloorTile.size():
|
if mesh != null:
|
||||||
var floor_positions := positions_by_floor_tile[i]
|
if not(mesh in positions_by_mesh):
|
||||||
|
positions_by_mesh[mesh] = PackedVector2Array()
|
||||||
|
|
||||||
if not(floor_positions.is_empty()):
|
positions_by_mesh[mesh].append(Vector2(x, y))
|
||||||
var mesh := _meshes_by_floor_tile[i]
|
|
||||||
|
|
||||||
if mesh != null:
|
# (Re)-bake tiles into multimesh instances for the chunk.
|
||||||
var floor_position_count := floor_positions.size()
|
var scenario_rid := _interior_map.get_world_3d().scenario
|
||||||
var renderable := Renderable.new(scenario_rid, _meshes_by_floor_tile[i].get_rid(), floor_position_count)
|
|
||||||
|
|
||||||
for j in floor_position_count:
|
for mesh in positions_by_mesh:
|
||||||
var tile_position := floor_positions[j]
|
var positions: PackedVector2Array = positions_by_mesh[mesh]
|
||||||
|
|
||||||
renderable.set_instance_transform(j, Transform3D(Basis.IDENTITY, Vector3(
|
if not(positions.is_empty()):
|
||||||
((float(offset.x) + tile_position.x) - (float(map_size.x) * _GRID_ORIGIN.x)) + 0.5,
|
var position_count := positions.size()
|
||||||
0.0,
|
var renderable := Renderable.new(scenario_rid, mesh.get_rid(), position_count)
|
||||||
((float(offset.y) + tile_position.y) - (float(map_size.y) * _GRID_ORIGIN.y)) + 0.5)))
|
|
||||||
|
|
||||||
_renderable_by_floor_tile[i] = renderable
|
for i in position_count:
|
||||||
|
var position := positions[i]
|
||||||
|
|
||||||
|
renderable.set_instance_transform(i, Transform3D(Basis.IDENTITY, Vector3(
|
||||||
|
((float(offset.x) + position.x) - (float(map_size.x) * _GRID_ORIGIN.x)) + 0.5,
|
||||||
|
0.0,
|
||||||
|
((float(offset.y) + position.y) - (float(map_size.y) * _GRID_ORIGIN.y)) + 0.5)))
|
||||||
|
|
||||||
|
_renderables_by_mesh[mesh] = renderable
|
||||||
|
|
||||||
func set_transform(transform: Transform3D) -> void:
|
func set_transform(transform: Transform3D) -> void:
|
||||||
for renderable in _renderable_by_floor_tile:
|
for mesh in _renderables_by_mesh:
|
||||||
if renderable != null:
|
_renderables_by_mesh[mesh].set_transform(transform)
|
||||||
renderable.set_transform(transform)
|
|
||||||
|
|
||||||
func set_visible(visible: bool) -> void:
|
func set_visible(visible: bool) -> void:
|
||||||
for renderable in _renderable_by_floor_tile:
|
for mesh in _renderables_by_mesh:
|
||||||
if renderable != null:
|
_renderables_by_mesh[mesh].set_visible(visible)
|
||||||
renderable.set_visible(visible)
|
|
||||||
|
|
||||||
##
|
##
|
||||||
##
|
##
|
||||||
|
@ -188,13 +179,7 @@ var _chunks: Array[Chunk] = []
|
||||||
|
|
||||||
var _chunks_size := Vector2i.ZERO
|
var _chunks_size := Vector2i.ZERO
|
||||||
|
|
||||||
var _floor_map := BitMap.new()
|
var _floor_map: Array[InteriorFloor] = []
|
||||||
|
|
||||||
##
|
|
||||||
##
|
|
||||||
##
|
|
||||||
@export
|
|
||||||
var interior_floor: InteriorFloor = null
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## Size of the tile grid (in engine units).
|
## Size of the tile grid (in engine units).
|
||||||
|
@ -204,7 +189,7 @@ var size: Vector2i:
|
||||||
set(value):
|
set(value):
|
||||||
_chunks_size = Vector2i((value / float(_CHUNK_SIZE)).ceil())
|
_chunks_size = Vector2i((value / float(_CHUNK_SIZE)).ceil())
|
||||||
|
|
||||||
_floor_map.resize(value)
|
_floor_map.resize(value.x * value.y)
|
||||||
_chunks.resize(_chunks_size.x * _chunks_size.y)
|
_chunks.resize(_chunks_size.x * _chunks_size.y)
|
||||||
|
|
||||||
for y in _chunks_size.y:
|
for y in _chunks_size.y:
|
||||||
|
@ -233,9 +218,8 @@ func _notification(what: int) -> void:
|
||||||
## For clearing a specific region of the mesh grid, see [method fill_mesh].
|
## For clearing a specific region of the mesh grid, see [method fill_mesh].
|
||||||
##
|
##
|
||||||
func clear() -> void:
|
func clear() -> void:
|
||||||
for y in size.y:
|
for i in _floor_map.size():
|
||||||
for x in size.x:
|
_floor_map[i] = null
|
||||||
_floor_map.set_bit(x, y, false)
|
|
||||||
|
|
||||||
for y in _chunks_size.y:
|
for y in _chunks_size.y:
|
||||||
for x in _chunks_size.x:
|
for x in _chunks_size.x:
|
||||||
|
@ -243,7 +227,7 @@ func clear() -> void:
|
||||||
|
|
||||||
##
|
##
|
||||||
## Clears the region of the tile grid at [code]area[/code] to only contain instances of
|
## Clears the region of the tile grid at [code]area[/code] to only contain instances of
|
||||||
## [code]tile[/code] pointing in the orientation of [code]orientation[/code].
|
## [code]interior_floor[/code].
|
||||||
##
|
##
|
||||||
## *Note* that [code]area[/code] *must* be within the area of the of the mesh grid, where
|
## *Note* that [code]area[/code] *must* be within the area of the of the mesh grid, where
|
||||||
## [code]Vector2i.ZERO[/code] is the top-left and [member size] [code]- 1[/code] is the bottom-
|
## [code]Vector2i.ZERO[/code] is the top-left and [member size] [code]- 1[/code] is the bottom-
|
||||||
|
@ -251,7 +235,7 @@ func clear() -> void:
|
||||||
##
|
##
|
||||||
## For clearing the whole of the mesh grid, see [method clear_mesh].
|
## For clearing the whole of the mesh grid, see [method clear_mesh].
|
||||||
##
|
##
|
||||||
func fill_floor(area: Rect2i, exists: bool) -> void:
|
func fill_floor(area: Rect2i, interior_floor: InteriorFloor) -> void:
|
||||||
assert(Rect2i(Vector2i.ZERO, size).encloses(area), "area must be within grid")
|
assert(Rect2i(Vector2i.ZERO, size).encloses(area), "area must be within grid")
|
||||||
|
|
||||||
var filled_chunks := BitMap.new()
|
var filled_chunks := BitMap.new()
|
||||||
|
@ -260,8 +244,7 @@ func fill_floor(area: Rect2i, exists: bool) -> void:
|
||||||
|
|
||||||
for y in range(area.position.y, area.end.y):
|
for y in range(area.position.y, area.end.y):
|
||||||
for x in range(area.position.x, area.end.x):
|
for x in range(area.position.x, area.end.x):
|
||||||
_floor_map.set_bit(x, y, exists)
|
_floor_map[(size.y * (y / _CHUNK_SIZE)) + (x / _CHUNK_SIZE)] = interior_floor
|
||||||
filled_chunks.set_bitv(Vector2i(x, y) / _CHUNK_SIZE, true)
|
|
||||||
|
|
||||||
for y in _chunks_size.y:
|
for y in _chunks_size.y:
|
||||||
for x in _chunks_size.x:
|
for x in _chunks_size.x:
|
||||||
|
@ -269,8 +252,8 @@ func fill_floor(area: Rect2i, exists: bool) -> void:
|
||||||
_get_chunk(Vector2i(x, y)).invalidate()
|
_get_chunk(Vector2i(x, y)).invalidate()
|
||||||
|
|
||||||
##
|
##
|
||||||
## Plots a single tile at [code]coordinates[/code] to be an instance of [code]tile[/code] pointing
|
## Plots a single tile at [code]coordinates[/code] to be an instance of [code]interior_floor[/code],
|
||||||
## in the orientation of [code]orientation[/code], overwriting whatever it previously contained.
|
## overwriting whatever it previously contained.
|
||||||
##
|
##
|
||||||
## *Note* that [code]coordinates[/code] *must* be within the area of the of the mesh grid, where
|
## *Note* that [code]coordinates[/code] *must* be within the area of the of the mesh grid, where
|
||||||
## [code]Vector2i.ZERO[/code] is the top-left and [member size] [code]- 1[/code] is the bottom-
|
## [code]Vector2i.ZERO[/code] is the top-left and [member size] [code]- 1[/code] is the bottom-
|
||||||
|
@ -278,7 +261,9 @@ func fill_floor(area: Rect2i, exists: bool) -> void:
|
||||||
##
|
##
|
||||||
## For bulk-setting many meshes at once, see [method fill_mesh] and [method clear_mesh].
|
## For bulk-setting many meshes at once, see [method fill_mesh] and [method clear_mesh].
|
||||||
##
|
##
|
||||||
func plot_floor(coordinates: Vector2i, exists: bool) -> void:
|
func plot_floor(coordinates: Vector2i, interior_floor: InteriorFloor) -> void:
|
||||||
assert(Rect2i(Vector2i.ZERO, size).has_point(coordinates), "coordinate must be within grid")
|
assert(Rect2i(Vector2i.ZERO, size).has_point(coordinates), "coordinate must be within grid")
|
||||||
_floor_map.set_bitv(coordinates, exists)
|
|
||||||
|
_floor_map[(size.y * coordinates.y) + coordinates.x] = interior_floor
|
||||||
|
|
||||||
_get_chunk(coordinates / _CHUNK_SIZE).invalidate()
|
_get_chunk(coordinates / _CHUNK_SIZE).invalidate()
|
||||||
|
|
BIN
map_editor.scn (Stored with Git LFS)
BIN
map_editor.scn (Stored with Git LFS)
Binary file not shown.
Loading…
Reference in New Issue