66 lines
2.2 KiB
GDScript
66 lines
2.2 KiB
GDScript
class_name M2PlacementGrouper
|
|
extends RefCounted
|
|
|
|
## Stateless ADT M2 placement validation, normalization and transform grouping.
|
|
|
|
const M2_PLACEMENT_TRANSFORM_RESOLVER_SCRIPT := preload(
|
|
"res://src/render/m2/m2_placement_transform_resolver.gd"
|
|
)
|
|
|
|
|
|
## Groups valid placements by normalized relative M2 path while preserving
|
|
## placement order inside each group. Returned containers are caller-owned.
|
|
func group_placements(
|
|
tile_origin: Vector3,
|
|
m2_names: PackedStringArray,
|
|
m2_placements: Array
|
|
) -> Dictionary:
|
|
var groups: Dictionary = {}
|
|
var placement_transform_resolver := (
|
|
M2_PLACEMENT_TRANSFORM_RESOLVER_SCRIPT.new()
|
|
)
|
|
for placement_variant in m2_placements:
|
|
if not (placement_variant is Dictionary):
|
|
continue
|
|
var placement: Dictionary = placement_variant
|
|
var name_id: int = int(placement.get("name_id", -1))
|
|
if name_id < 0 or name_id >= m2_names.size():
|
|
continue
|
|
|
|
var normalized_relative_path := _normalize_relative_path(m2_names[name_id])
|
|
if normalized_relative_path.is_empty():
|
|
continue
|
|
|
|
var world_position: Vector3 = placement.get("pos", Vector3.ZERO)
|
|
var local_position := world_position - tile_origin
|
|
var rotation_radians: Vector3 = placement.get("rot", Vector3.ZERO)
|
|
var scale_value := float(placement.get("scale", 1.0))
|
|
var placement_basis: Basis = placement_transform_resolver.resolve_basis(
|
|
rotation_radians,
|
|
normalized_relative_path
|
|
)
|
|
var origin_offset: Vector3 = placement_transform_resolver.resolve_origin_offset(
|
|
rotation_radians,
|
|
normalized_relative_path,
|
|
scale_value
|
|
)
|
|
var local_transform := Transform3D(
|
|
placement_basis.scaled(Vector3.ONE * maxf(scale_value, 0.0001)),
|
|
local_position + origin_offset
|
|
)
|
|
|
|
if not groups.has(normalized_relative_path):
|
|
groups[normalized_relative_path] = []
|
|
(groups[normalized_relative_path] as Array).append(local_transform)
|
|
return groups
|
|
|
|
|
|
func _normalize_relative_path(relative_path: String) -> String:
|
|
var normalized_relative_path := relative_path.replace("\\", "/")
|
|
if (
|
|
normalized_relative_path.ends_with(".mdx")
|
|
or normalized_relative_path.ends_with(".mdl")
|
|
):
|
|
normalized_relative_path = normalized_relative_path.get_basename() + ".m2"
|
|
return normalized_relative_path
|