diff --git a/Entities/GroundTile/GroundTile.tscn b/Entities/GroundTile/GroundTile.tscn index 37e6239..cd4bf43 100644 --- a/Entities/GroundTile/GroundTile.tscn +++ b/Entities/GroundTile/GroundTile.tscn @@ -11,8 +11,7 @@ viewport_path = NodePath("DebugText/DebugTextViewport") [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_f37ob"] -albedo_color = Color(0.133333, 0.576471, 0.47451, 1) -metallic = 1.0 +albedo_color = Color(0.196078, 0.392157, 0.196078, 1) [sub_resource type="PlaneMesh" id="PlaneMesh_oqd8f"] @@ -30,6 +29,7 @@ flip_faces = true script = ExtResource("1_uwxqs") [node name="DebugText" type="Node3D" parent="."] +visible = false [node name="DebugTextViewport" type="SubViewport" parent="DebugText"] size = Vector2i(50, 50) diff --git a/Entities/GroundTile/ground_tile.gd b/Entities/GroundTile/ground_tile.gd index 2e67574..86f29b5 100644 --- a/Entities/GroundTile/ground_tile.gd +++ b/Entities/GroundTile/ground_tile.gd @@ -9,6 +9,9 @@ var cell_info: CellDataResource = null var spawners_ready: bool = false var cached_rng: RandomClass = null +# 326432 229379 +# Grass - 1a7761 1f6051 + func _ready() -> void: spawners_ready = true diff --git a/Entities/GroundTile/scripts/trees.gd b/Entities/GroundTile/scripts/trees.gd index 929b62b..9743906 100644 --- a/Entities/GroundTile/scripts/trees.gd +++ b/Entities/GroundTile/scripts/trees.gd @@ -65,50 +65,11 @@ func spawn_tree_at_position(pos: Vector3, tree_resource: TreeDataResource): # Pass the TreeDataResource to the Tree instance if tree_instance.has_method("set_tree_data"): tree_instance.set_tree_data(tree_resource) - elif tree_instance.has_method("setup_tree"): - tree_instance.setup_tree(tree_resource) else: - Log.pr("Tree instance doesn't have set_tree_data() or setup_tree() method") + Log.pr("Tree instance doesn't have set_tree_data() method") func is_position_valid(pos: Vector3) -> bool: for existing_pos in spawned_positions: if pos.distance_to(existing_pos) < min_distance: return false return true - -# Alternative method that shuffles trees for more random placement -func spawn_trees_shuffled(cell_info: CellDataResource): - if not cell_info: - return - - if not parent_ground_tile: - return - - # Clear existing trees - for child in get_children(): - child.free() - spawned_positions.clear() - - # Create a copy and shuffle for random placement order - var trees_to_spawn = cell_info.trees.duplicate() - trees_to_spawn.shuffle() - - var spawned_count = 0 - var attempts = 0 - var max_attempts = trees_to_spawn.size() * 10 - - for tree_resource in trees_to_spawn: - if attempts >= max_attempts: - Log.pr("Reached max attempts, could only spawn %d of %d trees" % [spawned_count, trees_to_spawn.size()]) - break - - var pos = get_random_position() - - if is_position_valid(pos): - spawn_tree_at_position(pos, tree_resource as TreeDataResource) - spawned_positions.append(pos) - spawned_count += 1 - - attempts += 1 - - Log.pr("Spawned %d of %d trees in cell (shuffled)" % [spawned_count, trees_to_spawn.size()]) diff --git a/Entities/Tree/assets/Textures/texture.png b/Entities/Tree/assets/Textures/texture.png new file mode 100644 index 0000000..5ba4aad --- /dev/null +++ b/Entities/Tree/assets/Textures/texture.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:919826bd383102db0e4fbbb85465903d92fb18a5f3710d014796b1bbba7829f0 +size 122084 diff --git a/Entities/Tree/assets/Textures/texture.png.import b/Entities/Tree/assets/Textures/texture.png.import new file mode 100644 index 0000000..a0eb094 --- /dev/null +++ b/Entities/Tree/assets/Textures/texture.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dhajcn6k04poe" +path.s3tc="res://.godot/imported/texture.png-27d352bfc378434578d288ba141a0d45.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://Entities/Tree/assets/Textures/texture.png" +dest_files=["res://.godot/imported/texture.png-27d352bfc378434578d288ba141a0d45.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/Entities/Tree/assets/temp/tree_pineDefaultA.glb b/Entities/Tree/assets/tree_pineDefaultA.glb similarity index 100% rename from Entities/Tree/assets/temp/tree_pineDefaultA.glb rename to Entities/Tree/assets/tree_pineDefaultA.glb diff --git a/Entities/Tree/assets/temp/tree_pineDefaultA.glb.import b/Entities/Tree/assets/tree_pineDefaultA.glb.import similarity index 73% rename from Entities/Tree/assets/temp/tree_pineDefaultA.glb.import rename to Entities/Tree/assets/tree_pineDefaultA.glb.import index 3af2477..c7da8e4 100644 --- a/Entities/Tree/assets/temp/tree_pineDefaultA.glb.import +++ b/Entities/Tree/assets/tree_pineDefaultA.glb.import @@ -4,12 +4,12 @@ importer="scene" importer_version=1 type="PackedScene" uid="uid://brabfdgw5vs1o" -path="res://.godot/imported/tree_pineDefaultA.glb-1f3fb96752d92654789d1e25d544e1b6.scn" +path="res://.godot/imported/tree_pineDefaultA.glb-5dac8705865b7821c88a664af5de372c.scn" [deps] -source_file="res://Entities/Tree/assets/temp/tree_pineDefaultA.glb" -dest_files=["res://.godot/imported/tree_pineDefaultA.glb-1f3fb96752d92654789d1e25d544e1b6.scn"] +source_file="res://Entities/Tree/assets/tree_pineDefaultA.glb" +dest_files=["res://.godot/imported/tree_pineDefaultA.glb-5dac8705865b7821c88a664af5de372c.scn"] [params] diff --git a/Entities/Tree/resources/TreeData.tres b/Entities/Tree/resources/TreeData.tres index 52dc4ae..64e9eb9 100644 --- a/Entities/Tree/resources/TreeData.tres +++ b/Entities/Tree/resources/TreeData.tres @@ -1,11 +1,15 @@ -[gd_resource type="Resource" script_class="TreeDataCollection" load_steps=11 format=3 uid="uid://buf5mtxc5f7o"] +[gd_resource type="Resource" script_class="TreeDataCollection" load_steps=15 format=3 uid="uid://buf5mtxc5f7o"] [ext_resource type="Script" uid="uid://dj4dhsd0m0bvd" path="res://Entities/Tree/resources/TreeDataCollection.gd" id="1_7y4l8"] [ext_resource type="Script" uid="uid://cdudelqysppwl" path="res://Entities/Tree/resources/TreeDataResource.gd" id="2_4yk3p"] [ext_resource type="PackedScene" uid="uid://g74ar24o4s1" path="res://Entities/Tree/assets/tree_oak.glb" id="3_4yk3p"] -[ext_resource type="PackedScene" uid="uid://bwhpbjdyl577e" path="res://Entities/Tree/assets/tree.glb" id="4_4wxxs"] +[ext_resource type="Script" uid="uid://bjsj2j01nmnfq" path="res://Entities/Tree/scripts/color_tree_oak.gd" id="3_itox7"] [ext_resource type="PackedScene" uid="uid://besaean4w1n83" path="res://Entities/Tree/assets/tree_birch.glb" id="5_35hba"] +[ext_resource type="Script" uid="uid://de77441cemrqe" path="res://Entities/Tree/scripts/color_tree_pine.gd" id="5_cyc7o"] [ext_resource type="PackedScene" uid="uid://b3lc1nbuv5ol8" path="res://Entities/Tree/assets/tree_detailed.glb" id="6_ibfiw"] +[ext_resource type="PackedScene" uid="uid://brabfdgw5vs1o" path="res://Entities/Tree/assets/tree_pineDefaultA.glb" id="6_itox7"] +[ext_resource type="Script" uid="uid://dk04iuaocilih" path="res://Entities/Tree/scripts/color_tree_birch.gd" id="7_cyc7o"] +[ext_resource type="Script" uid="uid://3flh70jpmq2w" path="res://Entities/Tree/scripts/color_tree_elder.gd" id="9_dydvk"] [sub_resource type="Resource" id="Resource_7y4l8"] script = ExtResource("2_4yk3p") @@ -17,28 +21,44 @@ moisture_range = Vector2(0.3, 0.8) elevation_range = Vector2(0.1, 0.5) max_height = 15.0 growth_time = 120.0 -spawn_probability = 0.1 spread_radius = 5.0 seasonal_models = Array[PackedScene]([]) drops_leaves = true leaf_color_variations = Array[Color]([]) +color_script = ExtResource("3_itox7") +spring_leaf_color = Color(0.419608, 0.556863, 0.137255, 1) +summer_leaf_color = Color(0.419608, 0.556863, 0.137255, 1) +autumn_leaf_color = Color(0.624662, 0.302547, 1.92523e-07, 1) +winter_leaf_color = Color(0.784314, 0.823529, 0.745098, 1) +spring_trunk_color = Color(0.627451, 0.321569, 0.176471, 1) +summer_trunk_color = Color(0.627451, 0.321569, 0.176471, 1) +autumn_trunk_color = Color(0.4, 0.2, 0.1, 1) +winter_trunk_color = Color(0.3, 0.2, 0.1, 1) metadata/_custom_type_script = "uid://cdudelqysppwl" [sub_resource type="Resource" id="Resource_35hba"] script = ExtResource("2_4yk3p") tree_name = "Pine" -model = ExtResource("4_4wxxs") +model = ExtResource("6_itox7") growth_stages = Array[PackedScene]([]) temperature_range = Vector2(0.1, 0.6) moisture_range = Vector2(0.2, 0.6) elevation_range = Vector2(0.7, 1) max_height = 15.0 growth_time = 120.0 -spawn_probability = 0.1 spread_radius = 5.0 seasonal_models = Array[PackedScene]([]) drops_leaves = true leaf_color_variations = Array[Color]([]) +color_script = ExtResource("5_cyc7o") +spring_leaf_color = Color(0.196078, 0.501961, 0.196078, 1) +summer_leaf_color = Color(0.00392157, 0.196078, 0.12549, 1) +autumn_leaf_color = Color(0.133333, 0.376471, 0.168627, 1) +winter_leaf_color = Color(0.266667, 0.376471, 0.298039, 1) +spring_trunk_color = Color(0.396078, 0.262745, 0.129412, 1) +summer_trunk_color = Color(0.396078, 0.262745, 0.129412, 1) +autumn_trunk_color = Color(0.396078, 0.262745, 0.129412, 1) +winter_trunk_color = Color(0.313726, 0.207843, 0.101961, 1) metadata/_custom_type_script = "uid://cdudelqysppwl" [sub_resource type="Resource" id="Resource_4wxxs"] @@ -51,11 +71,19 @@ moisture_range = Vector2(0.5, 0.6) elevation_range = Vector2(0.1, 0.5) max_height = 15.0 growth_time = 120.0 -spawn_probability = 0.1 spread_radius = 5.0 seasonal_models = Array[PackedScene]([]) drops_leaves = true leaf_color_variations = Array[Color]([]) +color_script = ExtResource("7_cyc7o") +spring_leaf_color = Color(0.678431, 0.933333, 0.466667, 1) +summer_leaf_color = Color(0.603922, 0.803922, 0.196078, 1) +autumn_leaf_color = Color(1, 0.843137, 0, 1) +winter_leaf_color = Color(0.898039, 0.917647, 0.823529, 1) +spring_trunk_color = Color(0.960784, 0.960784, 0.862745, 1) +summer_trunk_color = Color(0.960784, 0.960784, 0.862745, 1) +autumn_trunk_color = Color(0.960784, 0.960784, 0.862745, 1) +winter_trunk_color = Color(0.862745, 0.862745, 0.784314, 1) metadata/_custom_type_script = "uid://cdudelqysppwl" [sub_resource type="Resource" id="Resource_54eyh"] @@ -68,11 +96,19 @@ moisture_range = Vector2(0.7, 1) elevation_range = Vector2(0, 0.2) max_height = 15.0 growth_time = 120.0 -spawn_probability = 0.1 spread_radius = 5.0 seasonal_models = Array[PackedScene]([]) drops_leaves = true leaf_color_variations = Array[Color]([]) +color_script = ExtResource("9_dydvk") +spring_leaf_color = Color(0.564706, 0.933333, 0.564706, 1) +summer_leaf_color = Color(0.196078, 0.803922, 0.196078, 1) +autumn_leaf_color = Color(0.545098, 0.270588, 0.0745098, 1) +winter_leaf_color = Color(0.627451, 0.666667, 0.627451, 1) +spring_trunk_color = Color(0.411765, 0.411765, 0.411765, 1) +summer_trunk_color = Color(0.411765, 0.411765, 0.411765, 1) +autumn_trunk_color = Color(0.411765, 0.411765, 0.411765, 1) +winter_trunk_color = Color(0.329412, 0.329412, 0.329412, 1) metadata/_custom_type_script = "uid://cdudelqysppwl" [resource] diff --git a/Entities/Tree/resources/TreeDataResource.gd b/Entities/Tree/resources/TreeDataResource.gd index abd2411..8d50ef8 100644 --- a/Entities/Tree/resources/TreeDataResource.gd +++ b/Entities/Tree/resources/TreeDataResource.gd @@ -14,10 +14,40 @@ extends Resource @export_group("Growth Properties") @export var max_height: float = 15.0 @export var growth_time: float = 120.0 # Seconds to full growth -@export var spawn_probability: float = 0.1 @export var spread_radius: float = 5.0 @export_group("Seasonal Behavior") @export var seasonal_models: Array[PackedScene] = [] # Spring, Summer, Fall, Winter @export var drops_leaves: bool = true @export var leaf_color_variations: Array[Color] = [] + +@export_group("Tree Color Management") +@export var color_script: GDScript = null + +@export_group("Leaf Colors") +@export var spring_leaf_color: Color = Color(0.0, 1.0, 0.0) # Green +@export var summer_leaf_color: Color = Color(0.0, 0.5, 0.0) # Darker green +@export var autumn_leaf_color: Color = Color(1.0, 0.5, 0.0) # Orange +@export var winter_leaf_color: Color = Color(0.5, 0.5, 0.5) # Gray/Brown + +@export_group("Trunk Colors") +@export var spring_trunk_color: Color = Color(0.6, 0.4, 0.2) # Brown +@export var summer_trunk_color: Color = Color(0.5, 0.3, 0.1) # Darker brown +@export var autumn_trunk_color: Color = Color(0.4, 0.2, 0.1) # Darker brown +@export var winter_trunk_color: Color = Color(0.3, 0.2, 0.1) # Very dark brown + +func apply_seasonal_colors(instance_model: Node3D, season: String = "summer") -> void: + if color_script == null: + return + + var script_instance = color_script.new() + + # Pass the tree name and season to the color script + if script_instance.has_method("set_tree_info"): + script_instance.set_tree_info(tree_name, season) + + + if script_instance.has_method("set_leaf_color"): + script_instance.set_leaf_color(instance_model) + if script_instance.has_method("set_trunk_color"): + script_instance.set_trunk_color(instance_model) \ No newline at end of file diff --git a/Entities/Tree/scripts/color_default.gd b/Entities/Tree/scripts/color_default.gd new file mode 100644 index 0000000..b91a5ab --- /dev/null +++ b/Entities/Tree/scripts/color_default.gd @@ -0,0 +1,108 @@ +class_name TreeColorDefault +extends RefCounted + +var tree_name: String = "" +var current_season: String = "summer" +var mesh_instances: Array[MeshInstance3D] = [] + +func set_tree_info(name: String, season: String): + tree_name = name + current_season = season + +func set_leaf_color(model_instance: Node3D): + #Log.pr("Setting leaf color to: %s" % color) + pass + +func set_trunk_color(model_instance: Node3D): + #Log.pr("Setting trunk color to: %s" % color) + pass + +# Update a specific material by name with a new color +func update_material_by_name(root_node: Node, material_name: String, new_color: Color) -> bool: + var updated = false + + for mesh_instance in mesh_instances: + if update_material_in_mesh_instance(mesh_instance, material_name, new_color): + updated = true + + return updated + +# Update multiple materials at once +func update_materials_by_names(root_node: Node, material_updates: Dictionary) -> Dictionary: + var results = {} + + # Initialize results + for material_name in material_updates.keys(): + results[material_name] = false + + for mesh_instance in mesh_instances: + for material_name in material_updates.keys(): + var new_color = material_updates[material_name] + if update_material_in_mesh_instance(mesh_instance, material_name, new_color): + results[material_name] = true + + return results + +# Get all material names from a model +func get_all_material_names(root_node: Node) -> Array[String]: + var material_names: Array[String] = [] + + for mesh_instance in mesh_instances: + var mesh = mesh_instance.mesh + if mesh: + for i in range(mesh.get_surface_count()): + var material = mesh.surface_get_material(i) + if material and material.resource_name: + if not material.resource_name in material_names: + material_names.append(material.resource_name) + + return material_names + +func update_material_by_name_with_material(root_node: Node, material_name: String, new_material: StandardMaterial3D) -> bool: + var updated = false + + for mesh_instance in mesh_instances: + var mesh = mesh_instance.mesh + if mesh: + for i in range(mesh.get_surface_count()): + var current_material = mesh.surface_get_material(i) + if current_material and current_material.resource_name == material_name: + apply_material_with_queue(mesh_instance, i, new_material) + #mesh_instance.set_surface_override_material(i, new_material) + updated = true + #Log.pr("Updated material '%s' with pre-made material" % material_name) + + return updated + + +# Helper function - find all mesh instances recursively +func find_all_mesh_instances(node: Node) -> Array[MeshInstance3D]: + if node is MeshInstance3D: + mesh_instances.append(node) + + for child in node.get_children(): + mesh_instances += find_all_mesh_instances(child) + + return mesh_instances + +# Helper function - update material in a specific mesh instance +func update_material_in_mesh_instance(mesh_instance: MeshInstance3D, material_name: String, new_color: Color) -> bool: + var updated = false + var mesh = mesh_instance.mesh + + if mesh: + for i in range(mesh.get_surface_count()): + var material = mesh.surface_get_material(i) + if material and material.resource_name == material_name: + var new_material = material.duplicate() + new_material.albedo_color = new_color + mesh_instance.set_surface_override_material(i, new_material) + #Log.pr("Updated material '%s' to color: %s" % [material_name, new_color]) + updated = true + + return updated + + +func apply_material_with_queue(mesh_instance: MeshInstance3D, index: int, material: StandardMaterial3D): + ColorData.queue_material_application(mesh_instance, index, material) + return diff --git a/Entities/Tree/scripts/color_default.gd.uid b/Entities/Tree/scripts/color_default.gd.uid new file mode 100644 index 0000000..0b5a160 --- /dev/null +++ b/Entities/Tree/scripts/color_default.gd.uid @@ -0,0 +1 @@ +uid://dmgn1sve22e8a diff --git a/Entities/Tree/scripts/color_tree_birch.gd b/Entities/Tree/scripts/color_tree_birch.gd new file mode 100644 index 0000000..6bb6a4d --- /dev/null +++ b/Entities/Tree/scripts/color_tree_birch.gd @@ -0,0 +1,19 @@ +extends TreeColorDefault + +func set_leaf_color(model_instance: Node3D): + find_all_mesh_instances(model_instance) + + var material = ColorData.get_random_leaf_material(tree_name, current_season) + + update_material_by_name_with_material(model_instance, "leafsGreen", material) + + return + +func set_trunk_color(model_instance: Node3D): + find_all_mesh_instances(model_instance) + + var material = ColorData.get_random_trunk_material(tree_name, current_season) + + update_material_by_name_with_material(model_instance, "woodBark", material) + + return \ No newline at end of file diff --git a/Entities/Tree/scripts/color_tree_birch.gd.uid b/Entities/Tree/scripts/color_tree_birch.gd.uid new file mode 100644 index 0000000..03cf99f --- /dev/null +++ b/Entities/Tree/scripts/color_tree_birch.gd.uid @@ -0,0 +1 @@ +uid://dk04iuaocilih diff --git a/Entities/Tree/scripts/color_tree_elder.gd b/Entities/Tree/scripts/color_tree_elder.gd new file mode 100644 index 0000000..6bb6a4d --- /dev/null +++ b/Entities/Tree/scripts/color_tree_elder.gd @@ -0,0 +1,19 @@ +extends TreeColorDefault + +func set_leaf_color(model_instance: Node3D): + find_all_mesh_instances(model_instance) + + var material = ColorData.get_random_leaf_material(tree_name, current_season) + + update_material_by_name_with_material(model_instance, "leafsGreen", material) + + return + +func set_trunk_color(model_instance: Node3D): + find_all_mesh_instances(model_instance) + + var material = ColorData.get_random_trunk_material(tree_name, current_season) + + update_material_by_name_with_material(model_instance, "woodBark", material) + + return \ No newline at end of file diff --git a/Entities/Tree/scripts/color_tree_elder.gd.uid b/Entities/Tree/scripts/color_tree_elder.gd.uid new file mode 100644 index 0000000..3fef319 --- /dev/null +++ b/Entities/Tree/scripts/color_tree_elder.gd.uid @@ -0,0 +1 @@ +uid://3flh70jpmq2w diff --git a/Entities/Tree/scripts/color_tree_oak.gd b/Entities/Tree/scripts/color_tree_oak.gd new file mode 100644 index 0000000..2b14ada --- /dev/null +++ b/Entities/Tree/scripts/color_tree_oak.gd @@ -0,0 +1,19 @@ +extends TreeColorDefault + +func set_leaf_color(model_instance: Node3D): + find_all_mesh_instances(model_instance) + + var material = ColorData.get_random_leaf_material(tree_name, current_season) + + update_material_by_name_with_material(model_instance, "leafsGreen", material) + + return + +func set_trunk_color(model_instance: Node3D): + find_all_mesh_instances(model_instance) + + var material = ColorData.get_random_trunk_material(tree_name, current_season) + + update_material_by_name_with_material(model_instance, "woodBark", material) + + return diff --git a/Entities/Tree/scripts/color_tree_oak.gd.uid b/Entities/Tree/scripts/color_tree_oak.gd.uid new file mode 100644 index 0000000..614af49 --- /dev/null +++ b/Entities/Tree/scripts/color_tree_oak.gd.uid @@ -0,0 +1 @@ +uid://bjsj2j01nmnfq diff --git a/Entities/Tree/scripts/color_tree_pine.gd b/Entities/Tree/scripts/color_tree_pine.gd new file mode 100644 index 0000000..ed11292 --- /dev/null +++ b/Entities/Tree/scripts/color_tree_pine.gd @@ -0,0 +1,19 @@ +extends TreeColorDefault + +func set_leaf_color(model_instance: Node3D): + find_all_mesh_instances(model_instance) + + var material = ColorData.get_random_leaf_material(tree_name, current_season) + + update_material_by_name_with_material(model_instance, "leafsDark", material) + + return + +func set_trunk_color(model_instance: Node3D): + find_all_mesh_instances(model_instance) + + var material = ColorData.get_random_trunk_material(tree_name, current_season) + + update_material_by_name_with_material(model_instance, "woodBark", material) + + return diff --git a/Entities/Tree/scripts/color_tree_pine.gd.uid b/Entities/Tree/scripts/color_tree_pine.gd.uid new file mode 100644 index 0000000..bbc038b --- /dev/null +++ b/Entities/Tree/scripts/color_tree_pine.gd.uid @@ -0,0 +1 @@ +uid://de77441cemrqe diff --git a/Entities/Tree/scripts/tree.gd b/Entities/Tree/scripts/tree.gd index 586f44f..f780a49 100644 --- a/Entities/Tree/scripts/tree.gd +++ b/Entities/Tree/scripts/tree.gd @@ -20,10 +20,6 @@ func set_tree_data(data: TreeDataResource): tree_data = data spawn_model() -func setup_tree(data: TreeDataResource): - # Alternative method name if you prefer - set_tree_data(data) - func spawn_model(): if not tree_data or not tree_data.model: Log.pr("No tree data or model provided") @@ -37,7 +33,9 @@ func spawn_model(): # Instantiate the model from the TreeDataResource model_instance = tree_data.model.instantiate() + tree_data.apply_seasonal_colors(model_instance, "spring") add_child(model_instance) + # Create base circle after model is loaded if not base_circle: @@ -45,6 +43,7 @@ func spawn_model(): # Re-scan for mesh instances in the new model find_all_mesh_instances(model_instance) + update_outline_materials() # Apply any additional properties from tree_data @@ -63,7 +62,7 @@ func apply_tree_properties(): var scale_variation = randf_range(0.8, 1.2) model_instance.scale *= scale_variation -func setup_outline_material(): +func setup_outline_material() -> void: # Create outline material with your shader outline_material = ShaderMaterial.new() outline_material.shader = preload("res://outline.gdshader") diff --git a/Utilities/ColorStorage/ColorStorage.gd b/Utilities/ColorStorage/ColorStorage.gd new file mode 100644 index 0000000..3da66a7 --- /dev/null +++ b/Utilities/ColorStorage/ColorStorage.gd @@ -0,0 +1,119 @@ +class_name ColorStorageClass +extends Node + +var tree_collection = preload("res://Entities/Tree/Resources/TreeData.tres") as TreeDataCollection +var tree_materials: Dictionary = {} +var grass_materials: Dictionary = {"spring": {"base": Vector3(0.196, 0.392, 0.196), "top": Vector3(0.253, 0.492, 0.253), "bottom": Vector3(0.196, 0.392, 0.196)}, + "summer": {"base": null, "top": null, "bottom": null}, + "autumn": {"base": null, "top": null, "bottom": null}, + "winter": {"base": null, "top": null, "bottom": null}} + + +## TODO - Move this out into its own class +var material_application_queue: Array = [] +var max_materials_per_frame: int = 10 # Adjust based on performance + +@export var tree_colours: Array + +func _ready() -> void: + populate_tree_colors() + Log.pr("Tree colors populated: %d trees" % tree_materials.size()) + +func _process(_delta): + # Process material applications gradually over multiple frames + process_material_queue() + +func process_material_queue(): + var processed = 0 + while material_application_queue.size() > 0 and processed < max_materials_per_frame: + var task = material_application_queue.pop_front() + + # Check if the mesh instance is still valid before applying + if is_instance_valid(task.mesh_instance) and task.mesh_instance != null: + apply_material_immediately(task.mesh_instance, task.surface_index, task.material) + # If invalid, just skip this task (object was freed) + + processed += 1 + +func queue_material_application(mesh_instance: MeshInstance3D, surface_index: int, material: StandardMaterial3D): + material_application_queue.append({ + "mesh_instance": mesh_instance, + "surface_index": surface_index, + "material": material + }) + +func apply_material_immediately(mesh_instance: MeshInstance3D, surface_index: int, material: StandardMaterial3D): + if is_instance_valid(mesh_instance): + mesh_instance.set_surface_override_material(surface_index, material) + +# Create materials once at startup +func populate_tree_colors() -> void: + for tree in tree_collection.trees: + Log.pr("Loading tree: %s" % tree.tree_name) + + tree_materials[tree.tree_name] = { + "spring": { + "leaf": create_leaf_materials(tree.spring_leaf_color, "spring", tree.tree_name), + "trunk": create_trunk_materials(tree.spring_trunk_color, "spring", tree.tree_name) + }, + "summer": { + "leaf": create_leaf_materials(tree.summer_leaf_color, "summer", tree.tree_name), + "trunk": create_trunk_materials(tree.summer_trunk_color, "summer", tree.tree_name) + }, + "autumn": { + "leaf": create_leaf_materials(tree.autumn_leaf_color, "autumn", tree.tree_name), + "trunk": create_trunk_materials(tree.autumn_trunk_color, "autumn", tree.tree_name) + }, + "winter": { + "leaf": create_leaf_materials(tree.winter_leaf_color, "winter", tree.tree_name), + "trunk": create_trunk_materials(tree.winter_trunk_color, "winter", tree.tree_name) + } + } + +func create_leaf_materials(base_color: Color, season: String, tree_name: String) -> Dictionary: + var materials = {} + materials = { + "1": create_material(base_color, "%s_leaf_%s_primary" % [tree_name, season]), + "2": create_material(base_color.darkened(0.1), "%s_leaf_%s_secondary" % [tree_name, season]), + "3": create_material(base_color.lightened(0.1), "%s_leaf_%s_highlight" % [tree_name, season]), + "4": create_material(base_color.darkened(0.3), "%s_leaf_%s_shadow" % [tree_name, season]) + } + return materials + +func create_trunk_materials(base_color: Color, season: String, tree_name: String) -> Dictionary: + var materials = {} + materials = { + "1": create_material(base_color, "%s_trunk_%s_primary" % [tree_name, season]), + "2": create_material(base_color.darkened(0.2), "%s_trunk_%s_bark" % [tree_name, season]), + "3": create_material(Color(0.2, 0.4, 0.1), "%s_trunk_%s_moss" % [tree_name, season]), + "4": create_material(base_color.lightened(0.1), "%s_trunk_%s_highlight" % [tree_name, season]) + } + return materials + +func create_material(color: Color, material_name: String) -> StandardMaterial3D: + var material = StandardMaterial3D.new() + material.albedo_color = color + material.metallic = 0.0 + material.roughness = 0.8 + material.resource_name = material_name + return material + +func get_random_leaf_material(tree_name: String, season: String) -> StandardMaterial3D: + if tree_materials.has(tree_name) and tree_materials[tree_name].has(season): + var leaf_materials = tree_materials[tree_name][season]["leaf"] + var material_keys = leaf_materials.keys() + if material_keys.size() > 0: + var random_key = material_keys[randi() % material_keys.size()] + return leaf_materials[random_key] + + return create_material(Color.GREEN, "fallback_leaf") + +func get_random_trunk_material(tree_name: String, season: String) -> StandardMaterial3D: + if tree_materials.has(tree_name) and tree_materials[tree_name].has(season): + var trunk_materials = tree_materials[tree_name][season]["trunk"] + var material_keys = trunk_materials.keys() + if material_keys.size() > 0: + var random_key = material_keys[randi() % material_keys.size()] + return trunk_materials[random_key] + + return create_material(Color(0.6, 0.4, 0.2), "fallback_trunk") diff --git a/Utilities/ColorStorage/ColorStorage.gd.uid b/Utilities/ColorStorage/ColorStorage.gd.uid new file mode 100644 index 0000000..19f1cee --- /dev/null +++ b/Utilities/ColorStorage/ColorStorage.gd.uid @@ -0,0 +1 @@ +uid://bbtdrg8ax8sca diff --git a/falloff.gdshader b/falloff.gdshader new file mode 100644 index 0000000..ca3d193 --- /dev/null +++ b/falloff.gdshader @@ -0,0 +1,10 @@ +shader_type canvas_item; + +uniform sampler2D gradient_fallof; + +void light() { + float calculated_light_value = max(0.0, dot(NORMAL, LIGHT_DIRECTION)); + float sample = clamp(calculated_light_value * LIGHT_ENERGY, 0.05, 0.95); + vec4 shaded_texture = texture(gradient_fallof, vec2(sample, 0)); + LIGHT = vec4(LIGHT_COLOR.rgb * COLOR.rgb * shaded_texture.rgb, LIGHT_COLOR.a); +} \ No newline at end of file diff --git a/falloff.gdshader.uid b/falloff.gdshader.uid new file mode 100644 index 0000000..a9ae8bc --- /dev/null +++ b/falloff.gdshader.uid @@ -0,0 +1 @@ +uid://ce7q2m8ux2l0j diff --git a/project.godot b/project.godot index 3fd6561..b41fddb 100644 --- a/project.godot +++ b/project.godot @@ -23,6 +23,7 @@ DebugMenu="*res://addons/debug_menu/debug_menu.tscn" MapGeneration="*res://Utilities/MapGeneration/MapGeneration.gd" BiomeData="*res://Utilities/BiomeGeneration/BiomeData.gd" MapData="*res://Utilities/MapData/MapData.gd" +ColorData="*res://Utilities/ColorStorage/ColorStorage.gd" MapPopulation="*res://Utilities/MapData/MapPopulation.gd" [editor_plugins] diff --git a/stages/Test3D/GrassMaterialOverride.tres b/stages/Test3D/GrassMaterialOverride.tres index 09945b0..e564350 100644 --- a/stages/Test3D/GrassMaterialOverride.tres +++ b/stages/Test3D/GrassMaterialOverride.tres @@ -1,14 +1,17 @@ -[gd_resource type="ShaderMaterial" load_steps=3 format=3 uid="uid://b1miqvl8lus75"] +[gd_resource type="ShaderMaterial" load_steps=4 format=3 uid="uid://b1miqvl8lus75"] [ext_resource type="Shader" uid="uid://dbduq0qcaxmyi" path="res://grass.gdshader" id="1_vnnwo"] +[sub_resource type="FastNoiseLite" id="FastNoiseLite_vnnwo"] + [sub_resource type="NoiseTexture2D" id="NoiseTexture2D_vnnwo"] +noise = SubResource("FastNoiseLite_vnnwo") [resource] render_priority = 0 shader = ExtResource("1_vnnwo") -shader_parameter/top_color = Color(0.102963, 0.465909, 0.382031, 1) -shader_parameter/bottom_color = Color(0.121494, 0.374954, 0.315972, 1) +shader_parameter/top_color = Color(0.252743, 0.492435, 0.25271, 1) +shader_parameter/bottom_color = Color(0.196078, 0.392157, 0.196078, 1) shader_parameter/ambient_occlusion_factor = 0.0 shader_parameter/specular_strength = 0.0 shader_parameter/player_displacement_strength = 1.0 diff --git a/stages/Test3D/Test3d.tscn b/stages/Test3D/Test3d.tscn index 662f6b0..518349c 100644 --- a/stages/Test3D/Test3d.tscn +++ b/stages/Test3D/Test3d.tscn @@ -740,7 +740,7 @@ script = ExtResource("2_sdmks") transform = Transform3D(1, 0, 0, 0, 1, -1.49012e-07, 0, 1.19209e-07, 1, 0.0410548, 0.237644, 3.45114) projection = 1 current = true -size = 4.0 +size = 3.0 near = 0.005 far = 100.0 @@ -772,7 +772,7 @@ draw_pass_1 = SubResource("QuadMesh_hvb1l") [node name="OmniLight3D" type="OmniLight3D" parent="SubViewportContainer/SubViewport/VFX/Fire"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.000509977, 0.121094, -0.00151992) light_color = Color(0.89, 0.461613, 0.2136, 1) -light_energy = 0.668778 +light_energy = 0.802091 light_indirect_energy = 1.084 light_volumetric_fog_energy = 3.764 light_size = 0.105 diff --git a/stages/Test3D/assets/stylizedGrassMeshes/grass.res b/stages/Test3D/assets/stylizedGrassMeshes/grass.res index 25ccb3d..598ca86 100644 Binary files a/stages/Test3D/assets/stylizedGrassMeshes/grass.res and b/stages/Test3D/assets/stylizedGrassMeshes/grass.res differ