From 499cfe84efc9a6f28e487acf4432e4e47eaddb30 Mon Sep 17 00:00:00 2001 From: kayomn Date: Fri, 27 Jan 2023 15:49:56 +0000 Subject: [PATCH] Clean up MeshGrid logic --- map_editor.scn | 4 +-- mesh_grid.gd | 78 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/map_editor.scn b/map_editor.scn index d597e3d..108fd93 100644 --- a/map_editor.scn +++ b/map_editor.scn @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b8de9c0cb07eadedbfd24cfa384a72d55c4f44d26665163e8de8e147d97e5df9 -size 9103 +oid sha256:8e1b8150dd960e318a4d296f32ea0a7e28445a0a64eac5471a56e31ffda78a5f +size 9102 diff --git a/mesh_grid.gd b/mesh_grid.gd index 950e0ae..de70774 100644 --- a/mesh_grid.gd +++ b/mesh_grid.gd @@ -5,33 +5,33 @@ const _CHUNK_SIZE := 32 const _GRID_ORIGIN := Vector2(0.5, 0.5) ## -## +## Baked block of meshes making up a segment of the grid. ## class Chunk: - var multimesh_instances: Array[MultiMeshInstance] = [] + var _multimesh_instances: Array[MultiMeshInstance] = [] - var meshes: Array[Mesh] = [] + var _meshes: Array[Mesh] = [] func _init() -> void: - meshes.resize(_CHUNK_SIZE * _CHUNK_SIZE) + _meshes.resize(_CHUNK_SIZE * _CHUNK_SIZE) ## - ## + ## Invalidates the mesh block, re-baking its contents from the current mesh data set. ## func invalidate(mesh_grid: MeshGrid, coordinate: Vector2i) -> void: # TODO: Once this is all lowered into native code, look for ways to parallelize the loops. - for multimesh_instance in multimesh_instances: + for multimesh_instance in _multimesh_instances: RenderingServer.free_rid(multimesh_instance._instance_rid) RenderingServer.free_rid(multimesh_instance._multimesh_rid) - multimesh_instances.clear() - + _multimesh_instances.clear() + # Normalize mesh instance data for the chunk. var transforms_by_mesh := {} var grid_size := mesh_grid.size - for i in meshes.size(): - var mesh := meshes[i] + for i in _meshes.size(): + var mesh := _meshes[i] if mesh != null: if not(mesh in transforms_by_mesh): @@ -43,7 +43,7 @@ class Chunk: (float(coordinate.y * _CHUNK_SIZE) + (i / _CHUNK_SIZE)) - (float(grid_size.y) * _GRID_ORIGIN.y)))) - # Bake into multimesh instances for the chunk. + # (Re)-bake into multimesh instances for the chunk. var scenario_rid := mesh_grid.get_world_3d().scenario var global_transform := mesh_grid.global_transform @@ -52,16 +52,20 @@ class Chunk: scenario_rid, chunk_mesh.get_rid(), transforms_by_mesh[chunk_mesh]) multimesh_instance.set_offset(global_transform) - multimesh_instances.append(multimesh_instance) + _multimesh_instances.append(multimesh_instance) ## + ## Sets the mesh location in the chunk at the relative [code]coordinatess[/code] to + ## [code]mesh[/code]. ## + ## *Note* that [method Chunk.invalidate] must be called at some point after to visually update + ## the chunk. ## - func set_mesh(coordinate: Vector2i, mesh: Mesh) -> void: - meshes[(_CHUNK_SIZE * coordinate.y) + coordinate.x] = mesh + func set_mesh(coordinates: Vector2i, mesh: Mesh) -> void: + _meshes[(_CHUNK_SIZE * coordinates.y) + coordinates.x] = mesh ## -## +## Specialized multi-mesh instance convenience for use within the mesh grid and its chunks. ## class MultiMeshInstance: var _instance_rid := RID() @@ -83,7 +87,7 @@ class MultiMeshInstance: RenderingServer.multimesh_instance_set_transform(_multimesh_rid, i, transforms[i]) ## - ## + ## Sets the parent transform of all mesh instances under it to [code]offset[/code]. ## func set_offset(offset: Transform3D) -> void: RenderingServer.instance_set_transform(_instance_rid, offset) @@ -93,7 +97,7 @@ var _chunks: Array[Chunk] = [] var _chunks_size := Vector2i.ZERO ## -## +## Size of the mesh grid (in engine units). ## @export var size: Vector2i: @@ -108,6 +112,9 @@ var size: Vector2i: _chunks_size = Vector2i((value / float(_CHUNK_SIZE)).ceil()) size = value +func _get_area() -> Rect2i: + return Rect2i(Vector2i.ZERO, size) + func _get_chunk(chunk_coordinate: Vector2i) -> Chunk: return _chunks[(_chunks_size.x * chunk_coordinate.y) + chunk_coordinate.x] @@ -115,11 +122,15 @@ func _notification(what: int) -> void: match what: NOTIFICATION_TRANSFORM_CHANGED: for chunk in _chunks: - for multimesh_instance in chunk.multimesh_instances: + for multimesh_instance in chunk._multimesh_instances: multimesh_instance.set_offset_transform(global_transform) ## +## Clears the entire mesh grid to only contain [code]mesh[/code]. ## +## [code]null[/code] may be past to [code]mesh[/code] for clearing the mesh grid to nothing. +## +## For clearing a specific region of the mesh grid, see [method fill_mesh]. ## func clear_mesh(mesh: Mesh) -> void: for y in size.y: @@ -135,10 +146,18 @@ func clear_mesh(mesh: Mesh) -> void: _get_chunk(chunk_coordinate).invalidate(self, chunk_coordinate) ## +## Clears the region of the mesh grid at [code]area[/code] to only contain [code]mesh[/code]. ## +## [code]null[/code] may be past to [code]mesh[/code] for filling the region to nothing. +## +## *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- +## right. +## +## For clearing the whole of the mesh grid, see [method clear_mesh]. ## func fill_mesh(area: Rect2i, mesh: Mesh) -> void: - assert(Rect2i(Vector2i.ZERO, size).encloses(area), "area must be within grid") + assert(_get_area().encloses(area), "area must be within grid") var filled_chunks := BitMap.new() @@ -160,16 +179,25 @@ func fill_mesh(area: Rect2i, mesh: Mesh) -> void: _get_chunk(chunk_coordinate).invalidate(self, chunk_coordinate) ## +## Plots a single mesh at [code]coordinates[/code] to be [code]mesh[/code], overwriting whatever it +## previously contained. ## +## [code]null[/code] may be past to [code]mesh[/code] for clearing the mesh grid to nothing. ## -func plot_mesh(coordinate: Vector2i, mesh: Mesh) -> void: - assert(Rect2i(Vector2i.ZERO, size).has_point(coordinate), "coordinate must be within grid") +## *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- +## right. +## +## For bulk-setting many meshes at once, see [method fill_mesh] and [method clear_mesh]. +## +func plot_mesh(coordinates: Vector2i, mesh: Mesh) -> void: + assert(_get_area().has_point(coordinates), "coordinate must be within grid") - var chunk_coordinate := coordinate / _CHUNK_SIZE - var chunk := _get_chunk(chunk_coordinate) + var chunk_coordinates := coordinates / _CHUNK_SIZE + var chunk := _get_chunk(chunk_coordinates) - chunk.set_mesh(coordinate % _CHUNK_SIZE, mesh) - chunk.invalidate(self, chunk_coordinate) + chunk.set_mesh(coordinates % _CHUNK_SIZE, mesh) + chunk.invalidate(self, chunk_coordinates) ## ## Returns [code]world_position[/code] converted into a coordinate aligned with the [MeshGrid].